summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite_2d.cpp3
-rw-r--r--scene/2d/area_2d.cpp17
-rw-r--r--scene/2d/area_2d.h6
-rw-r--r--scene/2d/audio_listener_2d.cpp4
-rw-r--r--scene/2d/audio_listener_2d.h2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp18
-rw-r--r--scene/2d/audio_stream_player_2d.h2
-rw-r--r--scene/2d/back_buffer_copy.cpp1
-rw-r--r--scene/2d/camera_2d.cpp83
-rw-r--r--scene/2d/camera_2d.h6
-rw-r--r--scene/2d/collision_object_2d.cpp1
-rw-r--r--scene/2d/collision_polygon_2d.cpp16
-rw-r--r--scene/2d/collision_shape_2d.cpp1
-rw-r--r--scene/2d/gpu_particles_2d.cpp2
-rw-r--r--scene/2d/joint_2d.cpp1
-rw-r--r--scene/2d/light_2d.cpp2
-rw-r--r--scene/2d/marker_2d.cpp1
-rw-r--r--scene/2d/navigation_agent_2d.cpp300
-rw-r--r--scene/2d/navigation_agent_2d.h32
-rw-r--r--scene/2d/navigation_link_2d.cpp1
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp19
-rw-r--r--scene/2d/navigation_region_2d.cpp1
-rw-r--r--scene/2d/ray_cast_2d.cpp1
-rw-r--r--scene/2d/remote_transform_2d.cpp1
-rw-r--r--scene/2d/shape_cast_2d.cpp4
-rw-r--r--scene/2d/shape_cast_2d.h2
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp11
-rw-r--r--scene/2d/visible_on_screen_notifier_2d.cpp1
-rw-r--r--scene/3d/area_3d.cpp16
-rw-r--r--scene/3d/area_3d.h6
-rw-r--r--scene/3d/audio_stream_player_3d.cpp24
-rw-r--r--scene/3d/audio_stream_player_3d.h2
-rw-r--r--scene/3d/bone_attachment_3d.cpp5
-rw-r--r--scene/3d/decal.cpp38
-rw-r--r--scene/3d/decal.h10
-rw-r--r--scene/3d/fog_volume.cpp44
-rw-r--r--scene/3d/fog_volume.h10
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp184
-rw-r--r--scene/3d/gpu_particles_collision_3d.h50
-rw-r--r--scene/3d/label_3d.cpp63
-rw-r--r--scene/3d/label_3d.h16
-rw-r--r--scene/3d/navigation_agent_3d.cpp328
-rw-r--r--scene/3d/navigation_agent_3d.h43
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp19
-rw-r--r--scene/3d/occluder_instance_3d.cpp5
-rw-r--r--scene/3d/physics_body_3d.cpp5
-rw-r--r--scene/3d/reflection_probe.cpp56
-rw-r--r--scene/3d/reflection_probe.h12
-rw-r--r--scene/3d/sprite_3d.cpp89
-rw-r--r--scene/3d/sprite_3d.h20
-rw-r--r--scene/3d/voxel_gi.cpp46
-rw-r--r--scene/3d/voxel_gi.h10
-rw-r--r--scene/animation/animation_blend_space_1d.cpp180
-rw-r--r--scene/animation/animation_blend_space_1d.h17
-rw-r--r--scene/animation/animation_blend_tree.cpp224
-rw-r--r--scene/animation/animation_blend_tree.h34
-rw-r--r--scene/animation/animation_node_state_machine.cpp15
-rw-r--r--scene/animation/animation_node_state_machine.h4
-rw-r--r--scene/animation/animation_player.cpp249
-rw-r--r--scene/animation/animation_player.h29
-rw-r--r--scene/animation/animation_tree.cpp369
-rw-r--r--scene/animation/animation_tree.h42
-rw-r--r--scene/animation/root_motion_view.cpp3
-rw-r--r--scene/animation/tween.cpp8
-rw-r--r--scene/audio/audio_stream_player.cpp5
-rw-r--r--scene/audio/audio_stream_player.h1
-rw-r--r--scene/gui/code_edit.cpp2
-rw-r--r--scene/gui/control.cpp12
-rw-r--r--scene/gui/control.h3
-rw-r--r--scene/gui/graph_edit.cpp13
-rw-r--r--scene/gui/line_edit.cpp2
-rw-r--r--scene/gui/popup_menu.cpp3
-rw-r--r--scene/gui/rich_text_label.cpp78
-rw-r--r--scene/gui/rich_text_label.h11
-rw-r--r--scene/gui/split_container.cpp2
-rw-r--r--scene/gui/subviewport_container.cpp4
-rw-r--r--scene/gui/tree.cpp1
-rw-r--r--scene/gui/video_stream_player.cpp7
-rw-r--r--scene/gui/video_stream_player.h1
-rw-r--r--scene/main/canvas_item.cpp36
-rw-r--r--scene/main/canvas_item.h8
-rw-r--r--scene/main/http_request.cpp21
-rw-r--r--scene/main/http_request.h8
-rw-r--r--scene/main/multiplayer_api.cpp16
-rw-r--r--scene/main/multiplayer_api.h8
-rw-r--r--scene/main/multiplayer_peer.cpp2
-rw-r--r--scene/main/node.cpp15
-rw-r--r--scene/main/viewport.cpp127
-rw-r--r--scene/main/viewport.h19
-rw-r--r--scene/main/window.cpp34
-rw-r--r--scene/main/window.h3
-rw-r--r--scene/register_scene_types.cpp3
-rw-r--r--scene/resources/animation.cpp35
-rw-r--r--scene/resources/animation.h3
-rw-r--r--scene/resources/bone_map.cpp1
-rw-r--r--scene/resources/capsule_shape_2d.cpp2
-rw-r--r--scene/resources/circle_shape_2d.cpp1
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp9
-rw-r--r--scene/resources/fog_material.cpp2
-rw-r--r--scene/resources/font.cpp32
-rw-r--r--scene/resources/importer_mesh.cpp24
-rw-r--r--scene/resources/material.cpp62
-rw-r--r--scene/resources/material.h2
-rw-r--r--scene/resources/navigation_mesh.cpp4
-rw-r--r--scene/resources/packed_scene.cpp20
-rw-r--r--scene/resources/primitive_meshes.cpp2
-rw-r--r--scene/resources/rectangle_shape_2d.cpp6
-rw-r--r--scene/resources/resource_format_text.cpp30
-rw-r--r--scene/resources/shader.cpp13
-rw-r--r--scene/resources/shader.h2
-rw-r--r--scene/resources/shader_include.cpp12
-rw-r--r--scene/resources/shader_include.h3
-rw-r--r--scene/resources/style_box.cpp2
-rw-r--r--scene/resources/surface_tool.cpp3
-rw-r--r--scene/resources/surface_tool.h9
-rw-r--r--scene/resources/video_stream.cpp198
-rw-r--r--scene/resources/video_stream.h76
-rw-r--r--scene/resources/visual_shader.cpp19
-rw-r--r--scene/resources/visual_shader.h19
-rw-r--r--scene/resources/visual_shader_nodes.cpp35
-rw-r--r--scene/resources/world_2d.cpp40
-rw-r--r--scene/resources/world_2d.h4
-rw-r--r--scene/resources/world_3d.cpp41
-rw-r--r--scene/resources/world_3d.h4
-rw-r--r--scene/resources/world_boundary_shape_2d.cpp7
126 files changed, 2992 insertions, 991 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index ccf9696d82..8f7006caca 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -475,8 +475,9 @@ void AnimatedSprite2D::play(const StringName &p_name, float p_custom_scale, bool
}
}
- notify_property_list_changed();
set_process_internal(true);
+ notify_property_list_changed();
+ queue_redraw();
}
void AnimatedSprite2D::play_backwards(const StringName &p_name) {
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index f80da6e9ab..a37fabf21f 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -51,13 +51,13 @@ bool Area2D::is_gravity_a_point() const {
return gravity_is_point;
}
-void Area2D::set_gravity_point_distance_scale(real_t p_scale) {
- gravity_distance_scale = p_scale;
- PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY_DISTANCE_SCALE, p_scale);
+void Area2D::set_gravity_point_unit_distance(real_t p_scale) {
+ gravity_point_unit_distance = p_scale;
+ PhysicsServer2D::get_singleton()->area_set_param(get_rid(), PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE, p_scale);
}
-real_t Area2D::get_gravity_point_distance_scale() const {
- return gravity_distance_scale;
+real_t Area2D::get_gravity_point_unit_distance() const {
+ return gravity_point_unit_distance;
}
void Area2D::set_gravity_point_center(const Vector2 &p_center) {
@@ -557,8 +557,8 @@ void Area2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area2D::set_gravity_is_point);
ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area2D::is_gravity_a_point);
- ClassDB::bind_method(D_METHOD("set_gravity_point_distance_scale", "distance_scale"), &Area2D::set_gravity_point_distance_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_point_distance_scale"), &Area2D::get_gravity_point_distance_scale);
+ ClassDB::bind_method(D_METHOD("set_gravity_point_unit_distance", "distance_scale"), &Area2D::set_gravity_point_unit_distance);
+ ClassDB::bind_method(D_METHOD("get_gravity_point_unit_distance"), &Area2D::get_gravity_point_unit_distance);
ClassDB::bind_method(D_METHOD("set_gravity_point_center", "center"), &Area2D::set_gravity_point_center);
ClassDB::bind_method(D_METHOD("get_gravity_point_center"), &Area2D::get_gravity_point_center);
@@ -622,7 +622,7 @@ void Area2D::_bind_methods() {
ADD_GROUP("Gravity", "gravity_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gravity_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_space_override_mode", "get_gravity_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_unit_distance", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp,suffix:px"), "set_gravity_point_unit_distance", "get_gravity_point_unit_distance");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:px"), "set_gravity_point_center", "get_gravity_point_center");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_direction"), "set_gravity_direction", "get_gravity_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_less,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity");
@@ -652,6 +652,7 @@ Area2D::Area2D() :
set_gravity_direction(Vector2(0, 1));
set_monitoring(true);
set_monitorable(true);
+ set_hide_clip_children(true);
}
Area2D::~Area2D() {
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index aaf7ea28f8..8f4bbe3219 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -51,7 +51,7 @@ private:
Vector2 gravity_vec;
real_t gravity = 0.0;
bool gravity_is_point = false;
- real_t gravity_distance_scale = 0.0;
+ real_t gravity_point_unit_distance = 0.0;
SpaceOverride linear_damp_space_override = SPACE_OVERRIDE_DISABLED;
SpaceOverride angular_damp_space_override = SPACE_OVERRIDE_DISABLED;
@@ -144,8 +144,8 @@ public:
void set_gravity_is_point(bool p_enabled);
bool is_gravity_a_point() const;
- void set_gravity_point_distance_scale(real_t p_scale);
- real_t get_gravity_point_distance_scale() const;
+ void set_gravity_point_unit_distance(real_t p_scale);
+ real_t get_gravity_point_unit_distance() const;
void set_gravity_point_center(const Vector2 &p_center);
const Vector2 &get_gravity_point_center() const;
diff --git a/scene/2d/audio_listener_2d.cpp b/scene/2d/audio_listener_2d.cpp
index 5b8833ce62..b4484694a5 100644
--- a/scene/2d/audio_listener_2d.cpp
+++ b/scene/2d/audio_listener_2d.cpp
@@ -110,3 +110,7 @@ void AudioListener2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_current"), &AudioListener2D::clear_current);
ClassDB::bind_method(D_METHOD("is_current"), &AudioListener2D::is_current);
}
+
+AudioListener2D::AudioListener2D() {
+ set_hide_clip_children(true);
+}
diff --git a/scene/2d/audio_listener_2d.h b/scene/2d/audio_listener_2d.h
index 12a44f26ae..abada06971 100644
--- a/scene/2d/audio_listener_2d.h
+++ b/scene/2d/audio_listener_2d.h
@@ -54,6 +54,8 @@ public:
void make_current();
void clear_current();
bool is_current() const;
+
+ AudioListener2D();
};
#endif // AUDIO_LISTENER_2D_H
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 7b681eac7a..902fba38bf 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -72,12 +72,10 @@ void AudioStreamPlayer2D::_notification(int p_what) {
_update_panning();
}
- if (setplay.get() >= 0 && stream.is_valid()) {
+ if (setplayback.is_valid() && setplay.get() >= 0) {
active.set();
- Ref<AudioStreamPlayback> new_playback = stream->instantiate_playback();
- ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback.");
- AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale);
- stream_playbacks.push_back(new_playback);
+ AudioServer::get_singleton()->start_playback_stream(setplayback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale);
+ setplayback.unref();
setplay.set(-1);
}
@@ -255,7 +253,11 @@ void AudioStreamPlayer2D::play(float p_from_pos) {
if (stream->is_monophonic() && is_playing()) {
stop();
}
+ Ref<AudioStreamPlayback> stream_playback = stream->instantiate_playback();
+ ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback.");
+ stream_playbacks.push_back(stream_playback);
+ setplayback = stream_playback;
setplay.set(p_from_pos);
active.set();
set_physics_process_internal(true);
@@ -390,6 +392,10 @@ bool AudioStreamPlayer2D::get_stream_paused() const {
return false;
}
+bool AudioStreamPlayer2D::has_stream_playback() {
+ return !stream_playbacks.is_empty();
+}
+
Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
return stream_playbacks[stream_playbacks.size() - 1];
@@ -458,6 +464,7 @@ void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_panning_strength", "panning_strength"), &AudioStreamPlayer2D::set_panning_strength);
ClassDB::bind_method(D_METHOD("get_panning_strength"), &AudioStreamPlayer2D::get_panning_strength);
+ ClassDB::bind_method(D_METHOD("has_stream_playback"), &AudioStreamPlayer2D::has_stream_playback);
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
@@ -479,6 +486,7 @@ void AudioStreamPlayer2D::_bind_methods() {
AudioStreamPlayer2D::AudioStreamPlayer2D() {
AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_bus_layout_changed));
cached_global_panning_strength = GLOBAL_GET("audio/general/2d_panning_strength");
+ set_hide_clip_children(true);
}
AudioStreamPlayer2D::~AudioStreamPlayer2D() {
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index a5fd584513..79a026fed2 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -56,6 +56,7 @@ private:
SafeFlag active{ false };
SafeNumeric<float> setplay{ -1.0 };
+ Ref<AudioStreamPlayback> setplayback;
Vector<AudioFrame> volume_vector;
@@ -129,6 +130,7 @@ public:
void set_panning_strength(float p_panning_strength);
float get_panning_strength() const;
+ bool has_stream_playback();
Ref<AudioStreamPlayback> get_stream_playback();
AudioStreamPlayer2D();
diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp
index ab048f0cd7..60b344b002 100644
--- a/scene/2d/back_buffer_copy.cpp
+++ b/scene/2d/back_buffer_copy.cpp
@@ -101,6 +101,7 @@ void BackBufferCopy::_bind_methods() {
BackBufferCopy::BackBufferCopy() {
_update_copy_mode();
+ set_hide_clip_children(true);
}
BackBufferCopy::~BackBufferCopy() {
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index c4647ae9ff..fe6bee0f1b 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -50,7 +50,7 @@ void Camera2D::_update_scroll() {
return;
}
- if (current) {
+ if (is_current()) {
ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id));
Transform2D xform = get_camera_transform();
@@ -241,10 +241,6 @@ void Camera2D::_notification(int p_what) {
viewport = get_viewport();
}
- if (is_current()) {
- viewport->_camera_2d_set(this);
- }
-
canvas = get_canvas();
RID vp = viewport->get_viewport_rid();
@@ -254,21 +250,21 @@ void Camera2D::_notification(int p_what) {
add_to_group(group_name);
add_to_group(canvas_group_name);
+ if (!Engine::get_singleton()->is_editor_hint() && enabled && !viewport->get_camera_2d()) {
+ make_current();
+ }
+
_update_process_callback();
first = true;
_update_scroll();
} break;
case NOTIFICATION_EXIT_TREE: {
- if (is_current()) {
- if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
- viewport->set_canvas_transform(Transform2D());
- clear_current();
- current = true;
- }
- }
remove_from_group(group_name);
remove_from_group(canvas_group_name);
+ if (is_current()) {
+ clear_current();
+ }
viewport = nullptr;
} break;
@@ -397,19 +393,31 @@ void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) {
_update_process_callback();
}
+void Camera2D::set_enabled(bool p_enabled) {
+ enabled = p_enabled;
+
+ if (enabled && is_inside_tree() && !viewport->get_camera_2d()) {
+ make_current();
+ } else if (!enabled && is_current()) {
+ clear_current();
+ }
+}
+
+bool Camera2D::is_enabled() const {
+ return enabled;
+}
+
Camera2D::Camera2DProcessCallback Camera2D::get_process_callback() const {
return process_callback;
}
void Camera2D::_make_current(Object *p_which) {
if (p_which == this) {
- current = true;
if (is_inside_tree()) {
get_viewport()->_camera_2d_set(this);
queue_redraw();
}
} else {
- current = false;
if (is_inside_tree()) {
if (get_viewport()->get_camera_2d() == this) {
get_viewport()->_camera_2d_set(nullptr);
@@ -419,45 +427,34 @@ void Camera2D::_make_current(Object *p_which) {
}
}
-void Camera2D::set_current(bool p_current) {
- if (p_current) {
- make_current();
- } else {
- if (current) {
- clear_current();
- }
- }
-}
-
void Camera2D::_update_process_internal_for_smoothing() {
bool is_not_in_scene_or_editor = !(is_inside_tree() && Engine::get_singleton()->is_editor_hint());
bool is_any_smoothing_valid = position_smoothing_speed > 0 || rotation_smoothing_speed > 0;
- bool enabled = is_any_smoothing_valid && is_not_in_scene_or_editor;
- set_process_internal(enabled);
-}
-
-bool Camera2D::is_current() const {
- return current;
+ bool enable = is_any_smoothing_valid && is_not_in_scene_or_editor;
+ set_process_internal(enable);
}
void Camera2D::make_current() {
- if (is_inside_tree()) {
- get_tree()->call_group(group_name, "_make_current", this);
- } else {
- current = true;
- }
+ ERR_FAIL_COND(!enabled || !is_inside_tree());
+ get_tree()->call_group(group_name, "_make_current", this);
_update_scroll();
}
void Camera2D::clear_current() {
- if (is_inside_tree()) {
- get_tree()->call_group(group_name, "_make_current", (Object *)nullptr);
- } else {
- current = false;
+ ERR_FAIL_COND(!is_current());
+ if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
+ viewport->assign_next_enabled_camera_2d(group_name);
}
}
+bool Camera2D::is_current() const {
+ if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
+ return viewport->get_camera_2d() == this;
+ }
+ return false;
+}
+
void Camera2D::set_limit(Side p_side, int p_limit) {
ERR_FAIL_INDEX((int)p_side, 4);
limit[p_side] = p_limit;
@@ -715,7 +712,10 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &Camera2D::set_process_callback);
ClassDB::bind_method(D_METHOD("get_process_callback"), &Camera2D::get_process_callback);
- ClassDB::bind_method(D_METHOD("set_current", "current"), &Camera2D::set_current);
+ ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &Camera2D::set_enabled);
+ ClassDB::bind_method(D_METHOD("is_enabled"), &Camera2D::is_enabled);
+
+ ClassDB::bind_method(D_METHOD("make_current"), &Camera2D::make_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera2D::is_current);
ClassDB::bind_method(D_METHOD("_make_current"), &Camera2D::_make_current);
@@ -779,7 +779,7 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_rotation"), "set_ignore_rotation", "is_ignoring_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom", PROPERTY_HINT_LINK), "set_zoom", "get_zoom");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
@@ -832,4 +832,5 @@ Camera2D::Camera2D() {
drag_margin[SIDE_BOTTOM] = 0.2;
set_notify_transform(true);
+ set_hide_clip_children(true);
}
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 304b4ceaa6..7a77266db8 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -64,7 +64,7 @@ protected:
Vector2 zoom_scale = Vector2(1, 1);
AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER;
bool ignore_rotation = true;
- bool current = false;
+ bool enabled = true;
real_t position_smoothing_speed = 5.0;
bool follow_smoothing_enabled = false;
@@ -88,7 +88,6 @@ protected:
void _update_scroll();
void _make_current(Object *p_which);
- void set_current(bool p_current);
void _set_old_smoothing(real_t p_enable);
@@ -155,6 +154,9 @@ public:
void set_process_callback(Camera2DProcessCallback p_mode);
Camera2DProcessCallback get_process_callback() const;
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
void make_current();
void clear_current();
bool is_current() const;
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index caea753d99..ba3b0cec5c 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -651,6 +651,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
area = p_area;
pickable = true;
set_notify_transform(true);
+ set_hide_clip_children(true);
total_subshapes = 0;
only_update_transform_changes = false;
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 0e18f77b8a..32dea80650 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -131,15 +131,7 @@ void CollisionPolygon2D::_notification(int p_what) {
break;
}
- int polygon_count = polygon.size();
- for (int i = 0; i < polygon_count; i++) {
- Vector2 p = polygon[i];
- Vector2 n = polygon[(i + 1) % polygon_count];
- // draw line with width <= 1, so it does not scale with zoom and break pixel exact editing
- draw_line(p, n, Color(0.9, 0.2, 0.0, 0.8), 1);
- }
-
- if (polygon_count > 2) {
+ if (polygon.size() > 2) {
#define DEBUG_DECOMPOSE
#if defined(TOOLS_ENABLED) && defined(DEBUG_DECOMPOSE)
Vector<Vector<Vector2>> decomp = _decompose_in_convex();
@@ -152,6 +144,11 @@ void CollisionPolygon2D::_notification(int p_what) {
#else
draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color());
#endif
+
+ const Color stroke_color = Color(0.9, 0.2, 0.0);
+ draw_polyline(polygon, stroke_color);
+ // Draw the last segment.
+ draw_line(polygon[polygon.size() - 1], polygon[0], stroke_color);
}
if (one_way_collision) {
@@ -323,4 +320,5 @@ void CollisionPolygon2D::_bind_methods() {
CollisionPolygon2D::CollisionPolygon2D() {
set_notify_local_transform(true);
+ set_hide_clip_children(true);
}
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 6ff789cad2..5951405bbe 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -288,5 +288,6 @@ void CollisionShape2D::_bind_methods() {
CollisionShape2D::CollisionShape2D() {
set_notify_local_transform(true);
+ set_hide_clip_children(true);
debug_color = _get_default_debug_color();
}
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 9a3b7c8687..00d13c59b9 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -638,7 +638,7 @@ void GPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interpolate"), "set_interpolate", "get_interpolate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,suffix:px"), "set_collision_base_size", "get_collision_base_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_base_size", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_collision_base_size", "get_collision_base_size");
ADD_GROUP("Drawing", "");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "visibility_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_visibility_rect", "get_visibility_rect");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp
index 47d0ac6e35..ce427d47aa 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -243,6 +243,7 @@ void Joint2D::_bind_methods() {
Joint2D::Joint2D() {
joint = PhysicsServer2D::get_singleton()->joint_create();
+ set_hide_clip_children(true);
}
Joint2D::~Joint2D() {
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index fb53400fd6..15b638ed92 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -443,6 +443,7 @@ void PointLight2D::_bind_methods() {
PointLight2D::PointLight2D() {
RS::get_singleton()->canvas_light_set_mode(_get_light(), RS::CANVAS_LIGHT_MODE_POINT);
+ set_hide_clip_children(true);
}
//////////
@@ -467,4 +468,5 @@ void DirectionalLight2D::_bind_methods() {
DirectionalLight2D::DirectionalLight2D() {
RS::get_singleton()->canvas_light_set_mode(_get_light(), RS::CANVAS_LIGHT_MODE_DIRECTIONAL);
set_max_distance(max_distance); // Update RenderingServer.
+ set_hide_clip_children(true);
}
diff --git a/scene/2d/marker_2d.cpp b/scene/2d/marker_2d.cpp
index 512875833c..9595fcfffe 100644
--- a/scene/2d/marker_2d.cpp
+++ b/scene/2d/marker_2d.cpp
@@ -117,4 +117,5 @@ void Marker2D::_bind_methods() {
}
Marker2D::Marker2D() {
+ set_hide_clip_children(true);
}
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 907fb7e6a9..85f6840fde 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -108,6 +108,26 @@ void NavigationAgent2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_time_horizon", "get_time_horizon");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:px/s"), "set_max_speed", "get_max_speed");
+#ifdef DEBUG_ENABLED
+ ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationAgent2D::set_debug_enabled);
+ ClassDB::bind_method(D_METHOD("get_debug_enabled"), &NavigationAgent2D::get_debug_enabled);
+ ClassDB::bind_method(D_METHOD("set_debug_use_custom", "enabled"), &NavigationAgent2D::set_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("get_debug_use_custom"), &NavigationAgent2D::get_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_color", "color"), &NavigationAgent2D::set_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_color"), &NavigationAgent2D::get_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_point_size", "point_size"), &NavigationAgent2D::set_debug_path_custom_point_size);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_point_size"), &NavigationAgent2D::get_debug_path_custom_point_size);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_line_width", "line_width"), &NavigationAgent2D::set_debug_path_custom_line_width);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_line_width"), &NavigationAgent2D::get_debug_path_custom_line_width);
+
+ ADD_GROUP("Debug", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_enabled"), "set_debug_enabled", "get_debug_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_custom"), "set_debug_use_custom", "get_debug_use_custom");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_path_custom_color"), "set_debug_path_custom_color", "get_debug_path_custom_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_point_size", PROPERTY_HINT_RANGE, "1,50,1,suffix:px"), "set_debug_path_custom_point_size", "get_debug_path_custom_point_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_line_width", PROPERTY_HINT_RANGE, "1,50,1,suffix:px"), "set_debug_path_custom_line_width", "get_debug_path_custom_line_width");
+#endif // DEBUG_ENABLED
+
ADD_SIGNAL(MethodInfo("path_changed"));
ADD_SIGNAL(MethodInfo("target_reached"));
ADD_SIGNAL(MethodInfo("waypoint_reached", PropertyInfo(Variant::DICTIONARY, "details")));
@@ -120,9 +140,15 @@ void NavigationAgent2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POST_ENTER_TREE: {
// need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready.
- // cannot use READY as ready does not get called if Node is readded to SceneTree
+ // cannot use READY as ready does not get called if Node is re-added to SceneTree
set_agent_parent(get_parent());
set_physics_process_internal(true);
+
+#ifdef DEBUG_ENABLED
+ if (NavigationServer2D::get_singleton()->get_debug_enabled()) {
+ debug_path_dirty = true;
+ }
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_PARENTED: {
@@ -142,6 +168,17 @@ void NavigationAgent2D::_notification(int p_what) {
set_physics_process_internal(false);
} break;
+ case NOTIFICATION_EXIT_TREE: {
+ set_agent_parent(nullptr);
+ set_physics_process_internal(false);
+
+#ifdef DEBUG_ENABLED
+ if (debug_path_instance.is_valid()) {
+ RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, false);
+ }
+#endif // DEBUG_ENABLED
+ } break;
+
case NOTIFICATION_PAUSED: {
if (agent_parent && !agent_parent->can_process()) {
map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
@@ -162,11 +199,6 @@ void NavigationAgent2D::_notification(int p_what) {
}
} break;
- case NOTIFICATION_EXIT_TREE: {
- agent_parent = nullptr;
- set_physics_process_internal(false);
- } break;
-
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent && target_position_submitted) {
if (avoidance_enabled) {
@@ -176,17 +208,22 @@ void NavigationAgent2D::_notification(int p_what) {
}
_check_distance_to_target();
}
+#ifdef DEBUG_ENABLED
+ if (debug_path_dirty) {
+ _update_debug_path();
+ }
+#endif // DEBUG_ENABLED
} break;
}
}
NavigationAgent2D::NavigationAgent2D() {
agent = NavigationServer2D::get_singleton()->agent_create();
- set_neighbor_distance(neighbor_distance);
- set_max_neighbors(max_neighbors);
- set_time_horizon(time_horizon);
- set_radius(radius);
- set_max_speed(max_speed);
+ NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
+ NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
+ NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
+ NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
+ NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
// Preallocate query and result objects to improve performance.
navigation_query = Ref<NavigationPathQueryParameters2D>();
@@ -194,20 +231,38 @@ NavigationAgent2D::NavigationAgent2D() {
navigation_result = Ref<NavigationPathQueryResult2D>();
navigation_result.instantiate();
+
+#ifdef DEBUG_ENABLED
+ NavigationServer2D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent2D::_navigation_debug_changed));
+#endif // DEBUG_ENABLED
}
NavigationAgent2D::~NavigationAgent2D() {
ERR_FAIL_NULL(NavigationServer2D::get_singleton());
NavigationServer2D::get_singleton()->free(agent);
agent = RID(); // Pointless
+
+#ifdef DEBUG_ENABLED
+ NavigationServer2D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent2D::_navigation_debug_changed));
+
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ if (debug_path_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_path_instance);
+ }
+#endif // DEBUG_ENABLED
}
void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) {
+ if (avoidance_enabled == p_enabled) {
+ return;
+ }
+
avoidance_enabled = p_enabled;
+
if (avoidance_enabled) {
- NavigationServer2D::get_singleton()->agent_set_callback(agent, get_instance_id(), "_avoidance_done");
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
} else {
- NavigationServer2D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, Callable());
}
}
@@ -216,8 +271,13 @@ bool NavigationAgent2D::get_avoidance_enabled() const {
}
void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
+ if (agent_parent == p_agent_parent) {
+ return;
+ }
+
// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
- NavigationServer2D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, Callable());
+
if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
// place agent on navigation map first or else the RVO agent callback creation fails silently later
agent_parent = Object::cast_to<Node2D>(p_agent_parent);
@@ -226,8 +286,11 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
} else {
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
}
+
// create new avoidance callback if enabled
- set_avoidance_enabled(avoidance_enabled);
+ if (avoidance_enabled) {
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
+ }
} else {
agent_parent = nullptr;
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
@@ -235,11 +298,13 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
}
void NavigationAgent2D::set_navigation_layers(uint32_t p_navigation_layers) {
- bool navigation_layers_changed = navigation_layers != p_navigation_layers;
- navigation_layers = p_navigation_layers;
- if (navigation_layers_changed) {
- _request_repath();
+ if (navigation_layers == p_navigation_layers) {
+ return;
}
+
+ navigation_layers = p_navigation_layers;
+
+ _request_repath();
}
uint32_t NavigationAgent2D::get_navigation_layers() const {
@@ -273,7 +338,12 @@ void NavigationAgent2D::set_path_metadata_flags(BitField<NavigationPathQueryPara
}
void NavigationAgent2D::set_navigation_map(RID p_navigation_map) {
+ if (map_override == p_navigation_map) {
+ return;
+ }
+
map_override = p_navigation_map;
+
NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
_request_repath();
}
@@ -287,41 +357,78 @@ RID NavigationAgent2D::get_navigation_map() const {
return RID();
}
-void NavigationAgent2D::set_path_desired_distance(real_t p_dd) {
- path_desired_distance = p_dd;
+void NavigationAgent2D::set_path_desired_distance(real_t p_path_desired_distance) {
+ if (Math::is_equal_approx(path_desired_distance, p_path_desired_distance)) {
+ return;
+ }
+
+ path_desired_distance = p_path_desired_distance;
}
-void NavigationAgent2D::set_target_desired_distance(real_t p_dd) {
- target_desired_distance = p_dd;
+void NavigationAgent2D::set_target_desired_distance(real_t p_target_desired_distance) {
+ if (Math::is_equal_approx(target_desired_distance, p_target_desired_distance)) {
+ return;
+ }
+
+ target_desired_distance = p_target_desired_distance;
}
void NavigationAgent2D::set_radius(real_t p_radius) {
+ if (Math::is_equal_approx(radius, p_radius)) {
+ return;
+ }
+
radius = p_radius;
+
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
}
void NavigationAgent2D::set_neighbor_distance(real_t p_distance) {
+ if (Math::is_equal_approx(neighbor_distance, p_distance)) {
+ return;
+ }
+
neighbor_distance = p_distance;
+
NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
}
void NavigationAgent2D::set_max_neighbors(int p_count) {
+ if (max_neighbors == p_count) {
+ return;
+ }
+
max_neighbors = p_count;
+
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
}
void NavigationAgent2D::set_time_horizon(real_t p_time) {
+ if (Math::is_equal_approx(time_horizon, p_time)) {
+ return;
+ }
+
time_horizon = p_time;
+
NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
}
void NavigationAgent2D::set_max_speed(real_t p_max_speed) {
+ if (Math::is_equal_approx(max_speed, p_max_speed)) {
+ return;
+ }
+
max_speed = p_max_speed;
+
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
}
-void NavigationAgent2D::set_path_max_distance(real_t p_pmd) {
- path_max_distance = p_pmd;
+void NavigationAgent2D::set_path_max_distance(real_t p_path_max_distance) {
+ if (Math::is_equal_approx(path_max_distance, p_path_max_distance)) {
+ return;
+ }
+
+ path_max_distance = p_path_max_distance;
}
real_t NavigationAgent2D::get_path_max_distance() {
@@ -329,8 +436,13 @@ real_t NavigationAgent2D::get_path_max_distance() {
}
void NavigationAgent2D::set_target_position(Vector2 p_position) {
+ if (target_position.is_equal_approx(p_position)) {
+ return;
+ }
+
target_position = p_position;
target_position_submitted = true;
+
_request_repath();
}
@@ -379,10 +491,15 @@ Vector2 NavigationAgent2D::get_final_position() {
}
void NavigationAgent2D::set_velocity(Vector2 p_velocity) {
+ if (target_velocity.is_equal_approx(p_velocity)) {
+ return;
+ }
+
target_velocity = p_velocity;
+ velocity_submitted = true;
+
NavigationServer2D::get_singleton()->agent_set_target_velocity(agent, target_velocity);
NavigationServer2D::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
- velocity_submitted = true;
}
void NavigationAgent2D::_avoidance_done(Vector3 p_new_velocity) {
@@ -461,6 +578,9 @@ void NavigationAgent2D::update_navigation() {
}
NavigationServer2D::get_singleton()->query_path(navigation_query, navigation_result);
+#ifdef DEBUG_ENABLED
+ debug_path_dirty = true;
+#endif // DEBUG_ENABLED
navigation_finished = false;
navigation_path_index = 0;
emit_signal(SNAME("path_changed"));
@@ -547,3 +667,131 @@ void NavigationAgent2D::_check_distance_to_target() {
}
}
}
+
+////////DEBUG////////////////////////////////////////////////////////////
+
+#ifdef DEBUG_ENABLED
+void NavigationAgent2D::set_debug_enabled(bool p_enabled) {
+ if (debug_enabled == p_enabled) {
+ return;
+ }
+
+ debug_enabled = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent2D::get_debug_enabled() const {
+ return debug_enabled;
+}
+
+void NavigationAgent2D::set_debug_use_custom(bool p_enabled) {
+ if (debug_use_custom == p_enabled) {
+ return;
+ }
+
+ debug_use_custom = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent2D::get_debug_use_custom() const {
+ return debug_use_custom;
+}
+
+void NavigationAgent2D::set_debug_path_custom_color(Color p_color) {
+ if (debug_path_custom_color == p_color) {
+ return;
+ }
+
+ debug_path_custom_color = p_color;
+ debug_path_dirty = true;
+}
+
+Color NavigationAgent2D::get_debug_path_custom_color() const {
+ return debug_path_custom_color;
+}
+
+void NavigationAgent2D::set_debug_path_custom_point_size(float p_point_size) {
+ if (Math::is_equal_approx(debug_path_custom_point_size, p_point_size)) {
+ return;
+ }
+
+ debug_path_custom_point_size = MAX(0.1, p_point_size);
+ debug_path_dirty = true;
+}
+
+float NavigationAgent2D::get_debug_path_custom_point_size() const {
+ return debug_path_custom_point_size;
+}
+
+void NavigationAgent2D::set_debug_path_custom_line_width(float p_line_width) {
+ if (Math::is_equal_approx(debug_path_custom_line_width, p_line_width)) {
+ return;
+ }
+
+ debug_path_custom_line_width = p_line_width;
+ debug_path_dirty = true;
+}
+
+float NavigationAgent2D::get_debug_path_custom_line_width() const {
+ return debug_path_custom_line_width;
+}
+
+void NavigationAgent2D::_navigation_debug_changed() {
+ debug_path_dirty = true;
+}
+
+void NavigationAgent2D::_update_debug_path() {
+ if (!debug_path_dirty) {
+ return;
+ }
+ debug_path_dirty = false;
+
+ if (!debug_path_instance.is_valid()) {
+ debug_path_instance = RenderingServer::get_singleton()->canvas_item_create();
+ }
+
+ RenderingServer::get_singleton()->canvas_item_clear(debug_path_instance);
+
+ if (!(debug_enabled && NavigationServer2D::get_singleton()->get_debug_navigation_enable_agent_paths())) {
+ return;
+ }
+
+ if (!(agent_parent && agent_parent->is_inside_tree())) {
+ return;
+ }
+
+ RenderingServer::get_singleton()->canvas_item_set_parent(debug_path_instance, agent_parent->get_canvas());
+ RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, agent_parent->is_visible_in_tree());
+
+ const Vector<Vector2> &navigation_path = navigation_result->get_path();
+
+ if (navigation_path.size() <= 1) {
+ return;
+ }
+
+ Color debug_path_color = NavigationServer2D::get_singleton()->get_debug_navigation_agent_path_color();
+ if (debug_use_custom) {
+ debug_path_color = debug_path_custom_color;
+ }
+
+ Vector<Color> debug_path_colors;
+ debug_path_colors.resize(navigation_path.size());
+ debug_path_colors.fill(debug_path_color);
+
+ RenderingServer::get_singleton()->canvas_item_add_polyline(debug_path_instance, navigation_path, debug_path_colors, debug_path_custom_line_width, false);
+
+ float point_size = NavigationServer2D::get_singleton()->get_debug_navigation_agent_path_point_size();
+ float half_point_size = point_size * 0.5;
+
+ if (debug_use_custom) {
+ point_size = debug_path_custom_point_size;
+ half_point_size = debug_path_custom_point_size * 0.5;
+ }
+
+ for (int i = 0; i < navigation_path.size(); i++) {
+ const Vector2 &vert = navigation_path[i];
+ Rect2 path_point_rect = Rect2(vert.x - half_point_size, vert.y - half_point_size, point_size, point_size);
+ RenderingServer::get_singleton()->canvas_item_add_rect(debug_path_instance, path_point_rect, debug_path_color);
+ }
+}
+#endif // DEBUG_ENABLED
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 9787bb1bdb..5278c81f66 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -57,7 +57,6 @@ class NavigationAgent2D : public Node {
int max_neighbors = 10;
real_t time_horizon = 1.0;
real_t max_speed = 100.0;
-
real_t path_max_distance = 100.0;
Vector2 target_position;
@@ -74,6 +73,20 @@ class NavigationAgent2D : public Node {
// No initialized on purpose
uint32_t update_frame_id = 0;
+#ifdef DEBUG_ENABLED
+ bool debug_enabled = false;
+ bool debug_path_dirty = true;
+ RID debug_path_instance;
+ float debug_path_custom_point_size = 4.0;
+ float debug_path_custom_line_width = 1.0;
+ bool debug_use_custom = false;
+ Color debug_path_custom_color = Color(1.0, 1.0, 1.0, 1.0);
+
+private:
+ void _navigation_debug_changed();
+ void _update_debug_path();
+#endif // DEBUG_ENABLED
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -169,6 +182,23 @@ public:
PackedStringArray get_configuration_warnings() const override;
+#ifdef DEBUG_ENABLED
+ void set_debug_enabled(bool p_enabled);
+ bool get_debug_enabled() const;
+
+ void set_debug_use_custom(bool p_enabled);
+ bool get_debug_use_custom() const;
+
+ void set_debug_path_custom_color(Color p_color);
+ Color get_debug_path_custom_color() const;
+
+ void set_debug_path_custom_point_size(float p_point_size);
+ float get_debug_path_custom_point_size() const;
+
+ void set_debug_path_custom_line_width(float p_line_width);
+ float get_debug_path_custom_line_width() const;
+#endif // DEBUG_ENABLED
+
private:
void update_navigation();
void _request_repath();
diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp
index 65bf178cc5..26dca40176 100644
--- a/scene/2d/navigation_link_2d.cpp
+++ b/scene/2d/navigation_link_2d.cpp
@@ -308,6 +308,7 @@ NavigationLink2D::NavigationLink2D() {
NavigationServer2D::get_singleton()->link_set_owner_id(link, get_instance_id());
set_notify_transform(true);
+ set_hide_clip_children(true);
}
NavigationLink2D::~NavigationLink2D() {
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index 4bd170301a..d7ef77e25b 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -185,6 +185,10 @@ real_t NavigationObstacle2D::estimate_agent_radius() const {
}
void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) {
+ if (parent_node2d == p_agent_parent) {
+ return;
+ }
+
if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
parent_node2d = Object::cast_to<Node2D>(p_agent_parent);
if (map_override.is_valid()) {
@@ -200,7 +204,12 @@ void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) {
}
void NavigationObstacle2D::set_navigation_map(RID p_navigation_map) {
+ if (map_override == p_navigation_map) {
+ return;
+ }
+
map_override = p_navigation_map;
+
NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
}
@@ -214,13 +223,23 @@ RID NavigationObstacle2D::get_navigation_map() const {
}
void NavigationObstacle2D::set_estimate_radius(bool p_estimate_radius) {
+ if (estimate_radius == p_estimate_radius) {
+ return;
+ }
+
estimate_radius = p_estimate_radius;
+
notify_property_list_changed();
reevaluate_agent_radius();
}
void NavigationObstacle2D::set_radius(real_t p_radius) {
ERR_FAIL_COND_MSG(p_radius <= 0.0, "Radius must be greater than 0.");
+ if (Math::is_equal_approx(radius, p_radius)) {
+ return;
+ }
+
radius = p_radius;
+
reevaluate_agent_radius();
}
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index fe6af8dad2..3484a9de65 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -330,6 +330,7 @@ bool NavigationRegion2D::_get(const StringName &p_name, Variant &r_ret) const {
NavigationRegion2D::NavigationRegion2D() {
set_notify_transform(true);
+ set_hide_clip_children(true);
region = NavigationServer2D::get_singleton()->region_create();
NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id());
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 39f88a0b5e..988ea87054 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -370,4 +370,5 @@ void RayCast2D::_bind_methods() {
}
RayCast2D::RayCast2D() {
+ set_hide_clip_children(true);
}
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index e9ce9560d3..c6730f7ab2 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -219,4 +219,5 @@ void RemoteTransform2D::_bind_methods() {
RemoteTransform2D::RemoteTransform2D() {
set_notify_transform(true);
+ set_hide_clip_children(true);
}
diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp
index 24821858cf..bafb83361a 100644
--- a/scene/2d/shape_cast_2d.cpp
+++ b/scene/2d/shape_cast_2d.cpp
@@ -472,3 +472,7 @@ void ShapeCast2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled");
}
+
+ShapeCast2D::ShapeCast2D() {
+ set_hide_clip_children(true);
+}
diff --git a/scene/2d/shape_cast_2d.h b/scene/2d/shape_cast_2d.h
index 182614a721..8a62b799f8 100644
--- a/scene/2d/shape_cast_2d.h
+++ b/scene/2d/shape_cast_2d.h
@@ -119,6 +119,8 @@ public:
void clear_exceptions();
PackedStringArray get_configuration_warnings() const override;
+
+ ShapeCast2D();
};
#endif // SHAPE_CAST_2D_H
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 83cfffc333..96711bbe72 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -519,6 +519,7 @@ Bone2D::Bone2D() {
bone_angle = 0;
autocalculate_length_and_angle = true;
set_notify_local_transform(true);
+ set_hide_clip_children(true);
//this is a clever hack so the bone knows no rest has been set yet, allowing to show an error.
for (int i = 0; i < 3; i++) {
rest[i] = Vector2(0, 0);
@@ -801,6 +802,7 @@ void Skeleton2D::_bind_methods() {
Skeleton2D::Skeleton2D() {
skeleton = RS::get_singleton()->skeleton_create();
set_notify_transform(true);
+ set_hide_clip_children(true);
}
Skeleton2D::~Skeleton2D() {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index a1304ab991..95bf67d38d 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -3969,6 +3969,17 @@ PackedStringArray TileMap::get_configuration_warnings() const {
}
}
+ // Check if Y-sort is enabled on a layer but not on the node.
+ if (!is_y_sort_enabled()) {
+ for (const TileMapLayer &layer : layers) {
+ if (layer.y_sort_enabled) {
+ warnings.push_back(RTR("A TileMap layer is set as Y-sorted, but Y-sort is not enabled on the TileMap node itself."));
+ break;
+ }
+ }
+ }
+
+ // Check if we are in isometric mode without Y-sort enabled.
if (tile_set.is_valid() && tile_set->get_tile_shape() == TileSet::TILE_SHAPE_ISOMETRIC) {
bool warn = !is_y_sort_enabled();
if (!warn) {
diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp
index 237eb3d987..1177cdb811 100644
--- a/scene/2d/visible_on_screen_notifier_2d.cpp
+++ b/scene/2d/visible_on_screen_notifier_2d.cpp
@@ -110,6 +110,7 @@ void VisibleOnScreenNotifier2D::_bind_methods() {
VisibleOnScreenNotifier2D::VisibleOnScreenNotifier2D() {
rect = Rect2(-10, -10, 20, 20);
+ set_hide_clip_children(true);
}
//////////////////////////////////////
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index 72f186c676..5901e38bb4 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -51,13 +51,13 @@ bool Area3D::is_gravity_a_point() const {
return gravity_is_point;
}
-void Area3D::set_gravity_point_distance_scale(real_t p_scale) {
- gravity_distance_scale = p_scale;
- PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_DISTANCE_SCALE, p_scale);
+void Area3D::set_gravity_point_unit_distance(real_t p_scale) {
+ gravity_point_unit_distance = p_scale;
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_UNIT_DISTANCE, p_scale);
}
-real_t Area3D::get_gravity_point_distance_scale() const {
- return gravity_distance_scale;
+real_t Area3D::get_gravity_point_unit_distance() const {
+ return gravity_point_unit_distance;
}
void Area3D::set_gravity_point_center(const Vector3 &p_center) {
@@ -655,8 +655,8 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_gravity_is_point", "enable"), &Area3D::set_gravity_is_point);
ClassDB::bind_method(D_METHOD("is_gravity_a_point"), &Area3D::is_gravity_a_point);
- ClassDB::bind_method(D_METHOD("set_gravity_point_distance_scale", "distance_scale"), &Area3D::set_gravity_point_distance_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_point_distance_scale"), &Area3D::get_gravity_point_distance_scale);
+ ClassDB::bind_method(D_METHOD("set_gravity_point_unit_distance", "distance_scale"), &Area3D::set_gravity_point_unit_distance);
+ ClassDB::bind_method(D_METHOD("get_gravity_point_unit_distance"), &Area3D::get_gravity_point_unit_distance);
ClassDB::bind_method(D_METHOD("set_gravity_point_center", "center"), &Area3D::set_gravity_point_center);
ClassDB::bind_method(D_METHOD("get_gravity_point_center"), &Area3D::get_gravity_point_center);
@@ -741,7 +741,7 @@ void Area3D::_bind_methods() {
ADD_GROUP("Gravity", "gravity_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "gravity_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_space_override_mode", "get_gravity_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_unit_distance", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp,suffix:m"), "set_gravity_point_unit_distance", "get_gravity_point_unit_distance");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:m"), "set_gravity_point_center", "get_gravity_point_center");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_direction"), "set_gravity_direction", "get_gravity_direction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_less,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 91b91f741a..607e0d2af8 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -51,7 +51,7 @@ private:
Vector3 gravity_vec;
real_t gravity = 0.0;
bool gravity_is_point = false;
- real_t gravity_distance_scale = 0.0;
+ real_t gravity_point_unit_distance = 0.0;
SpaceOverride linear_damp_space_override = SPACE_OVERRIDE_DISABLED;
SpaceOverride angular_damp_space_override = SPACE_OVERRIDE_DISABLED;
@@ -155,8 +155,8 @@ public:
void set_gravity_is_point(bool p_enabled);
bool is_gravity_a_point() const;
- void set_gravity_point_distance_scale(real_t p_scale);
- real_t get_gravity_point_distance_scale() const;
+ void set_gravity_point_unit_distance(real_t p_scale);
+ real_t get_gravity_point_unit_distance() const;
void set_gravity_point_center(const Vector3 &p_center);
const Vector3 &get_gravity_point_center() const;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 7ed18d2d41..436b936586 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -284,14 +284,12 @@ void AudioStreamPlayer3D::_notification(int p_what) {
volume_vector = _update_panning();
}
- if (setplay.get() >= 0 && stream.is_valid()) {
+ if (setplayback.is_valid() && setplay.get() >= 0) {
active.set();
- Ref<AudioStreamPlayback> new_playback = stream->instantiate_playback();
- ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback.");
HashMap<StringName, Vector<AudioFrame>> bus_map;
bus_map[_get_actual_bus()] = volume_vector;
- AudioServer::get_singleton()->start_playback_stream(new_playback, bus_map, setplay.get(), actual_pitch_scale, linear_attenuation, attenuation_filter_cutoff_hz);
- stream_playbacks.push_back(new_playback);
+ AudioServer::get_singleton()->start_playback_stream(setplayback, bus_map, setplay.get(), actual_pitch_scale, linear_attenuation, attenuation_filter_cutoff_hz);
+ setplayback.unref();
setplay.set(-1);
}
@@ -580,14 +578,21 @@ void AudioStreamPlayer3D::play(float p_from_pos) {
if (stream->is_monophonic() && is_playing()) {
stop();
}
+ Ref<AudioStreamPlayback> stream_playback = stream->instantiate_playback();
+ ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback.");
+
+ stream_playbacks.push_back(stream_playback);
+ setplayback = stream_playback;
setplay.set(p_from_pos);
active.set();
set_physics_process_internal(true);
}
void AudioStreamPlayer3D::seek(float p_seconds) {
- stop();
- play(p_seconds);
+ if (is_playing()) {
+ stop();
+ play(p_seconds);
+ }
}
void AudioStreamPlayer3D::stop() {
@@ -783,6 +788,10 @@ bool AudioStreamPlayer3D::get_stream_paused() const {
return false;
}
+bool AudioStreamPlayer3D::has_stream_playback() {
+ return !stream_playbacks.is_empty();
+}
+
Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
return stream_playbacks[stream_playbacks.size() - 1];
@@ -875,6 +884,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_panning_strength", "panning_strength"), &AudioStreamPlayer3D::set_panning_strength);
ClassDB::bind_method(D_METHOD("get_panning_strength"), &AudioStreamPlayer3D::get_panning_strength);
+ ClassDB::bind_method(D_METHOD("has_stream_playback"), &AudioStreamPlayer3D::has_stream_playback);
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 67cec91896..bba8f10761 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -69,6 +69,7 @@ private:
SafeFlag active{ false };
SafeNumeric<float> setplay{ -1.0 };
+ Ref<AudioStreamPlayback> setplayback;
AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE;
float volume_db = 0.0;
@@ -188,6 +189,7 @@ public:
void set_panning_strength(float p_panning_strength);
float get_panning_strength() const;
+ bool has_stream_playback();
Ref<AudioStreamPlayback> get_stream_playback();
AudioStreamPlayer3D();
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index fe7f6837f0..ba5ff02862 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -81,11 +81,6 @@ bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const {
}
void BoneAttachment3D::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "override_pose", PROPERTY_HINT_NONE, ""));
- if (override_pose) {
- p_list->push_back(PropertyInfo(Variant::INT, "override_mode", PROPERTY_HINT_ENUM, "Global Pose Override,Local Pose Override,Custom Pose"));
- }
-
p_list->push_back(PropertyInfo(Variant::BOOL, "use_external_skeleton", PROPERTY_HINT_NONE, ""));
if (use_external_skeleton) {
p_list->push_back(PropertyInfo(Variant::NODE_PATH, "external_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"));
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index fbcb1c8f2c..e122adcc8c 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -30,14 +30,14 @@
#include "decal.h"
-void Decal::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
- RS::get_singleton()->decal_set_extents(decal, p_extents);
+void Decal::set_size(const Vector3 &p_size) {
+ size = p_size;
+ RS::get_singleton()->decal_set_size(decal, p_size);
update_gizmos();
}
-Vector3 Decal::get_extents() const {
- return extents;
+Vector3 Decal::get_size() const {
+ return size;
}
void Decal::set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture) {
@@ -147,8 +147,8 @@ uint32_t Decal::get_cull_mask() const {
AABB Decal::get_aabb() const {
AABB aabb;
- aabb.position = -extents;
- aabb.size = extents * 2.0;
+ aabb.position = -size / 2;
+ aabb.size = size;
return aabb;
}
@@ -181,8 +181,8 @@ PackedStringArray Decal::get_configuration_warnings() const {
}
void Decal::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &Decal::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &Decal::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &Decal::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &Decal::get_size);
ClassDB::bind_method(D_METHOD("set_texture", "type", "texture"), &Decal::set_texture);
ClassDB::bind_method(D_METHOD("get_texture", "type"), &Decal::get_texture);
@@ -217,7 +217,7 @@ void Decal::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cull_mask", "mask"), &Decal::set_cull_mask);
ClassDB::bind_method(D_METHOD("get_cull_mask"), &Decal::get_cull_mask);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,suffix:m"), "set_size", "get_size");
ADD_GROUP("Textures", "texture_");
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "texture_albedo", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ALBEDO);
@@ -252,6 +252,24 @@ void Decal::_bind_methods() {
BIND_ENUM_CONSTANT(TEXTURE_MAX);
}
+#ifndef DISABLE_DEPRECATED
+bool Decal::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool Decal::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
Decal::Decal() {
decal = RenderingServer::get_singleton()->decal_create();
RS::get_singleton()->instance_set_base(get_instance(), decal);
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index 5797a2f645..171b52815a 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -47,7 +47,7 @@ public:
private:
RID decal;
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 size = Vector3(2, 2, 2);
Ref<Texture2D> textures[TEXTURE_MAX];
real_t emission_energy = 1.0;
real_t albedo_mix = 1.0;
@@ -63,12 +63,16 @@ private:
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
virtual PackedStringArray get_configuration_warnings() const override;
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture(DecalTexture p_type) const;
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index 30dfb45836..9b0a7bb302 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -34,36 +34,54 @@
///////////////////////////
void FogVolume::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &FogVolume::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &FogVolume::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &FogVolume::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &FogVolume::get_size);
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &FogVolume::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &FogVolume::get_shape);
ClassDB::bind_method(D_METHOD("set_material", "material"), &FogVolume::set_material);
ClassDB::bind_method(D_METHOD("get_material"), &FogVolume::get_material);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "shape", PROPERTY_HINT_ENUM, "Ellipsoid (Local),Cone (Local),Cylinder (Local),Box (Local),World (Global)"), "set_shape", "get_shape");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material");
}
void FogVolume::_validate_property(PropertyInfo &p_property) const {
- if (p_property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) {
+ if (p_property.name == "size" && shape == RS::FOG_VOLUME_SHAPE_WORLD) {
p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
-void FogVolume::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
- extents.x = MAX(0.0, extents.x);
- extents.y = MAX(0.0, extents.y);
- extents.z = MAX(0.0, extents.z);
- RS::get_singleton()->fog_volume_set_extents(_get_volume(), extents);
+#ifndef DISABLE_DEPRECATED
+bool FogVolume::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool FogVolume::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
+void FogVolume::set_size(const Vector3 &p_size) {
+ size = p_size;
+ size.x = MAX(0.0, size.x);
+ size.y = MAX(0.0, size.y);
+ size.z = MAX(0.0, size.z);
+ RS::get_singleton()->fog_volume_set_size(_get_volume(), size);
update_gizmos();
}
-Vector3 FogVolume::get_extents() const {
- return extents;
+Vector3 FogVolume::get_size() const {
+ return size;
}
void FogVolume::set_shape(RS::FogVolumeShape p_type) {
@@ -94,7 +112,7 @@ Ref<Material> FogVolume::get_material() const {
AABB FogVolume::get_aabb() const {
if (shape != RS::FOG_VOLUME_SHAPE_WORLD) {
- return AABB(-extents, extents * 2);
+ return AABB(-size / 2, size);
}
return AABB();
}
diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h
index fa02834762..f7e861e3d0 100644
--- a/scene/3d/fog_volume.h
+++ b/scene/3d/fog_volume.h
@@ -40,7 +40,7 @@
class FogVolume : public VisualInstance3D {
GDCLASS(FogVolume, VisualInstance3D);
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 size = Vector3(2, 2, 2);
Ref<Material> material;
RS::FogVolumeShape shape = RS::FOG_VOLUME_SHAPE_BOX;
@@ -50,10 +50,14 @@ protected:
_FORCE_INLINE_ RID _get_volume() { return volume; }
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_shape(RS::FogVolumeShape p_type);
RS::FogVolumeShape get_shape() const;
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index d1f2dfb25f..137d578291 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -95,24 +95,42 @@ GPUParticlesCollisionSphere3D::~GPUParticlesCollisionSphere3D() {
///////////////////////////
void GPUParticlesCollisionBox3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionBox3D::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionBox3D::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesCollisionBox3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesCollisionBox3D::get_size);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
}
-void GPUParticlesCollisionBox3D::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
- RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+#ifndef DISABLE_DEPRECATED
+bool GPUParticlesCollisionBox3D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool GPUParticlesCollisionBox3D::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
+void GPUParticlesCollisionBox3D::set_size(const Vector3 &p_size) {
+ size = p_size;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
update_gizmos();
}
-Vector3 GPUParticlesCollisionBox3D::get_extents() const {
- return extents;
+Vector3 GPUParticlesCollisionBox3D::get_size() const {
+ return size;
}
AABB GPUParticlesCollisionBox3D::get_aabb() const {
- return AABB(-extents, extents * 2);
+ return AABB(-size / 2, size);
}
GPUParticlesCollisionBox3D::GPUParticlesCollisionBox3D() :
@@ -359,7 +377,7 @@ Vector3i GPUParticlesCollisionSDF3D::get_estimated_cell_size() const {
static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
int subdiv = subdivs[get_resolution()];
- AABB aabb(-extents, extents * 2);
+ AABB aabb(-size / 2, size);
float cell_size = aabb.get_longest_axis_size() / float(subdiv);
@@ -374,7 +392,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
static const int subdivs[RESOLUTION_MAX] = { 16, 32, 64, 128, 256, 512 };
int subdiv = subdivs[get_resolution()];
- AABB aabb(-extents, extents * 2);
+ AABB aabb(-size / 2, size);
float cell_size = aabb.get_longest_axis_size() / float(subdiv);
@@ -515,8 +533,8 @@ PackedStringArray GPUParticlesCollisionSDF3D::get_configuration_warnings() const
}
void GPUParticlesCollisionSDF3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionSDF3D::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionSDF3D::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesCollisionSDF3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesCollisionSDF3D::get_size);
ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionSDF3D::set_resolution);
ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionSDF3D::get_resolution);
@@ -532,7 +550,7 @@ void GPUParticlesCollisionSDF3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bake_mask_value", "layer_number", "value"), &GPUParticlesCollisionSDF3D::set_bake_mask_value);
ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
@@ -547,6 +565,24 @@ void GPUParticlesCollisionSDF3D::_bind_methods() {
BIND_ENUM_CONSTANT(RESOLUTION_MAX);
}
+#ifndef DISABLE_DEPRECATED
+bool GPUParticlesCollisionSDF3D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool GPUParticlesCollisionSDF3D::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
void GPUParticlesCollisionSDF3D::set_thickness(float p_thickness) {
thickness = p_thickness;
}
@@ -555,14 +591,14 @@ float GPUParticlesCollisionSDF3D::get_thickness() const {
return thickness;
}
-void GPUParticlesCollisionSDF3D::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
- RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+void GPUParticlesCollisionSDF3D::set_size(const Vector3 &p_size) {
+ size = p_size;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
update_gizmos();
}
-Vector3 GPUParticlesCollisionSDF3D::get_extents() const {
- return extents;
+Vector3 GPUParticlesCollisionSDF3D::get_size() const {
+ return size;
}
void GPUParticlesCollisionSDF3D::set_resolution(Resolution p_resolution) {
@@ -610,7 +646,7 @@ Ref<Texture3D> GPUParticlesCollisionSDF3D::get_texture() const {
}
AABB GPUParticlesCollisionSDF3D::get_aabb() const {
- return AABB(-extents, extents * 2);
+ return AABB(-size / 2, size);
}
GPUParticlesCollisionSDF3D::BakeBeginFunc GPUParticlesCollisionSDF3D::bake_begin_function = nullptr;
@@ -675,8 +711,8 @@ void GPUParticlesCollisionHeightField3D::_notification(int p_what) {
}
void GPUParticlesCollisionHeightField3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionHeightField3D::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionHeightField3D::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesCollisionHeightField3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesCollisionHeightField3D::get_size);
ClassDB::bind_method(D_METHOD("set_resolution", "resolution"), &GPUParticlesCollisionHeightField3D::set_resolution);
ClassDB::bind_method(D_METHOD("get_resolution"), &GPUParticlesCollisionHeightField3D::get_resolution);
@@ -687,7 +723,7 @@ void GPUParticlesCollisionHeightField3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_follow_camera_enabled", "enabled"), &GPUParticlesCollisionHeightField3D::set_follow_camera_enabled);
ClassDB::bind_method(D_METHOD("is_follow_camera_enabled"), &GPUParticlesCollisionHeightField3D::is_follow_camera_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256 (Fastest),512 (Fast),1024 (Average),2048 (Slow),4096 (Slower),8192 (Slowest)"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "When Moved (Fast),Always (Slow)"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_enabled", "is_follow_camera_enabled");
@@ -704,15 +740,33 @@ void GPUParticlesCollisionHeightField3D::_bind_methods() {
BIND_ENUM_CONSTANT(UPDATE_MODE_ALWAYS);
}
-void GPUParticlesCollisionHeightField3D::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
- RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+#ifndef DISABLE_DEPRECATED
+bool GPUParticlesCollisionHeightField3D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool GPUParticlesCollisionHeightField3D::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
+void GPUParticlesCollisionHeightField3D::set_size(const Vector3 &p_size) {
+ size = p_size;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
update_gizmos();
RS::get_singleton()->particles_collision_height_field_update(_get_collision());
}
-Vector3 GPUParticlesCollisionHeightField3D::get_extents() const {
- return extents;
+Vector3 GPUParticlesCollisionHeightField3D::get_size() const {
+ return size;
}
void GPUParticlesCollisionHeightField3D::set_resolution(Resolution p_resolution) {
@@ -745,7 +799,7 @@ bool GPUParticlesCollisionHeightField3D::is_follow_camera_enabled() const {
}
AABB GPUParticlesCollisionHeightField3D::get_aabb() const {
- return AABB(-extents, extents * 2);
+ return AABB(-size / 2, size);
}
GPUParticlesCollisionHeightField3D::GPUParticlesCollisionHeightField3D() :
@@ -857,24 +911,42 @@ GPUParticlesAttractorSphere3D::~GPUParticlesAttractorSphere3D() {
///////////////////////////
void GPUParticlesAttractorBox3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesAttractorBox3D::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesAttractorBox3D::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesAttractorBox3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesAttractorBox3D::get_size);
+
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
+}
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
+#ifndef DISABLE_DEPRECATED
+bool GPUParticlesAttractorBox3D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
}
-void GPUParticlesAttractorBox3D::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
- RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+bool GPUParticlesAttractorBox3D::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
+void GPUParticlesAttractorBox3D::set_size(const Vector3 &p_size) {
+ size = p_size;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
update_gizmos();
}
-Vector3 GPUParticlesAttractorBox3D::get_extents() const {
- return extents;
+Vector3 GPUParticlesAttractorBox3D::get_size() const {
+ return size;
}
AABB GPUParticlesAttractorBox3D::get_aabb() const {
- return AABB(-extents, extents * 2);
+ return AABB(-size / 2, size);
}
GPUParticlesAttractorBox3D::GPUParticlesAttractorBox3D() :
@@ -887,24 +959,42 @@ GPUParticlesAttractorBox3D::~GPUParticlesAttractorBox3D() {
///////////////////////////
void GPUParticlesAttractorVectorField3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesAttractorVectorField3D::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesAttractorVectorField3D::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &GPUParticlesAttractorVectorField3D::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &GPUParticlesAttractorVectorField3D::get_size);
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &GPUParticlesAttractorVectorField3D::set_texture);
ClassDB::bind_method(D_METHOD("get_texture"), &GPUParticlesAttractorVectorField3D::get_texture);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
}
-void GPUParticlesAttractorVectorField3D::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
- RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
+#ifndef DISABLE_DEPRECATED
+bool GPUParticlesAttractorVectorField3D::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool GPUParticlesAttractorVectorField3D::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
+void GPUParticlesAttractorVectorField3D::set_size(const Vector3 &p_size) {
+ size = p_size;
+ RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), size / 2);
update_gizmos();
}
-Vector3 GPUParticlesAttractorVectorField3D::get_extents() const {
- return extents;
+Vector3 GPUParticlesAttractorVectorField3D::get_size() const {
+ return size;
}
void GPUParticlesAttractorVectorField3D::set_texture(const Ref<Texture3D> &p_texture) {
@@ -918,7 +1008,7 @@ Ref<Texture3D> GPUParticlesAttractorVectorField3D::get_texture() const {
}
AABB GPUParticlesAttractorVectorField3D::get_aabb() const {
- return AABB(-extents, extents * 2);
+ return AABB(-size / 2, size);
}
GPUParticlesAttractorVectorField3D::GPUParticlesAttractorVectorField3D() :
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index 3c569ac73d..1649320069 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -74,14 +74,18 @@ public:
class GPUParticlesCollisionBox3D : public GPUParticlesCollision3D {
GDCLASS(GPUParticlesCollisionBox3D, GPUParticlesCollision3D);
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 size = Vector3(2, 2, 2);
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
virtual AABB get_aabb() const override;
@@ -108,7 +112,7 @@ public:
typedef void (*BakeEndFunc)();
private:
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 size = Vector3(2, 2, 2);
Resolution resolution = RESOLUTION_64;
uint32_t bake_mask = 0xFFFFFFFF;
Ref<Texture3D> texture;
@@ -160,6 +164,10 @@ private:
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
virtual PackedStringArray get_configuration_warnings() const override;
@@ -167,8 +175,8 @@ public:
void set_thickness(float p_thickness);
float get_thickness() const;
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_resolution(Resolution p_resolution);
Resolution get_resolution() const;
@@ -217,7 +225,7 @@ public:
};
private:
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 size = Vector3(2, 2, 2);
Resolution resolution = RESOLUTION_1024;
bool follow_camera_mode = false;
@@ -226,10 +234,14 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_resolution(Resolution p_resolution);
Resolution get_resolution() const;
@@ -301,14 +313,18 @@ public:
class GPUParticlesAttractorBox3D : public GPUParticlesAttractor3D {
GDCLASS(GPUParticlesAttractorBox3D, GPUParticlesAttractor3D);
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 size = Vector3(2, 2, 2);
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
virtual AABB get_aabb() const override;
@@ -319,15 +335,19 @@ public:
class GPUParticlesAttractorVectorField3D : public GPUParticlesAttractor3D {
GDCLASS(GPUParticlesAttractorVectorField3D, GPUParticlesAttractor3D);
- Vector3 extents = Vector3(1, 1, 1);
+ Vector3 size = Vector3(2, 2, 2);
Ref<Texture3D> texture;
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_texture(const Ref<Texture3D> &p_texture);
Ref<Texture3D> get_texture() const;
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index d0f71768d2..b39ca43d2e 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -109,6 +109,15 @@ void Label3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_alpha_scissor_threshold", "threshold"), &Label3D::set_alpha_scissor_threshold);
ClassDB::bind_method(D_METHOD("get_alpha_scissor_threshold"), &Label3D::get_alpha_scissor_threshold);
+ ClassDB::bind_method(D_METHOD("set_alpha_hash_scale", "threshold"), &Label3D::set_alpha_hash_scale);
+ ClassDB::bind_method(D_METHOD("get_alpha_hash_scale"), &Label3D::get_alpha_hash_scale);
+
+ ClassDB::bind_method(D_METHOD("set_alpha_antialiasing", "alpha_aa"), &Label3D::set_alpha_antialiasing);
+ ClassDB::bind_method(D_METHOD("get_alpha_antialiasing"), &Label3D::get_alpha_antialiasing);
+
+ ClassDB::bind_method(D_METHOD("set_alpha_antialiasing_edge", "edge"), &Label3D::set_alpha_antialiasing_edge);
+ ClassDB::bind_method(D_METHOD("get_alpha_antialiasing_edge"), &Label3D::get_alpha_antialiasing_edge);
+
ClassDB::bind_method(D_METHOD("set_texture_filter", "mode"), &Label3D::set_texture_filter);
ClassDB::bind_method(D_METHOD("get_texture_filter"), &Label3D::get_texture_filter);
@@ -127,8 +136,11 @@ void Label3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "double_sided"), "set_draw_flag", "get_draw_flag", FLAG_DOUBLE_SIDED);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_draw_flag", "get_draw_flag", FLAG_DISABLE_DEPTH_TEST);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_draw_flag", "get_draw_flag", FLAG_FIXED_SIZE);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass,Alpha Hash"), "set_alpha_cut_mode", "get_alpha_cut_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority");
ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_outline_render_priority", "get_outline_render_priority");
@@ -162,6 +174,7 @@ void Label3D::_bind_methods() {
BIND_ENUM_CONSTANT(ALPHA_CUT_DISABLED);
BIND_ENUM_CONSTANT(ALPHA_CUT_DISCARD);
BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
+ BIND_ENUM_CONSTANT(ALPHA_CUT_HASH);
}
void Label3D::_validate_property(PropertyInfo &p_property) const {
@@ -350,13 +363,24 @@ void Label3D::_generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset,
RS::get_singleton()->material_set_param(surf.material, "uv2_offset", Vector3(0, 0, 0));
RS::get_singleton()->material_set_param(surf.material, "uv2_scale", Vector3(1, 1, 1));
RS::get_singleton()->material_set_param(surf.material, "alpha_scissor_threshold", alpha_scissor_threshold);
+ RS::get_singleton()->material_set_param(surf.material, "alpha_hash_scale", alpha_hash_scale);
+ RS::get_singleton()->material_set_param(surf.material, "alpha_antialiasing_edge", alpha_antialiasing_edge);
if (msdf) {
RS::get_singleton()->material_set_param(surf.material, "msdf_pixel_range", TS->font_get_msdf_pixel_range(p_glyph.font_rid));
RS::get_singleton()->material_set_param(surf.material, "msdf_outline_size", p_outline_size);
}
+ BaseMaterial3D::Transparency mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA;
+ if (get_alpha_cut_mode() == ALPHA_CUT_DISCARD) {
+ mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_SCISSOR;
+ } else if (get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS) {
+ mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS;
+ } else if (get_alpha_cut_mode() == ALPHA_CUT_HASH) {
+ mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_HASH;
+ }
+
RID shader_rid;
- StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), true, get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, msdf, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), texture_filter, &shader_rid);
+ StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), mat_transparency, get_draw_flag(FLAG_DOUBLE_SIDED), get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, msdf, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), texture_filter, alpha_antialiasing_mode, &shader_rid);
RS::get_singleton()->material_set_shader(surf.material, shader_rid);
RS::get_singleton()->material_set_param(surf.material, "texture_albedo", tex);
@@ -906,7 +930,7 @@ StandardMaterial3D::BillboardMode Label3D::get_billboard_mode() const {
}
void Label3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
- ERR_FAIL_INDEX(p_mode, 3);
+ ERR_FAIL_INDEX(p_mode, ALPHA_CUT_MAX);
if (alpha_cut != p_mode) {
alpha_cut = p_mode;
_queue_update();
@@ -929,6 +953,17 @@ Label3D::AlphaCutMode Label3D::get_alpha_cut_mode() const {
return alpha_cut;
}
+void Label3D::set_alpha_hash_scale(float p_hash_scale) {
+ if (alpha_hash_scale != p_hash_scale) {
+ alpha_hash_scale = p_hash_scale;
+ _queue_update();
+ }
+}
+
+float Label3D::get_alpha_hash_scale() const {
+ return alpha_hash_scale;
+}
+
void Label3D::set_alpha_scissor_threshold(float p_threshold) {
if (alpha_scissor_threshold != p_threshold) {
alpha_scissor_threshold = p_threshold;
@@ -940,6 +975,28 @@ float Label3D::get_alpha_scissor_threshold() const {
return alpha_scissor_threshold;
}
+void Label3D::set_alpha_antialiasing(BaseMaterial3D::AlphaAntiAliasing p_alpha_aa) {
+ if (alpha_antialiasing_mode != p_alpha_aa) {
+ alpha_antialiasing_mode = p_alpha_aa;
+ _queue_update();
+ }
+}
+
+BaseMaterial3D::AlphaAntiAliasing Label3D::get_alpha_antialiasing() const {
+ return alpha_antialiasing_mode;
+}
+
+void Label3D::set_alpha_antialiasing_edge(float p_edge) {
+ if (alpha_antialiasing_edge != p_edge) {
+ alpha_antialiasing_edge = p_edge;
+ _queue_update();
+ }
+}
+
+float Label3D::get_alpha_antialiasing_edge() const {
+ return alpha_antialiasing_edge;
+}
+
Label3D::Label3D() {
for (int i = 0; i < FLAG_MAX; i++) {
flags[i] = (i == FLAG_DOUBLE_SIDED);
diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h
index 96cc941209..912f485354 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -51,7 +51,9 @@ public:
enum AlphaCutMode {
ALPHA_CUT_DISABLED,
ALPHA_CUT_DISCARD,
- ALPHA_CUT_OPAQUE_PREPASS
+ ALPHA_CUT_OPAQUE_PREPASS,
+ ALPHA_CUT_HASH,
+ ALPHA_CUT_MAX
};
private:
@@ -59,6 +61,9 @@ private:
bool flags[FLAG_MAX] = {};
AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED;
float alpha_scissor_threshold = 0.5;
+ float alpha_hash_scale = 1.0;
+ StandardMaterial3D::AlphaAntiAliasing alpha_antialiasing_mode = StandardMaterial3D::ALPHA_ANTIALIASING_OFF;
+ float alpha_antialiasing_edge = 0.0f;
AABB aabb;
@@ -228,6 +233,15 @@ public:
void set_alpha_scissor_threshold(float p_threshold);
float get_alpha_scissor_threshold() const;
+ void set_alpha_hash_scale(float p_hash_scale);
+ float get_alpha_hash_scale() const;
+
+ void set_alpha_antialiasing(BaseMaterial3D::AlphaAntiAliasing p_alpha_aa);
+ BaseMaterial3D::AlphaAntiAliasing get_alpha_antialiasing() const;
+
+ void set_alpha_antialiasing_edge(float p_edge);
+ float get_alpha_antialiasing_edge() const;
+
void set_billboard_mode(StandardMaterial3D::BillboardMode p_mode);
StandardMaterial3D::BillboardMode get_billboard_mode() const;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index fe7ddcb06e..524304425c 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -120,15 +120,38 @@ void NavigationAgent3D::_bind_methods() {
ADD_SIGNAL(MethodInfo("link_reached", PropertyInfo(Variant::DICTIONARY, "details")));
ADD_SIGNAL(MethodInfo("navigation_finished"));
ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity")));
+
+#ifdef DEBUG_ENABLED
+ ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationAgent3D::set_debug_enabled);
+ ClassDB::bind_method(D_METHOD("get_debug_enabled"), &NavigationAgent3D::get_debug_enabled);
+ ClassDB::bind_method(D_METHOD("set_debug_use_custom", "enabled"), &NavigationAgent3D::set_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("get_debug_use_custom"), &NavigationAgent3D::get_debug_use_custom);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_color", "color"), &NavigationAgent3D::set_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_color"), &NavigationAgent3D::get_debug_path_custom_color);
+ ClassDB::bind_method(D_METHOD("set_debug_path_custom_point_size", "point_size"), &NavigationAgent3D::set_debug_path_custom_point_size);
+ ClassDB::bind_method(D_METHOD("get_debug_path_custom_point_size"), &NavigationAgent3D::get_debug_path_custom_point_size);
+
+ ADD_GROUP("Debug", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_enabled"), "set_debug_enabled", "get_debug_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_custom"), "set_debug_use_custom", "get_debug_use_custom");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_path_custom_color"), "set_debug_path_custom_color", "get_debug_path_custom_color");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_point_size", PROPERTY_HINT_RANGE, "1,50,1,suffix:px"), "set_debug_path_custom_point_size", "get_debug_path_custom_point_size");
+#endif // DEBUG_ENABLED
}
void NavigationAgent3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POST_ENTER_TREE: {
// need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready.
- // cannot use READY as ready does not get called if Node is readded to SceneTree
+ // cannot use READY as ready does not get called if Node is re-added to SceneTree
set_agent_parent(get_parent());
set_physics_process_internal(true);
+
+#ifdef DEBUG_ENABLED
+ if (NavigationServer3D::get_singleton()->get_debug_enabled()) {
+ debug_path_dirty = true;
+ }
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_PARENTED: {
@@ -151,6 +174,12 @@ void NavigationAgent3D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
set_agent_parent(nullptr);
set_physics_process_internal(false);
+
+#ifdef DEBUG_ENABLED
+ if (debug_path_instance.is_valid()) {
+ RS::get_singleton()->instance_set_visible(debug_path_instance, false);
+ }
+#endif // DEBUG_ENABLED
} break;
case NOTIFICATION_PAUSED: {
@@ -178,22 +207,27 @@ void NavigationAgent3D::_notification(int p_what) {
if (avoidance_enabled) {
// agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
// no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
- NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
+ NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
}
_check_distance_to_target();
}
+#ifdef DEBUG_ENABLED
+ if (debug_path_dirty) {
+ _update_debug_path();
+ }
+#endif // DEBUG_ENABLED
} break;
}
}
NavigationAgent3D::NavigationAgent3D() {
agent = NavigationServer3D::get_singleton()->agent_create();
- set_neighbor_distance(50.0);
- set_max_neighbors(10);
- set_time_horizon(5.0);
- set_radius(1.0);
- set_max_speed(10.0);
- set_ignore_y(true);
+ NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
+ NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
+ NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
+ NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
+ NavigationServer3D::get_singleton()->agent_set_max_speed(agent, max_speed);
+ NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, ignore_y);
// Preallocate query and result objects to improve performance.
navigation_query = Ref<NavigationPathQueryParameters3D>();
@@ -201,20 +235,41 @@ NavigationAgent3D::NavigationAgent3D() {
navigation_result = Ref<NavigationPathQueryResult3D>();
navigation_result.instantiate();
+
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent3D::_navigation_debug_changed));
+#endif // DEBUG_ENABLED
}
NavigationAgent3D::~NavigationAgent3D() {
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
NavigationServer3D::get_singleton()->free(agent);
agent = RID(); // Pointless
+
+#ifdef DEBUG_ENABLED
+ NavigationServer3D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent3D::_navigation_debug_changed));
+
+ ERR_FAIL_NULL(RenderingServer::get_singleton());
+ if (debug_path_instance.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_path_instance);
+ }
+ if (debug_path_mesh.is_valid()) {
+ RenderingServer::get_singleton()->free(debug_path_mesh->get_rid());
+ }
+#endif // DEBUG_ENABLED
}
void NavigationAgent3D::set_avoidance_enabled(bool p_enabled) {
+ if (avoidance_enabled == p_enabled) {
+ return;
+ }
+
avoidance_enabled = p_enabled;
+
if (avoidance_enabled) {
- NavigationServer3D::get_singleton()->agent_set_callback(agent, get_instance_id(), "_avoidance_done");
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent3D::_avoidance_done));
} else {
- NavigationServer3D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, Callable());
}
}
@@ -223,8 +278,13 @@ bool NavigationAgent3D::get_avoidance_enabled() const {
}
void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
+ if (agent_parent == p_agent_parent) {
+ return;
+ }
+
// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
- NavigationServer3D::get_singleton()->agent_set_callback(agent, ObjectID(), "_avoidance_done");
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, Callable());
+
if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) {
// place agent on navigation map first or else the RVO agent callback creation fails silently later
agent_parent = Object::cast_to<Node3D>(p_agent_parent);
@@ -233,8 +293,11 @@ void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
} else {
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
}
+
// create new avoidance callback if enabled
- set_avoidance_enabled(avoidance_enabled);
+ if (avoidance_enabled) {
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, callable_mp(this, &NavigationAgent3D::_avoidance_done));
+ }
} else {
agent_parent = nullptr;
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
@@ -242,11 +305,13 @@ void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
}
void NavigationAgent3D::set_navigation_layers(uint32_t p_navigation_layers) {
- bool navigation_layers_changed = navigation_layers != p_navigation_layers;
- navigation_layers = p_navigation_layers;
- if (navigation_layers_changed) {
- _request_repath();
+ if (navigation_layers == p_navigation_layers) {
+ return;
}
+
+ navigation_layers = p_navigation_layers;
+
+ _request_repath();
}
uint32_t NavigationAgent3D::get_navigation_layers() const {
@@ -280,7 +345,12 @@ void NavigationAgent3D::set_path_metadata_flags(BitField<NavigationPathQueryPara
}
void NavigationAgent3D::set_navigation_map(RID p_navigation_map) {
+ if (map_override == p_navigation_map) {
+ return;
+ }
+
map_override = p_navigation_map;
+
NavigationServer3D::get_singleton()->agent_set_map(agent, map_override);
_request_repath();
}
@@ -294,50 +364,96 @@ RID NavigationAgent3D::get_navigation_map() const {
return RID();
}
-void NavigationAgent3D::set_path_desired_distance(real_t p_dd) {
- path_desired_distance = p_dd;
+void NavigationAgent3D::set_path_desired_distance(real_t p_path_desired_distance) {
+ if (Math::is_equal_approx(path_desired_distance, p_path_desired_distance)) {
+ return;
+ }
+
+ path_desired_distance = p_path_desired_distance;
}
-void NavigationAgent3D::set_target_desired_distance(real_t p_dd) {
- target_desired_distance = p_dd;
+void NavigationAgent3D::set_target_desired_distance(real_t p_target_desired_distance) {
+ if (Math::is_equal_approx(target_desired_distance, p_target_desired_distance)) {
+ return;
+ }
+
+ target_desired_distance = p_target_desired_distance;
}
void NavigationAgent3D::set_radius(real_t p_radius) {
+ if (Math::is_equal_approx(radius, p_radius)) {
+ return;
+ }
+
radius = p_radius;
+
NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
}
-void NavigationAgent3D::set_agent_height_offset(real_t p_hh) {
- navigation_height_offset = p_hh;
+void NavigationAgent3D::set_agent_height_offset(real_t p_agent_height_offset) {
+ if (Math::is_equal_approx(navigation_height_offset, p_agent_height_offset)) {
+ return;
+ }
+
+ navigation_height_offset = p_agent_height_offset;
}
void NavigationAgent3D::set_ignore_y(bool p_ignore_y) {
+ if (ignore_y == p_ignore_y) {
+ return;
+ }
+
ignore_y = p_ignore_y;
+
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, ignore_y);
}
void NavigationAgent3D::set_neighbor_distance(real_t p_distance) {
+ if (Math::is_equal_approx(neighbor_distance, p_distance)) {
+ return;
+ }
+
neighbor_distance = p_distance;
+
NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
}
void NavigationAgent3D::set_max_neighbors(int p_count) {
+ if (max_neighbors == p_count) {
+ return;
+ }
+
max_neighbors = p_count;
+
NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
}
void NavigationAgent3D::set_time_horizon(real_t p_time) {
+ if (Math::is_equal_approx(time_horizon, p_time)) {
+ return;
+ }
+
time_horizon = p_time;
+
NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, time_horizon);
}
void NavigationAgent3D::set_max_speed(real_t p_max_speed) {
+ if (Math::is_equal_approx(max_speed, p_max_speed)) {
+ return;
+ }
+
max_speed = p_max_speed;
+
NavigationServer3D::get_singleton()->agent_set_max_speed(agent, max_speed);
}
-void NavigationAgent3D::set_path_max_distance(real_t p_pmd) {
- path_max_distance = p_pmd;
+void NavigationAgent3D::set_path_max_distance(real_t p_path_max_distance) {
+ if (Math::is_equal_approx(path_max_distance, p_path_max_distance)) {
+ return;
+ }
+
+ path_max_distance = p_path_max_distance;
}
real_t NavigationAgent3D::get_path_max_distance() {
@@ -345,8 +461,13 @@ real_t NavigationAgent3D::get_path_max_distance() {
}
void NavigationAgent3D::set_target_position(Vector3 p_position) {
+ if (target_position.is_equal_approx(p_position)) {
+ return;
+ }
+
target_position = p_position;
target_position_submitted = true;
+
_request_repath();
}
@@ -360,7 +481,7 @@ Vector3 NavigationAgent3D::get_next_path_position() {
const Vector<Vector3> &navigation_path = navigation_result->get_path();
if (navigation_path.size() == 0) {
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector3(), "The agent has no parent.");
- return agent_parent->get_global_transform().origin;
+ return agent_parent->get_global_position();
} else {
return navigation_path[navigation_path_index] - Vector3(0, navigation_height_offset, 0);
}
@@ -368,7 +489,7 @@ Vector3 NavigationAgent3D::get_next_path_position() {
real_t NavigationAgent3D::distance_to_target() const {
ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent.");
- return agent_parent->get_global_transform().origin.distance_to(target_position);
+ return agent_parent->get_global_position().distance_to(target_position);
}
bool NavigationAgent3D::is_target_reached() const {
@@ -395,10 +516,15 @@ Vector3 NavigationAgent3D::get_final_position() {
}
void NavigationAgent3D::set_velocity(Vector3 p_velocity) {
+ if (target_velocity.is_equal_approx(p_velocity)) {
+ return;
+ }
+
target_velocity = p_velocity;
+ velocity_submitted = true;
+
NavigationServer3D::get_singleton()->agent_set_target_velocity(agent, target_velocity);
NavigationServer3D::get_singleton()->agent_set_velocity(agent, prev_safe_velocity);
- velocity_submitted = true;
}
void NavigationAgent3D::_avoidance_done(Vector3 p_new_velocity) {
@@ -439,7 +565,7 @@ void NavigationAgent3D::update_navigation() {
update_frame_id = Engine::get_singleton()->get_physics_frames();
- Vector3 origin = agent_parent->get_global_transform().origin;
+ Vector3 origin = agent_parent->get_global_position();
bool reload_path = false;
@@ -478,6 +604,9 @@ void NavigationAgent3D::update_navigation() {
}
NavigationServer3D::get_singleton()->query_path(navigation_query, navigation_result);
+#ifdef DEBUG_ENABLED
+ debug_path_dirty = true;
+#endif // DEBUG_ENABLED
navigation_finished = false;
navigation_path_index = 0;
emit_signal(SNAME("path_changed"));
@@ -564,3 +693,146 @@ void NavigationAgent3D::_check_distance_to_target() {
}
}
}
+
+////////DEBUG////////////////////////////////////////////////////////////
+
+#ifdef DEBUG_ENABLED
+void NavigationAgent3D::set_debug_enabled(bool p_enabled) {
+ if (debug_enabled == p_enabled) {
+ return;
+ }
+
+ debug_enabled = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent3D::get_debug_enabled() const {
+ return debug_enabled;
+}
+
+void NavigationAgent3D::set_debug_use_custom(bool p_enabled) {
+ if (debug_use_custom == p_enabled) {
+ return;
+ }
+
+ debug_use_custom = p_enabled;
+ debug_path_dirty = true;
+}
+
+bool NavigationAgent3D::get_debug_use_custom() const {
+ return debug_use_custom;
+}
+
+void NavigationAgent3D::set_debug_path_custom_color(Color p_color) {
+ if (debug_path_custom_color == p_color) {
+ return;
+ }
+
+ debug_path_custom_color = p_color;
+ debug_path_dirty = true;
+}
+
+Color NavigationAgent3D::get_debug_path_custom_color() const {
+ return debug_path_custom_color;
+}
+
+void NavigationAgent3D::set_debug_path_custom_point_size(float p_point_size) {
+ if (Math::is_equal_approx(debug_path_custom_point_size, p_point_size)) {
+ return;
+ }
+
+ debug_path_custom_point_size = p_point_size;
+ debug_path_dirty = true;
+}
+
+float NavigationAgent3D::get_debug_path_custom_point_size() const {
+ return debug_path_custom_point_size;
+}
+
+void NavigationAgent3D::_navigation_debug_changed() {
+ debug_path_dirty = true;
+}
+
+void NavigationAgent3D::_update_debug_path() {
+ if (!debug_path_dirty) {
+ return;
+ }
+ debug_path_dirty = false;
+
+ if (!debug_path_instance.is_valid()) {
+ debug_path_instance = RenderingServer::get_singleton()->instance_create();
+ }
+
+ if (!debug_path_mesh.is_valid()) {
+ debug_path_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ debug_path_mesh->clear_surfaces();
+
+ if (!(debug_enabled && NavigationServer3D::get_singleton()->get_debug_navigation_enable_agent_paths())) {
+ return;
+ }
+
+ if (!(agent_parent && agent_parent->is_inside_tree())) {
+ return;
+ }
+
+ const Vector<Vector3> &navigation_path = navigation_result->get_path();
+
+ if (navigation_path.size() <= 1) {
+ return;
+ }
+
+ Vector<Vector3> debug_path_lines_vertex_array;
+
+ for (int i = 0; i < navigation_path.size() - 1; i++) {
+ debug_path_lines_vertex_array.push_back(navigation_path[i]);
+ debug_path_lines_vertex_array.push_back(navigation_path[i + 1]);
+ }
+
+ Array debug_path_lines_mesh_array;
+ debug_path_lines_mesh_array.resize(Mesh::ARRAY_MAX);
+ debug_path_lines_mesh_array[Mesh::ARRAY_VERTEX] = debug_path_lines_vertex_array;
+
+ debug_path_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, debug_path_lines_mesh_array);
+
+ Ref<StandardMaterial3D> debug_agent_path_line_material = NavigationServer3D::get_singleton()->get_debug_navigation_agent_path_line_material();
+ if (debug_use_custom) {
+ if (!debug_agent_path_line_custom_material.is_valid()) {
+ debug_agent_path_line_custom_material = debug_agent_path_line_material->duplicate();
+ }
+ debug_agent_path_line_custom_material->set_albedo(debug_path_custom_color);
+ debug_path_mesh->surface_set_material(0, debug_agent_path_line_custom_material);
+ } else {
+ debug_path_mesh->surface_set_material(0, debug_agent_path_line_material);
+ }
+
+ Vector<Vector3> debug_path_points_vertex_array;
+
+ for (int i = 0; i < navigation_path.size(); i++) {
+ debug_path_points_vertex_array.push_back(navigation_path[i]);
+ }
+
+ Array debug_path_points_mesh_array;
+ debug_path_points_mesh_array.resize(Mesh::ARRAY_MAX);
+ debug_path_points_mesh_array[Mesh::ARRAY_VERTEX] = debug_path_lines_vertex_array;
+
+ debug_path_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, debug_path_points_mesh_array);
+
+ Ref<StandardMaterial3D> debug_agent_path_point_material = NavigationServer3D::get_singleton()->get_debug_navigation_agent_path_point_material();
+ if (debug_use_custom) {
+ if (!debug_agent_path_point_custom_material.is_valid()) {
+ debug_agent_path_point_custom_material = debug_agent_path_point_material->duplicate();
+ }
+ debug_agent_path_point_custom_material->set_albedo(debug_path_custom_color);
+ debug_agent_path_point_custom_material->set_point_size(debug_path_custom_point_size);
+ debug_path_mesh->surface_set_material(1, debug_agent_path_point_custom_material);
+ } else {
+ debug_path_mesh->surface_set_material(1, debug_agent_path_point_material);
+ }
+
+ RS::get_singleton()->instance_set_base(debug_path_instance, debug_path_mesh->get_rid());
+ RS::get_singleton()->instance_set_scenario(debug_path_instance, agent_parent->get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_visible(debug_path_instance, agent_parent->is_visible_in_tree());
+}
+#endif // DEBUG_ENABLED
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 12f83ce6a8..209b2a0989 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -52,14 +52,13 @@ class NavigationAgent3D : public Node {
real_t path_desired_distance = 1.0;
real_t target_desired_distance = 1.0;
- real_t radius = 0.0;
+ real_t radius = 1.0;
real_t navigation_height_offset = 0.0;
- bool ignore_y = false;
- real_t neighbor_distance = 0.0;
- int max_neighbors = 0;
- real_t time_horizon = 0.0;
- real_t max_speed = 0.0;
-
+ bool ignore_y = true;
+ real_t neighbor_distance = 50.0;
+ int max_neighbors = 10;
+ real_t time_horizon = 5.0;
+ real_t max_speed = 10.0;
real_t path_max_distance = 3.0;
Vector3 target_position;
@@ -76,6 +75,22 @@ class NavigationAgent3D : public Node {
// No initialized on purpose
uint32_t update_frame_id = 0;
+#ifdef DEBUG_ENABLED
+ bool debug_enabled = false;
+ bool debug_path_dirty = true;
+ RID debug_path_instance;
+ Ref<ArrayMesh> debug_path_mesh;
+ float debug_path_custom_point_size = 4.0;
+ bool debug_use_custom = false;
+ Color debug_path_custom_color = Color(1.0, 1.0, 1.0, 1.0);
+ Ref<StandardMaterial3D> debug_agent_path_line_custom_material;
+ Ref<StandardMaterial3D> debug_agent_path_point_custom_material;
+
+private:
+ void _navigation_debug_changed();
+ void _update_debug_path();
+#endif // DEBUG_ENABLED
+
protected:
static void _bind_methods();
void _notification(int p_what);
@@ -181,6 +196,20 @@ public:
PackedStringArray get_configuration_warnings() const override;
+#ifdef DEBUG_ENABLED
+ void set_debug_enabled(bool p_enabled);
+ bool get_debug_enabled() const;
+
+ void set_debug_use_custom(bool p_enabled);
+ bool get_debug_use_custom() const;
+
+ void set_debug_path_custom_color(Color p_color);
+ Color get_debug_path_custom_color() const;
+
+ void set_debug_path_custom_point_size(float p_point_size);
+ float get_debug_path_custom_point_size() const;
+#endif // DEBUG_ENABLED
+
private:
void update_navigation();
void _request_repath();
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index c706f55566..85b3c164cc 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -192,6 +192,10 @@ real_t NavigationObstacle3D::estimate_agent_radius() const {
}
void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) {
+ if (parent_node3d == p_agent_parent) {
+ return;
+ }
+
if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) {
parent_node3d = Object::cast_to<Node3D>(p_agent_parent);
if (map_override.is_valid()) {
@@ -207,7 +211,12 @@ void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) {
}
void NavigationObstacle3D::set_navigation_map(RID p_navigation_map) {
+ if (map_override == p_navigation_map) {
+ return;
+ }
+
map_override = p_navigation_map;
+
NavigationServer3D::get_singleton()->agent_set_map(agent, map_override);
}
@@ -221,13 +230,23 @@ RID NavigationObstacle3D::get_navigation_map() const {
}
void NavigationObstacle3D::set_estimate_radius(bool p_estimate_radius) {
+ if (estimate_radius == p_estimate_radius) {
+ return;
+ }
+
estimate_radius = p_estimate_radius;
+
notify_property_list_changed();
reevaluate_agent_radius();
}
void NavigationObstacle3D::set_radius(real_t p_radius) {
ERR_FAIL_COND_MSG(p_radius <= 0.0, "Radius must be greater than 0.");
+ if (Math::is_equal_approx(radius, p_radius)) {
+ return;
+ }
+
radius = p_radius;
+
reevaluate_agent_radius();
}
diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp
index 632b27953f..594580a205 100644
--- a/scene/3d/occluder_instance_3d.cpp
+++ b/scene/3d/occluder_instance_3d.cpp
@@ -542,13 +542,14 @@ void OccluderInstance3D::_bake_surface(const Transform3D &p_transform, Array p_s
float error = -1.0f;
int target_index_count = MIN(indices.size(), 36);
+ const int simplify_options = SurfaceTool::SIMPLIFY_LOCK_BORDER;
+
uint32_t index_count = SurfaceTool::simplify_func(
(unsigned int *)indices.ptrw(),
(unsigned int *)indices.ptr(),
indices.size(),
vertices_f32.ptr(), vertices.size(), sizeof(float) * 3,
- target_index_count, target_error, &error);
-
+ target_index_count, target_error, simplify_options, &error);
indices.resize(index_count);
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index f4ab09cd9b..c8cfcf7d7a 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -333,6 +333,11 @@ void AnimatableBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
}
void AnimatableBody3D::_notification(int p_what) {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ return;
+ }
+#endif
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
last_valid_transform = get_global_transform();
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 606f6140cb..62202c0b1b 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -85,38 +85,40 @@ float ReflectionProbe::get_mesh_lod_threshold() const {
return mesh_lod_threshold;
}
-void ReflectionProbe::set_extents(const Vector3 &p_extents) {
- extents = p_extents;
+void ReflectionProbe::set_size(const Vector3 &p_size) {
+ size = p_size;
for (int i = 0; i < 3; i++) {
- if (extents[i] < 0.01) {
- extents[i] = 0.01;
+ float half_size = size[i] / 2;
+ if (half_size < 0.01) {
+ half_size = 0.01;
}
- if (extents[i] - 0.01 < ABS(origin_offset[i])) {
- origin_offset[i] = SIGN(origin_offset[i]) * (extents[i] - 0.01);
+ if (half_size - 0.01 < ABS(origin_offset[i])) {
+ origin_offset[i] = SIGN(origin_offset[i]) * (half_size - 0.01);
}
}
- RS::get_singleton()->reflection_probe_set_extents(probe, extents);
+ RS::get_singleton()->reflection_probe_set_size(probe, size);
RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset);
update_gizmos();
}
-Vector3 ReflectionProbe::get_extents() const {
- return extents;
+Vector3 ReflectionProbe::get_size() const {
+ return size;
}
-void ReflectionProbe::set_origin_offset(const Vector3 &p_extents) {
- origin_offset = p_extents;
+void ReflectionProbe::set_origin_offset(const Vector3 &p_offset) {
+ origin_offset = p_offset;
for (int i = 0; i < 3; i++) {
- if (extents[i] - 0.01 < ABS(origin_offset[i])) {
- origin_offset[i] = SIGN(origin_offset[i]) * (extents[i] - 0.01);
+ float half_size = size[i] / 2;
+ if (half_size - 0.01 < ABS(origin_offset[i])) {
+ origin_offset[i] = SIGN(origin_offset[i]) * (half_size - 0.01);
}
}
- RS::get_singleton()->reflection_probe_set_extents(probe, extents);
+ RS::get_singleton()->reflection_probe_set_size(probe, size);
RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset);
update_gizmos();
@@ -174,7 +176,7 @@ ReflectionProbe::UpdateMode ReflectionProbe::get_update_mode() const {
AABB ReflectionProbe::get_aabb() const {
AABB aabb;
aabb.position = -origin_offset;
- aabb.size = origin_offset + extents;
+ aabb.size = origin_offset + size / 2;
return aabb;
}
@@ -205,8 +207,8 @@ void ReflectionProbe::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mesh_lod_threshold", "ratio"), &ReflectionProbe::set_mesh_lod_threshold);
ClassDB::bind_method(D_METHOD("get_mesh_lod_threshold"), &ReflectionProbe::get_mesh_lod_threshold);
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &ReflectionProbe::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &ReflectionProbe::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &ReflectionProbe::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &ReflectionProbe::get_size);
ClassDB::bind_method(D_METHOD("set_origin_offset", "origin_offset"), &ReflectionProbe::set_origin_offset);
ClassDB::bind_method(D_METHOD("get_origin_offset"), &ReflectionProbe::get_origin_offset);
@@ -229,7 +231,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once (Fast),Always (Slow)"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384,0.1,or_greater,exp,suffix:m"), "set_max_distance", "get_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_NONE, "suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "origin_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_origin_offset", "get_origin_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_as_interior", "is_set_as_interior");
@@ -250,6 +252,24 @@ void ReflectionProbe::_bind_methods() {
BIND_ENUM_CONSTANT(AMBIENT_COLOR);
}
+#ifndef DISABLE_DEPRECATED
+bool ReflectionProbe::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool ReflectionProbe::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
ReflectionProbe::ReflectionProbe() {
probe = RenderingServer::get_singleton()->reflection_probe_create();
RS::get_singleton()->instance_set_base(get_instance(), probe);
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index cb417c3eea..738277ad39 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -52,7 +52,7 @@ private:
RID probe;
float intensity = 1.0;
float max_distance = 0.0;
- Vector3 extents = Vector3(10, 10, 10);
+ Vector3 size = Vector3(20, 20, 20);
Vector3 origin_offset = Vector3(0, 0, 0);
bool box_projection = false;
bool enable_shadows = false;
@@ -68,6 +68,10 @@ private:
protected:
static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
void set_intensity(float p_intensity);
@@ -91,10 +95,10 @@ public:
void set_mesh_lod_threshold(float p_pixels);
float get_mesh_lod_threshold() const;
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
- void set_origin_offset(const Vector3 &p_extents);
+ void set_origin_offset(const Vector3 &p_offset);
Vector3 get_origin_offset() const;
void set_as_interior(bool p_enable);
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 635c566ef8..59e4a0b718 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -245,8 +245,26 @@ void SpriteBase3D::draw_texture_rect(Ref<Texture2D> p_texture, Rect2 p_dst_rect,
RS::get_singleton()->mesh_set_custom_aabb(mesh_new, aabb_new);
set_aabb(aabb_new);
+ RS::get_singleton()->material_set_param(get_material(), "alpha_scissor_threshold", alpha_scissor_threshold);
+ RS::get_singleton()->material_set_param(get_material(), "alpha_hash_scale", alpha_hash_scale);
+ RS::get_singleton()->material_set_param(get_material(), "alpha_antialiasing_edge", alpha_antialiasing_edge);
+
+ BaseMaterial3D::Transparency mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_DISABLED;
+ if (get_draw_flag(FLAG_TRANSPARENT)) {
+ if (get_alpha_cut_mode() == ALPHA_CUT_DISCARD) {
+ mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_SCISSOR;
+ } else if (get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS) {
+ mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_DEPTH_PRE_PASS;
+ } else if (get_alpha_cut_mode() == ALPHA_CUT_HASH) {
+ mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA_HASH;
+ } else {
+ mat_transparency = BaseMaterial3D::Transparency::TRANSPARENCY_ALPHA;
+ }
+ }
+
RID shader_rid;
- StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), &shader_rid);
+ StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), mat_transparency, get_draw_flag(FLAG_DOUBLE_SIDED), get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, false, get_draw_flag(FLAG_DISABLE_DEPTH_TEST), get_draw_flag(FLAG_FIXED_SIZE), get_texture_filter(), alpha_antialiasing_mode, &shader_rid);
+
if (last_shader != shader_rid) {
RS::get_singleton()->material_set_shader(get_material(), shader_rid);
last_shader = shader_rid;
@@ -433,7 +451,7 @@ bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const {
}
void SpriteBase3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
- ERR_FAIL_INDEX(p_mode, 3);
+ ERR_FAIL_INDEX(p_mode, ALPHA_CUT_MAX);
alpha_cut = p_mode;
_queue_redraw();
}
@@ -442,6 +460,50 @@ SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
return alpha_cut;
}
+void SpriteBase3D::set_alpha_hash_scale(float p_hash_scale) {
+ if (alpha_hash_scale != p_hash_scale) {
+ alpha_hash_scale = p_hash_scale;
+ _queue_redraw();
+ }
+}
+
+float SpriteBase3D::get_alpha_hash_scale() const {
+ return alpha_hash_scale;
+}
+
+void SpriteBase3D::set_alpha_scissor_threshold(float p_threshold) {
+ if (alpha_scissor_threshold != p_threshold) {
+ alpha_scissor_threshold = p_threshold;
+ _queue_redraw();
+ }
+}
+
+float SpriteBase3D::get_alpha_scissor_threshold() const {
+ return alpha_scissor_threshold;
+}
+
+void SpriteBase3D::set_alpha_antialiasing(BaseMaterial3D::AlphaAntiAliasing p_alpha_aa) {
+ if (alpha_antialiasing_mode != p_alpha_aa) {
+ alpha_antialiasing_mode = p_alpha_aa;
+ _queue_redraw();
+ }
+}
+
+BaseMaterial3D::AlphaAntiAliasing SpriteBase3D::get_alpha_antialiasing() const {
+ return alpha_antialiasing_mode;
+}
+
+void SpriteBase3D::set_alpha_antialiasing_edge(float p_edge) {
+ if (alpha_antialiasing_edge != p_edge) {
+ alpha_antialiasing_edge = p_edge;
+ _queue_redraw();
+ }
+}
+
+float SpriteBase3D::get_alpha_antialiasing_edge() const {
+ return alpha_antialiasing_edge;
+}
+
void SpriteBase3D::set_billboard_mode(StandardMaterial3D::BillboardMode p_mode) {
ERR_FAIL_INDEX(p_mode, 3); // Cannot use BILLBOARD_PARTICLES.
billboard_mode = p_mode;
@@ -494,6 +556,18 @@ void SpriteBase3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_alpha_cut_mode", "mode"), &SpriteBase3D::set_alpha_cut_mode);
ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode);
+ ClassDB::bind_method(D_METHOD("set_alpha_scissor_threshold", "threshold"), &SpriteBase3D::set_alpha_scissor_threshold);
+ ClassDB::bind_method(D_METHOD("get_alpha_scissor_threshold"), &SpriteBase3D::get_alpha_scissor_threshold);
+
+ ClassDB::bind_method(D_METHOD("set_alpha_hash_scale", "threshold"), &SpriteBase3D::set_alpha_hash_scale);
+ ClassDB::bind_method(D_METHOD("get_alpha_hash_scale"), &SpriteBase3D::get_alpha_hash_scale);
+
+ ClassDB::bind_method(D_METHOD("set_alpha_antialiasing", "alpha_aa"), &SpriteBase3D::set_alpha_antialiasing);
+ ClassDB::bind_method(D_METHOD("get_alpha_antialiasing"), &SpriteBase3D::get_alpha_antialiasing);
+
+ ClassDB::bind_method(D_METHOD("set_alpha_antialiasing_edge", "edge"), &SpriteBase3D::set_alpha_antialiasing_edge);
+ ClassDB::bind_method(D_METHOD("get_alpha_antialiasing_edge"), &SpriteBase3D::get_alpha_antialiasing_edge);
+
ClassDB::bind_method(D_METHOD("set_billboard_mode", "mode"), &SpriteBase3D::set_billboard_mode);
ClassDB::bind_method(D_METHOD("get_billboard_mode"), &SpriteBase3D::get_billboard_mode);
@@ -519,7 +593,11 @@ void SpriteBase3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "double_sided"), "set_draw_flag", "get_draw_flag", FLAG_DOUBLE_SIDED);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_draw_flag", "get_draw_flag", FLAG_DISABLE_DEPTH_TEST);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_draw_flag", "get_draw_flag", FLAG_FIXED_SIZE);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass,Alpha Hash"), "set_alpha_cut_mode", "get_alpha_cut_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority");
@@ -533,6 +611,7 @@ void SpriteBase3D::_bind_methods() {
BIND_ENUM_CONSTANT(ALPHA_CUT_DISABLED);
BIND_ENUM_CONSTANT(ALPHA_CUT_DISCARD);
BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
+ BIND_ENUM_CONSTANT(ALPHA_CUT_HASH);
}
SpriteBase3D::SpriteBase3D() {
@@ -550,7 +629,6 @@ SpriteBase3D::SpriteBase3D() {
RS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1));
RS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0));
RS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1));
- RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.5);
mesh = RenderingServer::get_singleton()->mesh_create();
@@ -1182,8 +1260,9 @@ void AnimatedSprite3D::play(const StringName &p_name, float p_custom_scale, bool
}
}
- notify_property_list_changed();
set_process_internal(true);
+ notify_property_list_changed();
+ _queue_redraw();
}
void AnimatedSprite3D::play_backwards(const StringName &p_name) {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index d0fd767d89..1eb1211951 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -53,7 +53,9 @@ public:
enum AlphaCutMode {
ALPHA_CUT_DISABLED,
ALPHA_CUT_DISCARD,
- ALPHA_CUT_OPAQUE_PREPASS
+ ALPHA_CUT_OPAQUE_PREPASS,
+ ALPHA_CUT_HASH,
+ ALPHA_CUT_MAX
};
private:
@@ -85,6 +87,10 @@ private:
bool flags[FLAG_MAX] = {};
AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED;
+ float alpha_scissor_threshold = 0.5;
+ float alpha_hash_scale = 1.0;
+ StandardMaterial3D::AlphaAntiAliasing alpha_antialiasing_mode = StandardMaterial3D::ALPHA_ANTIALIASING_OFF;
+ float alpha_antialiasing_edge = 0.0f;
StandardMaterial3D::BillboardMode billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED;
StandardMaterial3D::TextureFilter texture_filter = StandardMaterial3D::TEXTURE_FILTER_LINEAR_WITH_MIPMAPS;
bool pending_update = false;
@@ -143,6 +149,18 @@ public:
void set_alpha_cut_mode(AlphaCutMode p_mode);
AlphaCutMode get_alpha_cut_mode() const;
+ void set_alpha_scissor_threshold(float p_threshold);
+ float get_alpha_scissor_threshold() const;
+
+ void set_alpha_hash_scale(float p_hash_scale);
+ float get_alpha_hash_scale() const;
+
+ void set_alpha_antialiasing(BaseMaterial3D::AlphaAntiAliasing p_alpha_aa);
+ BaseMaterial3D::AlphaAntiAliasing get_alpha_antialiasing() const;
+
+ void set_alpha_antialiasing_edge(float p_edge);
+ float get_alpha_antialiasing_edge() const;
+
void set_billboard_mode(StandardMaterial3D::BillboardMode p_mode);
StandardMaterial3D::BillboardMode get_billboard_mode() const;
diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp
index 41dc27352f..36a877246e 100644
--- a/scene/3d/voxel_gi.cpp
+++ b/scene/3d/voxel_gi.cpp
@@ -237,6 +237,24 @@ void VoxelGIData::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
}
+#ifndef DISABLE_DEPRECATED
+bool VoxelGI::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ set_size((Vector3)p_value * 2);
+ return true;
+ }
+ return false;
+}
+
+bool VoxelGI::_get(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "extents") { // Compatibility with Godot 3.x.
+ r_property = size / 2;
+ return true;
+ }
+ return false;
+}
+#endif // DISABLE_DEPRECATED
+
VoxelGIData::VoxelGIData() {
probe = RS::get_singleton()->voxel_gi_create();
}
@@ -273,14 +291,14 @@ VoxelGI::Subdiv VoxelGI::get_subdiv() const {
return subdiv;
}
-void VoxelGI::set_extents(const Vector3 &p_extents) {
- // Prevent very small extents as these break baking if other extents are set very high.
- extents = Vector3(MAX(1.0, p_extents.x), MAX(1.0, p_extents.y), MAX(1.0, p_extents.z));
+void VoxelGI::set_size(const Vector3 &p_size) {
+ // Prevent very small size dimensions as these breaks baking if other size dimensions are set very high.
+ size = Vector3(MAX(1.0, p_size.x), MAX(1.0, p_size.y), MAX(1.0, p_size.z));
update_gizmos();
}
-Vector3 VoxelGI::get_extents() const {
- return extents;
+Vector3 VoxelGI::get_size() const {
+ return size;
}
void VoxelGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) {
@@ -300,7 +318,7 @@ void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform();
- if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) {
+ if (AABB(-size / 2, size).intersects(xf.xform(aabb))) {
PlotMesh pm;
pm.local_xform = xf;
pm.mesh = mesh;
@@ -328,7 +346,7 @@ void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) {
Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf);
- if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) {
+ if (AABB(-size / 2, size).intersects(xf.xform(aabb))) {
PlotMesh pm;
pm.local_xform = xf;
pm.mesh = mesh;
@@ -352,7 +370,7 @@ Vector3i VoxelGI::get_estimated_cell_size() const {
static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 };
int cell_subdiv = subdiv_value[subdiv];
int axis_cell_size[3];
- AABB bounds = AABB(-extents, extents * 2.0);
+ AABB bounds = AABB(-size / 2, size);
int longest_axis = bounds.get_longest_axis_index();
axis_cell_size[longest_axis] = 1 << cell_subdiv;
@@ -390,7 +408,7 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
Voxelizer baker;
- baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0), exposure_normalization);
+ baker.begin_bake(subdiv_value[subdiv], AABB(-size / 2, size), exposure_normalization);
List<PlotMesh> mesh_list;
@@ -448,7 +466,7 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) {
RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data_new->get_rid(), exposure_normalization);
- probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
+ probe_data_new->allocate(baker.get_to_cell_space_xform(), AABB(-size / 2, size), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count());
set_probe_data(probe_data_new);
#ifdef TOOLS_ENABLED
@@ -468,7 +486,7 @@ void VoxelGI::_debug_bake() {
}
AABB VoxelGI::get_aabb() const {
- return AABB(-extents, extents * 2);
+ return AABB(-size / 2, size);
}
PackedStringArray VoxelGI::get_configuration_warnings() const {
@@ -489,8 +507,8 @@ void VoxelGI::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &VoxelGI::set_subdiv);
ClassDB::bind_method(D_METHOD("get_subdiv"), &VoxelGI::get_subdiv);
- ClassDB::bind_method(D_METHOD("set_extents", "extents"), &VoxelGI::set_extents);
- ClassDB::bind_method(D_METHOD("get_extents"), &VoxelGI::get_extents);
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &VoxelGI::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &VoxelGI::get_size);
ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &VoxelGI::set_camera_attributes);
ClassDB::bind_method(D_METHOD("get_camera_attributes"), &VoxelGI::get_camera_attributes);
@@ -500,7 +518,7 @@ void VoxelGI::_bind_methods() {
ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_NONE, "suffix:m"), "set_extents", "get_extents");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ALWAYS_DUPLICATE), "set_probe_data", "get_probe_data");
diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h
index ae348daf9e..d276186dd1 100644
--- a/scene/3d/voxel_gi.h
+++ b/scene/3d/voxel_gi.h
@@ -118,7 +118,7 @@ private:
RID voxel_gi;
Subdiv subdiv = SUBDIV_128;
- Vector3 extents = Vector3(10, 10, 10);
+ Vector3 size = Vector3(20, 20, 20);
Ref<CameraAttributes> camera_attributes;
struct PlotMesh {
@@ -133,6 +133,10 @@ private:
protected:
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+ bool _get(const StringName &p_name, Variant &r_property) const;
+#endif // DISABLE_DEPRECATED
public:
static BakeBeginFunc bake_begin_function;
@@ -145,8 +149,8 @@ public:
void set_subdiv(Subdiv p_subdiv);
Subdiv get_subdiv() const;
- void set_extents(const Vector3 &p_extents);
- Vector3 get_extents() const;
+ void set_size(const Vector3 &p_size);
+ Vector3 get_size() const;
void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes);
Ref<CameraAttributes> get_camera_attributes() const;
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index a2028b8de8..d28a6fcc04 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -30,12 +30,20 @@
#include "animation_blend_space_1d.h"
+#include "animation_blend_tree.h"
+
void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_position));
+ r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
+ r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
- return 0;
+ if (p_parameter == closest) {
+ return -1;
+ } else {
+ return 0;
+ }
}
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
@@ -77,6 +85,9 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace1D::set_blend_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace1D::get_blend_mode);
+
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace1D::set_use_sync);
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace1D::is_using_sync);
@@ -91,7 +102,12 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
+
+ BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE);
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY);
}
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -214,6 +230,14 @@ String AnimationNodeBlendSpace1D::get_value_label() const {
return value_label;
}
+void AnimationNodeBlendSpace1D::set_blend_mode(BlendMode p_blend_mode) {
+ blend_mode = p_blend_mode;
+}
+
+AnimationNodeBlendSpace1D::BlendMode AnimationNodeBlendSpace1D::get_blend_mode() const {
+ return blend_mode;
+}
+
void AnimationNodeBlendSpace1D::set_use_sync(bool p_sync) {
sync = p_sync;
}
@@ -241,79 +265,125 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_
}
double blend_pos = get_parameter(blend_position);
+ int cur_closest = get_parameter(closest);
+ double cur_length_internal = get_parameter(length_internal);
+ double max_time_remaining = 0.0;
- float weights[MAX_BLEND_POINTS] = {};
+ if (blend_mode == BLEND_MODE_INTERPOLATED) {
+ float weights[MAX_BLEND_POINTS] = {};
+
+ int point_lower = -1;
+ float pos_lower = 0.0;
+ int point_higher = -1;
+ float pos_higher = 0.0;
+
+ // find the closest two points to blend between
+ for (int i = 0; i < blend_points_used; i++) {
+ float pos = blend_points[i].position;
+
+ if (pos <= blend_pos) {
+ if (point_lower == -1) {
+ point_lower = i;
+ pos_lower = pos;
+ } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
+ point_lower = i;
+ pos_lower = pos;
+ }
+ } else {
+ if (point_higher == -1) {
+ point_higher = i;
+ pos_higher = pos;
+ } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
+ point_higher = i;
+ pos_higher = pos;
+ }
+ }
+ }
- int point_lower = -1;
- float pos_lower = 0.0;
- int point_higher = -1;
- float pos_higher = 0.0;
+ // fill in weights
- // find the closest two points to blend between
- for (int i = 0; i < blend_points_used; i++) {
- float pos = blend_points[i].position;
-
- if (pos <= blend_pos) {
- if (point_lower == -1) {
- point_lower = i;
- pos_lower = pos;
- } else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
- point_lower = i;
- pos_lower = pos;
- }
+ if (point_lower == -1 && point_higher != -1) {
+ // we are on the left side, no other point to the left
+ // we just play the next point.
+
+ weights[point_higher] = 1.0;
+ } else if (point_higher == -1) {
+ // we are on the right side, no other point to the right
+ // we just play the previous point
+
+ weights[point_lower] = 1.0;
} else {
- if (point_higher == -1) {
- point_higher = i;
- pos_higher = pos;
- } else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
- point_higher = i;
- pos_higher = pos;
- }
- }
- }
+ // we are between two points.
+ // figure out weights, then blend the animations
- // fill in weights
+ float distance_between_points = pos_higher - pos_lower;
- if (point_lower == -1 && point_higher != -1) {
- // we are on the left side, no other point to the left
- // we just play the next point.
+ float current_pos_inbetween = blend_pos - pos_lower;
- weights[point_higher] = 1.0;
- } else if (point_higher == -1) {
- // we are on the right side, no other point to the right
- // we just play the previous point
+ float blend_percentage = current_pos_inbetween / distance_between_points;
- weights[point_lower] = 1.0;
- } else {
- // we are between two points.
- // figure out weights, then blend the animations
+ float blend_lower = 1.0 - blend_percentage;
+ float blend_higher = blend_percentage;
- float distance_between_points = pos_higher - pos_lower;
+ weights[point_lower] = blend_lower;
+ weights[point_higher] = blend_higher;
+ }
- float current_pos_inbetween = blend_pos - pos_lower;
+ // actually blend the animations now
- float blend_percentage = current_pos_inbetween / distance_between_points;
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i == point_lower || i == point_higher) {
+ double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
+ max_time_remaining = MAX(max_time_remaining, remaining);
+ } else if (sync) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
+ }
+ } else {
+ int new_closest = -1;
+ double new_closest_dist = 1e20;
+
+ for (int i = 0; i < blend_points_used; i++) {
+ double d = abs(blend_points[i].position - blend_pos);
+ if (d < new_closest_dist) {
+ new_closest = i;
+ new_closest_dist = d;
+ }
+ }
- float blend_lower = 1.0 - blend_percentage;
- float blend_higher = blend_percentage;
+ if (new_closest != cur_closest && new_closest != -1) {
+ double from = 0.0;
+ if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) {
+ //for ping-pong loop
+ Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node);
+ Ref<AnimationNodeAnimation> na_n = static_cast<Ref<AnimationNodeAnimation>>(blend_points[new_closest].node);
+ if (!na_c.is_null() && !na_n.is_null()) {
+ na_n->set_backward(na_c->is_backward());
+ }
+ //see how much animation remains
+ from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true);
+ }
- weights[point_lower] = blend_lower;
- weights[point_higher] = blend_higher;
- }
+ max_time_remaining = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ cur_length_internal = from + max_time_remaining;
- // actually blend the animations now
+ cur_closest = new_closest;
- double max_time_remaining = 0.0;
+ } else {
+ max_time_remaining = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ }
- for (int i = 0; i < blend_points_used; i++) {
- if (i == point_lower || i == point_higher) {
- double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
- max_time_remaining = MAX(max_time_remaining, remaining);
- } else if (sync) {
- blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ if (sync) {
+ for (int i = 0; i < blend_points_used; i++) {
+ if (i != cur_closest) {
+ blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
+ }
+ }
}
}
+ set_parameter(this->closest, cur_closest);
+ set_parameter(this->length_internal, cur_length_internal);
return max_time_remaining;
}
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index af93783c0d..a1e9a7a764 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -36,6 +36,14 @@
class AnimationNodeBlendSpace1D : public AnimationRootNode {
GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode);
+public:
+ enum BlendMode {
+ BLEND_MODE_INTERPOLATED,
+ BLEND_MODE_DISCRETE,
+ BLEND_MODE_DISCRETE_CARRY,
+ };
+
+protected:
enum {
MAX_BLEND_POINTS = 64
};
@@ -61,6 +69,10 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
void _tree_changed();
StringName blend_position = "blend_position";
+ StringName closest = "closest";
+ StringName length_internal = "length_internal";
+
+ BlendMode blend_mode = BLEND_MODE_INTERPOLATED;
protected:
bool sync = false;
@@ -95,6 +107,9 @@ public:
void set_value_label(const String &p_label);
String get_value_label() const;
+ void set_blend_mode(BlendMode p_blend_mode);
+ BlendMode get_blend_mode() const;
+
void set_use_sync(bool p_sync);
bool is_using_sync() const;
@@ -107,4 +122,6 @@ public:
~AnimationNodeBlendSpace1D();
};
+VARIANT_ENUM_CAST(AnimationNodeBlendSpace1D::BlendMode)
+
#endif // ANIMATION_BLEND_SPACE_1D_H
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index a00b1d8ee1..12a96c8679 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -518,7 +518,7 @@ void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const {
}
Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const {
- return 0; //for blend amount
+ return 0; // For blend amount.
}
String AnimationNodeBlend2::get_caption() const {
@@ -531,7 +531,7 @@ double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_is_extern
double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - amount, FILTER_BLEND, sync);
double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync);
- return amount > 0.5 ? rem1 : rem0; //hacky but good enough
+ return amount > 0.5 ? rem1 : rem0; // Hacky but good enough.
}
bool AnimationNodeBlend2::has_filter() const {
@@ -553,7 +553,7 @@ void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const {
}
Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const {
- return 0; //for blend amount
+ return 0; // For blend amount.
}
String AnimationNodeBlend3::get_caption() const {
@@ -566,7 +566,7 @@ double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_is_extern
double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0 - ABS(amount), FILTER_IGNORE, sync);
double rem2 = blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_IGNORE, sync);
- return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough
+ return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); // Hacky but good enough.
}
void AnimationNodeBlend3::_bind_methods() {
@@ -585,7 +585,7 @@ void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) cons
}
Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const {
- return 1.0; //initial timescale
+ return 1.0; // Initial timescale.
}
String AnimationNodeTimeScale::get_caption() const {
@@ -611,24 +611,24 @@ AnimationNodeTimeScale::AnimationNodeTimeScale() {
////////////////////////////////////
void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const {
- r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater"));
+ r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos_request, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater")); // It will be reset to -1 after seeking the position immediately.
}
Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const {
- return 1.0; //initial timescale
+ return -1.0; // Initial seek request.
}
String AnimationNodeTimeSeek::get_caption() const {
- return "Seek";
+ return "TimeSeek";
}
double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_is_external_seeking) {
- double cur_seek_pos = get_parameter(seek_pos);
+ double cur_seek_pos = get_parameter(seek_pos_request);
if (p_seek) {
return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
} else if (cur_seek_pos >= 0) {
double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true);
- set_parameter(seek_pos, -1.0); //reset
+ set_parameter(seek_pos_request, -1.0); // Reset.
return ret;
} else {
return blend_input(0, p_time, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
@@ -644,9 +644,66 @@ AnimationNodeTimeSeek::AnimationNodeTimeSeek() {
/////////////////////////////////////////////////
+bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_value) {
+ String path = p_path;
+
+ if (!path.begins_with("input_")) {
+ return false;
+ }
+
+ int which = path.get_slicec('/', 0).get_slicec('_', 1).to_int();
+ String what = path.get_slicec('/', 1);
+
+ if (which == get_input_count() && what == "name") {
+ if (add_input(p_value)) {
+ return true;
+ }
+ return false;
+ }
+
+ ERR_FAIL_INDEX_V(which, get_input_count(), false);
+
+ if (what == "name") {
+ set_input_name(which, p_value);
+ } else if (what == "auto_advance") {
+ set_input_as_auto_advance(which, p_value);
+ } else if (what == "reset") {
+ set_input_reset(which, p_value);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool AnimationNodeTransition::_get(const StringName &p_path, Variant &r_ret) const {
+ String path = p_path;
+
+ if (!path.begins_with("input_")) {
+ return false;
+ }
+
+ int which = path.get_slicec('/', 0).get_slicec('_', 1).to_int();
+ String what = path.get_slicec('/', 1);
+
+ ERR_FAIL_INDEX_V(which, get_input_count(), false);
+
+ if (what == "name") {
+ r_ret = get_input_name(which);
+ } else if (what == "auto_advance") {
+ r_ret = is_input_set_as_auto_advance(which);
+ } else if (what == "reset") {
+ r_ret = is_input_reset(which);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const {
String anims;
- for (int i = 0; i < enabled_inputs; i++) {
+ for (int i = 0; i < get_input_count(); i++) {
if (i > 0) {
anims += ",";
}
@@ -684,56 +741,47 @@ String AnimationNodeTransition::get_caption() const {
return "Transition";
}
-void AnimationNodeTransition::_update_inputs() {
- while (get_input_count() < enabled_inputs) {
- add_input(inputs[get_input_count()].name);
+void AnimationNodeTransition::set_input_count(int p_inputs) {
+ for (int i = get_input_count(); i < p_inputs; i++) {
+ add_input("state_" + itos(i));
}
-
- while (get_input_count() > enabled_inputs) {
+ while (get_input_count() > p_inputs) {
remove_input(get_input_count() - 1);
}
+ notify_property_list_changed();
}
-void AnimationNodeTransition::set_enabled_inputs(int p_inputs) {
- ERR_FAIL_INDEX(p_inputs, MAX_INPUTS);
- enabled_inputs = p_inputs;
- _update_inputs();
+bool AnimationNodeTransition::add_input(const String &p_name) {
+ if (AnimationNode::add_input(p_name)) {
+ input_data.push_back(InputData());
+ return true;
+ }
+ return false;
}
-int AnimationNodeTransition::get_enabled_inputs() {
- return enabled_inputs;
+void AnimationNodeTransition::remove_input(int p_index) {
+ input_data.remove_at(p_index);
+ AnimationNode::remove_input(p_index);
}
void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) {
- ERR_FAIL_INDEX(p_input, MAX_INPUTS);
- inputs[p_input].auto_advance = p_enable;
+ ERR_FAIL_INDEX(p_input, get_input_count());
+ input_data.write[p_input].auto_advance = p_enable;
}
bool AnimationNodeTransition::is_input_set_as_auto_advance(int p_input) const {
- ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, false);
- return inputs[p_input].auto_advance;
+ ERR_FAIL_INDEX_V(p_input, get_input_count(), false);
+ return input_data[p_input].auto_advance;
}
-void AnimationNodeTransition::set_input_caption(int p_input, const String &p_name) {
- ERR_FAIL_INDEX(p_input, MAX_INPUTS);
- inputs[p_input].name = p_name;
- set_input_name(p_input, p_name);
+void AnimationNodeTransition::set_input_reset(int p_input, bool p_enable) {
+ ERR_FAIL_INDEX(p_input, get_input_count());
+ input_data.write[p_input].reset = p_enable;
}
-String AnimationNodeTransition::get_input_caption(int p_input) const {
- ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, String());
- return inputs[p_input].name;
-}
-
-int AnimationNodeTransition::find_input_caption(const String &p_name) const {
- int idx = -1;
- for (int i = 0; i < MAX_INPUTS; i++) {
- if (inputs[i].name == p_name) {
- idx = i;
- break;
- }
- }
- return idx;
+bool AnimationNodeTransition::is_input_reset(int p_input) const {
+ ERR_FAIL_INDEX_V(p_input, get_input_count(), true);
+ return input_data[p_input].reset;
}
void AnimationNodeTransition::set_xfade_time(double p_fade) {
@@ -752,12 +800,12 @@ Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
return xfade_curve;
}
-void AnimationNodeTransition::set_reset(bool p_reset) {
- reset = p_reset;
+void AnimationNodeTransition::set_allow_transition_to_self(bool p_enable) {
+ allow_transition_to_self = p_enable;
}
-bool AnimationNodeTransition::is_reset() const {
- return reset;
+bool AnimationNodeTransition::is_allow_transition_to_self() const {
+ return allow_transition_to_self;
}
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) {
@@ -772,23 +820,25 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
bool restart = false;
if (!cur_transition_request.is_empty()) {
- int new_idx = find_input_caption(cur_transition_request);
+ int new_idx = find_input(cur_transition_request);
if (new_idx >= 0) {
if (cur_current_index == new_idx) {
- // Transition to same state.
- restart = reset;
- cur_prev_xfading = 0;
- set_parameter(prev_xfading, 0);
- cur_prev_index = -1;
- set_parameter(prev_index, -1);
+ if (allow_transition_to_self) {
+ // Transition to same state.
+ restart = input_data[cur_current_index].reset;
+ cur_prev_xfading = 0;
+ set_parameter(prev_xfading, 0);
+ cur_prev_index = -1;
+ set_parameter(prev_index, -1);
+ }
} else {
switched = true;
cur_prev_index = cur_current_index;
set_parameter(prev_index, cur_current_index);
+ cur_current_index = new_idx;
+ set_parameter(current_index, cur_current_index);
+ set_parameter(current_state, cur_transition_request);
}
- cur_current_index = new_idx;
- set_parameter(current_index, cur_current_index);
- set_parameter(current_state, cur_transition_request);
} else {
ERR_PRINT("No such input: '" + cur_transition_request + "'");
}
@@ -807,21 +857,21 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
cur_time = 0;
}
- if (cur_current_index < 0 || cur_current_index >= enabled_inputs || cur_prev_index >= enabled_inputs) {
+ if (cur_current_index < 0 || cur_current_index >= get_input_count() || cur_prev_index >= get_input_count()) {
return 0;
}
double rem = 0.0;
if (sync) {
- for (int i = 0; i < enabled_inputs; i++) {
+ for (int i = 0; i < get_input_count(); i++) {
if (i != cur_current_index && i != cur_prev_index) {
blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
}
}
}
- if (cur_prev_index < 0) { // process current animation, check for transition
+ if (cur_prev_index < 0) { // Process current animation, check for transition.
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
@@ -831,11 +881,11 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
cur_time += p_time;
}
- if (inputs[cur_current_index].auto_advance && rem <= xfade_time) {
- set_parameter(transition_request, get_input_caption((cur_current_index + 1) % enabled_inputs));
+ if (input_data[cur_current_index].auto_advance && rem <= xfade_time) {
+ set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count()));
}
- } else { // cross-fading from prev to current
+ } else { // Cross-fading from prev to current.
real_t blend = xfade_time == 0 ? 0 : (cur_prev_xfading / xfade_time);
if (xfade_curve.is_valid()) {
@@ -844,7 +894,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
real_t blend_inv = 1.0 - blend;
- if (reset && !p_seek && switched) { //just switched, seek to start of current
+ if (input_data[cur_current_index].reset && !p_seek && switched) { // Just switched, seek to start of current.
rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
} else {
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
@@ -869,28 +919,22 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
return rem;
}
-void AnimationNodeTransition::_validate_property(PropertyInfo &p_property) const {
- if (p_property.name.begins_with("input_")) {
- String n = p_property.name.get_slicec('/', 0).get_slicec('_', 1);
- if (n != "count") {
- int idx = n.to_int();
- if (idx >= enabled_inputs) {
- p_property.usage = PROPERTY_USAGE_NONE;
- }
- }
+void AnimationNodeTransition::_get_property_list(List<PropertyInfo> *p_list) const {
+ for (int i = 0; i < get_input_count(); i++) {
+ p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/reset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL));
}
}
void AnimationNodeTransition::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_enabled_inputs", "amount"), &AnimationNodeTransition::set_enabled_inputs);
- ClassDB::bind_method(D_METHOD("get_enabled_inputs"), &AnimationNodeTransition::get_enabled_inputs);
+ ClassDB::bind_method(D_METHOD("set_input_count", "input_count"), &AnimationNodeTransition::set_input_count);
ClassDB::bind_method(D_METHOD("set_input_as_auto_advance", "input", "enable"), &AnimationNodeTransition::set_input_as_auto_advance);
ClassDB::bind_method(D_METHOD("is_input_set_as_auto_advance", "input"), &AnimationNodeTransition::is_input_set_as_auto_advance);
- ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
- ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
- ClassDB::bind_method(D_METHOD("find_input_caption", "caption"), &AnimationNodeTransition::find_input_caption);
+ ClassDB::bind_method(D_METHOD("set_input_reset", "input", "enable"), &AnimationNodeTransition::set_input_reset);
+ ClassDB::bind_method(D_METHOD("is_input_reset", "input"), &AnimationNodeTransition::is_input_reset);
ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
@@ -898,24 +942,16 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
- ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeTransition::set_reset);
- ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeTransition::is_reset);
+ ClassDB::bind_method(D_METHOD("set_allow_transition_to_self", "enable"), &AnimationNodeTransition::set_allow_transition_to_self);
+ ClassDB::bind_method(D_METHOD("is_allow_transition_to_self"), &AnimationNodeTransition::is_allow_transition_to_self);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,31,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset");
-
- for (int i = 0; i < MAX_INPUTS; i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
- ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_as_auto_advance", "is_input_set_as_auto_advance", i);
- }
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_transition_to_self"), "set_allow_transition_to_self", "is_allow_transition_to_self");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED, "Inputs,input_"), "set_input_count", "get_input_count");
}
AnimationNodeTransition::AnimationNodeTransition() {
- for (int i = 0; i < MAX_INPUTS; i++) {
- inputs[i].name = "state " + itos(i);
- }
}
/////////////////////
@@ -1016,7 +1052,7 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
nodes.erase(p_name);
- //erase connections to name
+ // Erase connections to name.
for (KeyValue<StringName, Node> &E : nodes) {
for (int i = 0; i < E.value.connections.size(); i++) {
if (E.value.connections[i] == p_name) {
@@ -1040,7 +1076,7 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
nodes[p_new_name] = nodes[p_name];
nodes.erase(p_name);
- //rename connections
+ // Rename connections.
for (KeyValue<StringName, Node> &E : nodes) {
for (int i = 0; i < E.value.connections.size(); i++) {
if (E.value.connections[i] == p_name) {
@@ -1048,7 +1084,7 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
}
}
}
- //connection must be done with new name
+ // Connection must be done with new name.
nodes[p_new_name].node->connect("changed", callable_mp(this, &AnimationNodeBlendTree::_node_changed).bind(p_new_name), CONNECT_REFERENCE_COUNTED);
emit_signal(SNAME("tree_changed"));
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index a1969bb621..1e90952564 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -257,7 +257,7 @@ public:
class AnimationNodeTimeSeek : public AnimationNode {
GDCLASS(AnimationNodeTimeSeek, AnimationNode);
- StringName seek_pos = PNAME("seek_position");
+ StringName seek_pos_request = PNAME("seek_request");
protected:
static void _bind_methods();
@@ -276,16 +276,11 @@ public:
class AnimationNodeTransition : public AnimationNodeSync {
GDCLASS(AnimationNodeTransition, AnimationNodeSync);
- enum {
- MAX_INPUTS = 32
- };
struct InputData {
- String name;
bool auto_advance = false;
+ bool reset = true;
};
-
- InputData inputs[MAX_INPUTS];
- int enabled_inputs = 0;
+ Vector<InputData> input_data;
StringName time = "time";
StringName prev_xfading = "prev_xfading";
@@ -299,13 +294,13 @@ class AnimationNodeTransition : public AnimationNodeSync {
double xfade_time = 0.0;
Ref<Curve> xfade_curve;
- bool reset = true;
-
- void _update_inputs();
+ bool allow_transition_to_self = false;
protected:
+ bool _get(const StringName &p_path, Variant &r_ret) const;
+ bool _set(const StringName &p_path, const Variant &p_value);
static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const;
+ void _get_property_list(List<PropertyInfo> *p_list) const;
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
@@ -314,15 +309,16 @@ public:
virtual String get_caption() const override;
- void set_enabled_inputs(int p_inputs);
- int get_enabled_inputs();
+ void set_input_count(int p_inputs);
+
+ virtual bool add_input(const String &p_name) override;
+ virtual void remove_input(int p_index) override;
void set_input_as_auto_advance(int p_input, bool p_enable);
bool is_input_set_as_auto_advance(int p_input) const;
- void set_input_caption(int p_input, const String &p_name);
- String get_input_caption(int p_input) const;
- int find_input_caption(const String &p_name) const;
+ void set_input_reset(int p_input, bool p_enable);
+ bool is_input_reset(int p_input) const;
void set_xfade_time(double p_fade);
double get_xfade_time() const;
@@ -330,8 +326,8 @@ public:
void set_xfade_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_xfade_curve() const;
- void set_reset(bool p_reset);
- bool is_reset() const;
+ void set_allow_transition_to_self(bool p_enable);
+ bool is_allow_transition_to_self() const;
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 7fb831b3b2..ec28a5cca1 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -252,7 +252,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
path.clear(); //a new one will be needed
if (current == p_travel) {
- return false; // Will teleport oneself (restart).
+ return !p_state_machine->is_allow_transition_to_self();
}
Vector2 current_pos = p_state_machine->states[current].position;
@@ -813,6 +813,14 @@ void AnimationNodeStateMachine::replace_node(const StringName &p_name, Ref<Anima
p_node->connect("tree_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed), CONNECT_REFERENCE_COUNTED);
}
+void AnimationNodeStateMachine::set_allow_transition_to_self(bool p_enable) {
+ allow_transition_to_self = p_enable;
+}
+
+bool AnimationNodeStateMachine::is_allow_transition_to_self() const {
+ return allow_transition_to_self;
+}
+
bool AnimationNodeStateMachine::can_edit_node(const StringName &p_name) const {
if (states.has(p_name)) {
return !(states[p_name].node->is_class("AnimationNodeStartState") || states[p_name].node->is_class("AnimationNodeEndState"));
@@ -1383,6 +1391,11 @@ void AnimationNodeStateMachine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeStateMachine::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeStateMachine::get_graph_offset);
+
+ ClassDB::bind_method(D_METHOD("set_allow_transition_to_self", "enable"), &AnimationNodeStateMachine::set_allow_transition_to_self);
+ ClassDB::bind_method(D_METHOD("is_allow_transition_to_self"), &AnimationNodeStateMachine::is_allow_transition_to_self);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_transition_to_self"), "set_allow_transition_to_self", "is_allow_transition_to_self");
}
AnimationNodeStateMachine::AnimationNodeStateMachine() {
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index cf4d850aa6..5c2a4d6264 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -188,6 +188,7 @@ private:
};
HashMap<StringName, State> states;
+ bool allow_transition_to_self = false;
struct Transition {
StringName from;
@@ -254,6 +255,9 @@ public:
void remove_transition_by_index(const int p_transition);
void remove_transition(const StringName &p_from, const StringName &p_to);
+ void set_allow_transition_to_self(bool p_enable);
+ bool is_allow_transition_to_self() const;
+
bool can_edit_node(const StringName &p_name) const;
AnimationNodeStateMachine *get_prev_state_machine() const;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 63e0fb6935..2e25d685d6 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -431,6 +431,17 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
}
}
+ if (a->track_get_type(i) == Animation::TYPE_AUDIO) {
+ if (!node_cache->audio_anim.has(a->track_get_path(i).get_concatenated_names())) {
+ TrackNodeCache::AudioAnim aa;
+ aa.object = (Object *)child;
+ aa.audio_stream.instantiate();
+ aa.audio_stream->set_polyphony(audio_max_polyphony);
+
+ node_cache->audio_anim[a->track_get_path(i).get_concatenated_names()] = aa;
+ }
+ }
+
node_cache->last_setup_pass = setup_pass;
}
}
@@ -820,52 +831,40 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (!nc->node || is_stopping) {
continue;
}
-
- if (p_seeked) {
#ifdef TOOLS_ENABLED
- if (!can_call) {
- continue; // To avoid spamming the preview in editor.
- }
+ if (p_seeked && !can_call) {
+ continue; // To avoid spamming the preview in editor.
+ }
#endif // TOOLS_ENABLED
- int idx = a->track_find_key(i, p_time);
- if (idx < 0) {
- continue;
- }
-
- Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
- if (!stream.is_valid()) {
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- } else {
- float start_ofs = a->audio_track_get_key_start_offset(i, idx);
- start_ofs += p_time - a->track_get_key_time(i, idx);
- float end_ofs = a->audio_track_get_key_end_offset(i, idx);
- float len = stream->get_length();
-
- if (start_ofs > len - end_ofs) {
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- continue;
- }
-
- nc->node->call(SNAME("set_stream"), stream);
- nc->node->call(SNAME("play"), start_ofs);
+ HashMap<StringName, TrackNodeCache::AudioAnim>::Iterator E = nc->audio_anim.find(a->track_get_path(i).get_concatenated_names());
+ ERR_CONTINUE(!E); //should it continue, or create a new one?
- nc->audio_playing = true;
- playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force an end at a time
- nc->audio_len = len - start_ofs - end_ofs;
- } else {
- nc->audio_len = 0;
- }
+ TrackNodeCache::AudioAnim *aa = &E->value;
+ Node *asp = Object::cast_to<Node>(aa->object);
+ if (!asp) {
+ continue;
+ }
+ aa->length = a->get_length();
+ aa->time = p_time;
+ aa->loop = a->get_loop_mode() != Animation::LOOP_NONE;
+ aa->backward = backward;
+ if (aa->accum_pass != accum_pass) {
+ ERR_CONTINUE(cache_update_audio_size >= NODE_CACHE_UPDATE_MAX);
+ cache_update_audio[cache_update_audio_size++] = aa;
+ aa->accum_pass = accum_pass;
+ }
- nc->audio_start = p_time;
+ HashMap<int, TrackNodeCache::PlayingAudioStreamInfo> &map = aa->playing_streams;
+ // Find stream.
+ int idx = -1;
+ if (p_seeked) {
+ idx = a->track_find_key(i, p_time);
+ // Discard previous stream when seeking.
+ if (map.has(idx)) {
+ aa->audio_stream_playback->stop_stream(map[idx].index);
+ map.erase(idx);
}
-
} else {
- //find stuff to play
List<int> to_play;
if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
@@ -875,55 +874,47 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_looped_flag);
if (to_play.size()) {
- int idx = to_play.back()->get();
-
- Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
- if (!stream.is_valid()) {
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- } else {
- float start_ofs = a->audio_track_get_key_start_offset(i, idx);
- float end_ofs = a->audio_track_get_key_end_offset(i, idx);
- float len = stream->get_length();
-
- nc->node->call(SNAME("set_stream"), stream);
- nc->node->call(SNAME("play"), start_ofs);
-
- nc->audio_playing = true;
- playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force an end at a time
- nc->audio_len = len - start_ofs - end_ofs;
- } else {
- nc->audio_len = 0;
- }
-
- nc->audio_start = p_time;
- }
- } else if (nc->audio_playing) {
- bool loop = a->get_loop_mode() != Animation::LOOP_NONE;
-
- bool stop = false;
-
- if (!loop) {
- if ((p_time < nc->audio_start && !backward) || (p_time > nc->audio_start && backward)) {
- stop = true;
- }
- } else if (nc->audio_len > 0) {
- float len = nc->audio_start > p_time ? (a->get_length() - nc->audio_start) + p_time : p_time - nc->audio_start;
+ idx = to_play.back()->get();
+ }
+ }
+ if (idx < 0) {
+ continue;
+ }
- if (len > nc->audio_len) {
- stop = true;
- }
+ // Play stream.
+ Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
+ if (stream.is_valid()) {
+ double start_ofs = a->audio_track_get_key_start_offset(i, idx);
+ double end_ofs = a->audio_track_get_key_end_offset(i, idx);
+ double len = stream->get_length();
+
+ if (aa->object->call(SNAME("get_stream")) != aa->audio_stream) {
+ aa->object->call(SNAME("set_stream"), aa->audio_stream);
+ aa->audio_stream_playback.unref();
+ if (!playing_audio_stream_players.has(asp)) {
+ playing_audio_stream_players.push_back(asp);
}
+ }
+ if (!aa->object->call(SNAME("is_playing"))) {
+ aa->object->call(SNAME("play"));
+ }
+ if (!aa->object->call(SNAME("has_stream_playback"))) {
+ aa->audio_stream_playback.unref();
+ continue;
+ }
+ if (aa->audio_stream_playback.is_null()) {
+ aa->audio_stream_playback = aa->object->call(SNAME("get_stream_playback"));
+ }
- if (stop) {
- //time to stop
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- }
+ TrackNodeCache::PlayingAudioStreamInfo pasi;
+ pasi.index = aa->audio_stream_playback->play_stream(stream, start_ofs);
+ pasi.start = p_time;
+ if (len && end_ofs > 0) { // Force an end at a time.
+ pasi.len = len - start_ofs - end_ofs;
+ } else {
+ pasi.len = 0;
}
+ map[idx] = pasi;
}
} break;
@@ -1223,6 +1214,53 @@ void AnimationPlayer::_animation_update_transforms() {
ERR_CONTINUE(ba->accum_pass != accum_pass);
ba->object->set_indexed(ba->bezier_property, ba->bezier_accum);
}
+
+ for (int i = 0; i < cache_update_audio_size; i++) {
+ TrackNodeCache::AudioAnim *aa = cache_update_audio[i];
+
+ ERR_CONTINUE(aa->accum_pass != accum_pass);
+
+ // Audio ending process.
+ LocalVector<int> erase_list;
+ for (const KeyValue<int, TrackNodeCache::PlayingAudioStreamInfo> &K : aa->playing_streams) {
+ TrackNodeCache::PlayingAudioStreamInfo pasi = K.value;
+
+ bool stop = false;
+ if (!aa->audio_stream_playback->is_stream_playing(pasi.index)) {
+ stop = true;
+ }
+ if (!aa->loop) {
+ if (!aa->backward) {
+ if (aa->time < pasi.start) {
+ stop = true;
+ }
+ } else if (aa->backward) {
+ if (aa->time > pasi.start) {
+ stop = true;
+ }
+ }
+ }
+ if (pasi.len > 0) {
+ double len = 0.0;
+ if (!aa->backward) {
+ len = pasi.start > aa->time ? (aa->length - pasi.start) + aa->time : aa->time - pasi.start;
+ } else {
+ len = pasi.start < aa->time ? (aa->length - aa->time) + pasi.start : pasi.start - aa->time;
+ }
+ if (len > pasi.len) {
+ stop = true;
+ }
+ }
+ if (stop) {
+ // Time to stop.
+ aa->audio_stream_playback->stop_stream(pasi.index);
+ erase_list.push_back(K.key);
+ }
+ }
+ for (uint32_t erase_idx = 0; erase_idx < erase_list.size(); erase_idx++) {
+ aa->playing_streams.erase(erase_list[erase_idx]);
+ }
+ }
}
void AnimationPlayer::_animation_process(double p_delta) {
@@ -1238,6 +1276,7 @@ void AnimationPlayer::_animation_process(double p_delta) {
cache_update_size = 0;
cache_update_prop_size = 0;
cache_update_bezier_size = 0;
+ cache_update_audio_size = 0;
AnimationData *prev_from = playback.current.from;
_animation_process2(p_delta, started);
@@ -1675,6 +1714,7 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa
}
if (get_current_animation() != p_name) {
+ _clear_audio_streams();
_stop_playing_caches(false);
}
@@ -1776,15 +1816,18 @@ float AnimationPlayer::get_playing_speed() const {
}
void AnimationPlayer::seek(double p_time, bool p_update) {
+ playback.current.pos = p_time;
+
if (!playback.current.from) {
if (playback.assigned) {
ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned));
playback.current.from = &animation_set[playback.assigned];
}
- ERR_FAIL_COND(!playback.current.from);
+ if (!playback.current.from) {
+ return; // There is no animation.
+ }
}
- playback.current.pos = p_time;
playback.seeked = true;
if (p_update) {
_animation_process(0);
@@ -1792,20 +1835,22 @@ void AnimationPlayer::seek(double p_time, bool p_update) {
}
void AnimationPlayer::seek_delta(double p_time, double p_delta) {
+ playback.current.pos = p_time - p_delta;
+
if (!playback.current.from) {
if (playback.assigned) {
ERR_FAIL_COND_MSG(!animation_set.has(playback.assigned), vformat("Animation not found: %s.", playback.assigned));
playback.current.from = &animation_set[playback.assigned];
}
- ERR_FAIL_COND(!playback.current.from);
+ if (!playback.current.from) {
+ return; // There is no animation.
+ }
}
- playback.current.pos = p_time - p_delta;
if (speed_scale != 0.0) {
p_delta /= speed_scale;
}
_animation_process(p_delta);
- //playback.current.pos=p_time;
}
bool AnimationPlayer::is_valid() const {
@@ -1856,6 +1901,7 @@ void AnimationPlayer::_node_removed(Node *p_node) {
}
void AnimationPlayer::clear_caches() {
+ _clear_audio_streams();
_stop_playing_caches(true);
node_cache_map.clear();
@@ -1867,10 +1913,19 @@ void AnimationPlayer::clear_caches() {
cache_update_size = 0;
cache_update_prop_size = 0;
cache_update_bezier_size = 0;
+ cache_update_audio_size = 0;
emit_signal(SNAME("caches_cleared"));
}
+void AnimationPlayer::_clear_audio_streams() {
+ for (int i = 0; i < playing_audio_stream_players.size(); i++) {
+ playing_audio_stream_players[i]->call(SNAME("stop"));
+ playing_audio_stream_players[i]->call(SNAME("set_stream"), Ref<AudioStream>());
+ }
+ playing_audio_stream_players.clear();
+}
+
void AnimationPlayer::set_active(bool p_active) {
if (active == p_active) {
return;
@@ -1950,6 +2005,15 @@ AnimationPlayer::AnimationMethodCallMode AnimationPlayer::get_method_call_mode()
return method_call_mode;
}
+void AnimationPlayer::set_audio_max_polyphony(int p_audio_max_polyphony) {
+ ERR_FAIL_COND(p_audio_max_polyphony < 0 || p_audio_max_polyphony > 128);
+ audio_max_polyphony = p_audio_max_polyphony;
+}
+
+int AnimationPlayer::get_audio_max_polyphony() const {
+ return audio_max_polyphony;
+}
+
void AnimationPlayer::set_movie_quit_on_finish_enabled(bool p_enabled) {
movie_quit_on_finish = p_enabled;
}
@@ -1978,6 +2042,7 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) {
}
void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) {
+ _clear_audio_streams();
_stop_playing_caches(p_reset);
Playback &c = playback;
c.blend.clear();
@@ -2198,6 +2263,9 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode);
ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_mode);
+ ClassDB::bind_method(D_METHOD("set_audio_max_polyphony", "max_polyphony"), &AnimationPlayer::set_audio_max_polyphony);
+ ClassDB::bind_method(D_METHOD("get_audio_max_polyphony"), &AnimationPlayer::get_audio_max_polyphony);
+
ClassDB::bind_method(D_METHOD("set_movie_quit_on_finish_enabled", "enabled"), &AnimationPlayer::set_movie_quit_on_finish_enabled);
ClassDB::bind_method(D_METHOD("is_movie_quit_on_finish_enabled"), &AnimationPlayer::is_movie_quit_on_finish_enabled);
@@ -2223,6 +2291,7 @@ void AnimationPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_active", "is_active");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "method_call_mode", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_method_call_mode", "get_method_call_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "movie_quit_on_finish"), "set_movie_quit_on_finish_enabled", "is_movie_quit_on_finish_enabled");
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 2901c43dcf..b0975fbead 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -37,6 +37,7 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/animation.h"
#include "scene/resources/animation_library.h"
+#include "scene/resources/audio_stream_polyphonic.h"
#ifdef TOOLS_ENABLED
class AnimatedValuesBackup : public RefCounted {
@@ -147,6 +148,26 @@ private:
HashMap<StringName, BezierAnim> bezier_anim;
+ struct PlayingAudioStreamInfo {
+ AudioStreamPlaybackPolyphonic::ID index = -1;
+ double start = 0.0;
+ double len = 0.0;
+ };
+
+ struct AudioAnim {
+ Ref<AudioStreamPolyphonic> audio_stream;
+ Ref<AudioStreamPlaybackPolyphonic> audio_stream_playback;
+ HashMap<int, PlayingAudioStreamInfo> playing_streams;
+ Object *object = nullptr;
+ uint64_t accum_pass = 0;
+ double length = 0.0;
+ double time = 0.0;
+ bool loop = false;
+ bool backward = false;
+ };
+
+ HashMap<StringName, AudioAnim> audio_anim;
+
uint32_t last_setup_pass = 0;
TrackNodeCache() {}
};
@@ -187,7 +208,10 @@ private:
int cache_update_prop_size = 0;
TrackNodeCache::BezierAnim *cache_update_bezier[NODE_CACHE_UPDATE_MAX];
int cache_update_bezier_size = 0;
+ TrackNodeCache::AudioAnim *cache_update_audio[NODE_CACHE_UPDATE_MAX];
+ int cache_update_audio_size = 0;
HashSet<TrackNodeCache *> playing_caches;
+ Vector<Node *> playing_audio_stream_players;
uint64_t accum_pass = 1;
float speed_scale = 1.0;
@@ -263,6 +287,7 @@ private:
bool reset_on_save = true;
AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE;
AnimationMethodCallMode method_call_mode = ANIMATION_METHOD_CALL_DEFERRED;
+ int audio_max_polyphony = 32;
bool movie_quit_on_finish = false;
bool processing = false;
bool active = true;
@@ -278,6 +303,7 @@ private:
void _animation_process(double p_delta);
void _node_removed(Node *p_node);
+ void _clear_audio_streams();
void _stop_playing_caches(bool p_reset);
// bind helpers
@@ -377,6 +403,9 @@ public:
void set_method_call_mode(AnimationMethodCallMode p_mode);
AnimationMethodCallMode get_method_call_mode() const;
+ void set_audio_max_polyphony(int p_audio_max_polyphony);
+ int get_audio_max_polyphony() const;
+
void set_movie_quit_on_finish_enabled(bool p_enabled);
bool is_movie_quit_on_finish_enabled() const;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 05b6c72cbd..dd5bf31c66 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -303,36 +303,21 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_is_external_seeking, p_connections);
}
-int AnimationNode::get_input_count() const {
- return inputs.size();
-}
-
-String AnimationNode::get_input_name(int p_input) {
- ERR_FAIL_INDEX_V(p_input, inputs.size(), String());
- return inputs[p_input].name;
-}
-
String AnimationNode::get_caption() const {
String ret = "Node";
GDVIRTUAL_CALL(_get_caption, ret);
return ret;
}
-void AnimationNode::add_input(const String &p_name) {
+bool AnimationNode::add_input(const String &p_name) {
//root nodes can't add inputs
- ERR_FAIL_COND(Object::cast_to<AnimationRootNode>(this) != nullptr);
+ ERR_FAIL_COND_V(Object::cast_to<AnimationRootNode>(this) != nullptr, false);
Input input;
- ERR_FAIL_COND(p_name.contains(".") || p_name.contains("/"));
+ ERR_FAIL_COND_V(p_name.contains(".") || p_name.contains("/"), false);
input.name = p_name;
inputs.push_back(input);
emit_changed();
-}
-
-void AnimationNode::set_input_name(int p_input, const String &p_name) {
- ERR_FAIL_INDEX(p_input, inputs.size());
- ERR_FAIL_COND(p_name.contains(".") || p_name.contains("/"));
- inputs.write[p_input].name = p_name;
- emit_changed();
+ return true;
}
void AnimationNode::remove_input(int p_index) {
@@ -341,6 +326,34 @@ void AnimationNode::remove_input(int p_index) {
emit_changed();
}
+bool AnimationNode::set_input_name(int p_input, const String &p_name) {
+ ERR_FAIL_INDEX_V(p_input, inputs.size(), false);
+ ERR_FAIL_COND_V(p_name.contains(".") || p_name.contains("/"), false);
+ inputs.write[p_input].name = p_name;
+ emit_changed();
+ return true;
+}
+
+String AnimationNode::get_input_name(int p_input) const {
+ ERR_FAIL_INDEX_V(p_input, inputs.size(), String());
+ return inputs[p_input].name;
+}
+
+int AnimationNode::get_input_count() const {
+ return inputs.size();
+}
+
+int AnimationNode::find_input(const String &p_name) const {
+ int idx = -1;
+ for (int i = 0; i < inputs.size(); i++) {
+ if (inputs[i].name == p_name) {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+}
+
double AnimationNode::process(double p_time, bool p_seek, bool p_is_external_seeking) {
double ret = 0;
GDVIRTUAL_CALL(_process, p_time, p_seek, p_is_external_seeking, ret);
@@ -404,11 +417,12 @@ Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
}
void AnimationNode::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);
- ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);
-
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
+ ClassDB::bind_method(D_METHOD("set_input_name", "input", "name"), &AnimationNode::set_input_name);
+ ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name);
+ ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count);
+ ClassDB::bind_method(D_METHOD("find_input", "name"), &AnimationNode::find_input);
ClassDB::bind_method(D_METHOD("set_filter_path", "path", "enable"), &AnimationNode::set_filter_path);
ClassDB::bind_method(D_METHOD("is_path_filtered", "path"), &AnimationNode::is_path_filtered);
@@ -486,13 +500,7 @@ void AnimationTree::set_active(bool p_active) {
}
if (!active && is_inside_tree()) {
- for (const TrackCache *E : playing_caches) {
- if (ObjectDB::get_instance(E->object_id)) {
- E->object->call(SNAME("stop"));
- }
- }
-
- playing_caches.clear();
+ _clear_caches();
}
}
@@ -531,6 +539,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
if (!player->has_node(player->get_root())) {
ERR_PRINT("AnimationTree: AnimationPlayer root is invalid.");
set_active(false);
+ _clear_caches();
return false;
}
Node *parent = player->get_node(player->get_root());
@@ -763,6 +772,8 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track_audio->object = child;
track_audio->object_id = track_audio->object->get_instance_id();
+ track_audio->audio_stream.instantiate();
+ track_audio->audio_stream->set_polyphony(audio_max_polyphony);
track = track_audio;
@@ -860,14 +871,32 @@ void AnimationTree::_animation_player_changed() {
}
void AnimationTree::_clear_caches() {
+ _clear_audio_streams();
+ _clear_playing_caches();
for (KeyValue<NodePath, TrackCache *> &K : track_cache) {
memdelete(K.value);
}
- playing_caches.clear();
track_cache.clear();
cache_valid = false;
}
+void AnimationTree::_clear_audio_streams() {
+ for (int i = 0; i < playing_audio_stream_players.size(); i++) {
+ playing_audio_stream_players[i]->call(SNAME("stop"));
+ playing_audio_stream_players[i]->call(SNAME("set_stream"), Ref<AudioStream>());
+ }
+ playing_audio_stream_players.clear();
+}
+
+void AnimationTree::_clear_playing_caches() {
+ for (const TrackCache *E : playing_caches) {
+ if (ObjectDB::get_instance(E->object_id)) {
+ E->object->call(SNAME("stop"));
+ }
+ }
+ playing_caches.clear();
+}
+
static void _call_object(Object *p_object, const StringName &p_method, const Vector<Variant> &p_params, bool p_deferred) {
// Separate function to use alloca() more efficiently
const Variant **argptrs = (const Variant **)alloca(sizeof(const Variant **) * p_params.size());
@@ -1007,6 +1036,13 @@ void AnimationTree::_process_graph(double p_delta) {
TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
t->value = t->init_value;
} break;
+ case Animation::TYPE_AUDIO: {
+ TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
+ for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {
+ PlayingAudioTrackInfo &track_info = L.value;
+ track_info.volume = 0.0;
+ }
+ } break;
default: {
} break;
}
@@ -1026,8 +1062,8 @@ void AnimationTree::_process_graph(double p_delta) {
bool seeked = as.seeked;
Animation::LoopedFlag looped_flag = as.looped_flag;
bool is_external_seeking = as.is_external_seeking;
+ bool backward = signbit(delta); // This flag is used by the root motion calculates or detecting the end of audio stream.
#ifndef _3D_DISABLED
- bool backward = signbit(delta); // This flag is required only for the root motion since it calculates the difference between the previous and current frames.
bool calc_root = !seeked || is_external_seeking;
#endif // _3D_DISABLED
@@ -1046,9 +1082,6 @@ void AnimationTree::_process_graph(double p_delta) {
int blend_idx = state.track_map[path];
ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count);
real_t blend = (*as.track_blends)[blend_idx] * weight;
- if (Math::is_zero_approx(blend)) {
- continue; // Nothing to blend.
- }
Animation::TrackType ttype = a->track_get_type(i);
if (ttype != Animation::TYPE_POSITION_3D && ttype != Animation::TYPE_ROTATION_3D && ttype != Animation::TYPE_SCALE_3D && track->type != ttype) {
@@ -1060,6 +1093,9 @@ void AnimationTree::_process_graph(double p_delta) {
switch (ttype) {
case Animation::TYPE_POSITION_3D: {
#ifndef _3D_DISABLED
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
double prev_time = time - delta;
@@ -1151,6 +1187,9 @@ void AnimationTree::_process_graph(double p_delta) {
} break;
case Animation::TYPE_ROTATION_3D: {
#ifndef _3D_DISABLED
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
double prev_time = time - delta;
@@ -1241,6 +1280,9 @@ void AnimationTree::_process_graph(double p_delta) {
} break;
case Animation::TYPE_SCALE_3D: {
#ifndef _3D_DISABLED
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track);
if (track->root_motion && calc_root) {
double prev_time = time - delta;
@@ -1332,6 +1374,9 @@ void AnimationTree::_process_graph(double p_delta) {
} break;
case Animation::TYPE_BLEND_SHAPE: {
#ifndef _3D_DISABLED
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheBlendShape *t = static_cast<TrackCacheBlendShape *>(track);
float value;
@@ -1348,6 +1393,9 @@ void AnimationTree::_process_graph(double p_delta) {
#endif // _3D_DISABLED
} break;
case Animation::TYPE_VALUE: {
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
Animation::UpdateMode update_mode = a->value_track_get_update_mode(i);
@@ -1414,6 +1462,9 @@ void AnimationTree::_process_graph(double p_delta) {
continue;
}
#endif // TOOLS_ENABLED
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);
if (seeked) {
@@ -1435,6 +1486,9 @@ void AnimationTree::_process_graph(double p_delta) {
}
} break;
case Animation::TYPE_BEZIER: {
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track);
real_t bezier = a->bezier_track_interpolate(i, time);
@@ -1445,110 +1499,87 @@ void AnimationTree::_process_graph(double p_delta) {
case Animation::TYPE_AUDIO: {
TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
- if (seeked) {
- int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
- if (idx < 0) {
- continue;
- }
-
- Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
- if (!stream.is_valid()) {
- t->object->call(SNAME("stop"));
- t->playing = false;
- playing_caches.erase(t);
- } else {
- double start_ofs = a->audio_track_get_key_start_offset(i, idx);
- start_ofs += time - a->track_get_key_time(i, idx);
- double end_ofs = a->audio_track_get_key_end_offset(i, idx);
- double len = stream->get_length();
-
- if (start_ofs > len - end_ofs) {
- t->object->call(SNAME("stop"));
- t->playing = false;
- playing_caches.erase(t);
- continue;
- }
-
- t->object->call(SNAME("set_stream"), stream);
- t->object->call(SNAME("play"), start_ofs);
-
- t->playing = true;
- playing_caches.insert(t);
- if (len && end_ofs > 0) { //force an end at a time
- t->len = len - start_ofs - end_ofs;
- } else {
- t->len = 0;
- }
+ Node *asp = Object::cast_to<Node>(t->object);
+ if (!asp) {
+ t->playing_streams.clear();
+ continue;
+ }
- t->start = time;
+ ObjectID oid = a->get_instance_id();
+ if (!t->playing_streams.has(oid)) {
+ t->playing_streams[oid] = PlayingAudioTrackInfo();
+ }
+ // The end of audio should be observed even if the blend value is 0, build up the information and store to the cache for that.
+ PlayingAudioTrackInfo &track_info = t->playing_streams[oid];
+ track_info.length = a->get_length();
+ track_info.time = time;
+ track_info.volume += blend;
+ track_info.loop = a->get_loop_mode() != Animation::LOOP_NONE;
+ track_info.backward = backward;
+ track_info.use_blend = a->audio_track_is_use_blend(i);
+
+ HashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;
+ // Find stream.
+ int idx = -1;
+ if (seeked) {
+ idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
+ // Discard previous stream when seeking.
+ if (map.has(idx)) {
+ t->audio_stream_playback->stop_stream(map[idx].index);
+ map.erase(idx);
}
-
} else {
- //find stuff to play
List<int> to_play;
a->track_get_key_indices_in_range(i, time, delta, &to_play, looped_flag);
if (to_play.size()) {
- int idx = to_play.back()->get();
-
- Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
- if (!stream.is_valid()) {
- t->object->call(SNAME("stop"));
- t->playing = false;
- playing_caches.erase(t);
- } else {
- double start_ofs = a->audio_track_get_key_start_offset(i, idx);
- double end_ofs = a->audio_track_get_key_end_offset(i, idx);
- double len = stream->get_length();
-
- t->object->call(SNAME("set_stream"), stream);
- t->object->call(SNAME("play"), start_ofs);
-
- t->playing = true;
- playing_caches.insert(t);
- if (len && end_ofs > 0) { //force an end at a time
- t->len = len - start_ofs - end_ofs;
- } else {
- t->len = 0;
- }
-
- t->start = time;
- }
- } else if (t->playing) {
- bool loop = a->get_loop_mode() != Animation::LOOP_NONE;
-
- bool stop = false;
-
- if (!loop) {
- if (delta > 0) {
- if (time < t->start) {
- stop = true;
- }
- } else if (delta < 0) {
- if (time > t->start) {
- stop = true;
- }
- }
- } else if (t->len > 0) {
- double len = t->start > time ? (a->get_length() - t->start) + time : time - t->start;
+ idx = to_play.back()->get();
+ }
+ }
+ if (idx < 0) {
+ continue;
+ }
- if (len > t->len) {
- stop = true;
- }
+ // Play stream.
+ Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
+ if (stream.is_valid()) {
+ double start_ofs = a->audio_track_get_key_start_offset(i, idx);
+ double end_ofs = a->audio_track_get_key_end_offset(i, idx);
+ double len = stream->get_length();
+
+ if (t->object->call(SNAME("get_stream")) != t->audio_stream) {
+ t->object->call(SNAME("set_stream"), t->audio_stream);
+ t->audio_stream_playback.unref();
+ if (!playing_audio_stream_players.has(asp)) {
+ playing_audio_stream_players.push_back(asp);
}
+ }
+ if (!t->object->call(SNAME("is_playing"))) {
+ t->object->call(SNAME("play"));
+ }
+ if (!t->object->call(SNAME("has_stream_playback"))) {
+ t->audio_stream_playback.unref();
+ continue;
+ }
+ if (t->audio_stream_playback.is_null()) {
+ t->audio_stream_playback = t->object->call(SNAME("get_stream_playback"));
+ }
- if (stop) {
- //time to stop
- t->object->call(SNAME("stop"));
- t->playing = false;
- playing_caches.erase(t);
- }
+ PlayingAudioStreamInfo pasi;
+ pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs);
+ pasi.start = time;
+ if (len && end_ofs > 0) { // Force an end at a time.
+ pasi.len = len - start_ofs - end_ofs;
+ } else {
+ pasi.len = 0;
}
+ map[idx] = pasi;
}
- real_t db = Math::linear_to_db(MAX(blend, 0.00001));
- t->object->call(SNAME("set_volume_db"), db);
} break;
case Animation::TYPE_ANIMATION: {
+ if (Math::is_zero_approx(blend)) {
+ continue; // Nothing to blend.
+ }
TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track);
AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object);
@@ -1694,6 +1725,64 @@ void AnimationTree::_process_graph(double p_delta) {
t->object->set_indexed(t->subpath, t->value);
} break;
+ case Animation::TYPE_AUDIO: {
+ TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track);
+
+ // Audio ending process.
+ LocalVector<ObjectID> erase_maps;
+ for (KeyValue<ObjectID, PlayingAudioTrackInfo> &L : t->playing_streams) {
+ PlayingAudioTrackInfo &track_info = L.value;
+ float db = Math::linear_to_db(track_info.use_blend ? track_info.volume : 1.0);
+ LocalVector<int> erase_streams;
+ HashMap<int, PlayingAudioStreamInfo> &map = track_info.stream_info;
+ for (const KeyValue<int, PlayingAudioStreamInfo> &M : map) {
+ PlayingAudioStreamInfo pasi = M.value;
+
+ bool stop = false;
+ if (!t->audio_stream_playback->is_stream_playing(pasi.index)) {
+ stop = true;
+ }
+ if (!track_info.loop) {
+ if (!track_info.backward) {
+ if (track_info.time < pasi.start) {
+ stop = true;
+ }
+ } else if (track_info.backward) {
+ if (track_info.time > pasi.start) {
+ stop = true;
+ }
+ }
+ }
+ if (pasi.len > 0) {
+ double len = 0.0;
+ if (!track_info.backward) {
+ len = pasi.start > track_info.time ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start;
+ } else {
+ len = pasi.start < track_info.time ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time;
+ }
+ if (len > pasi.len) {
+ stop = true;
+ }
+ }
+ if (stop) {
+ // Time to stop.
+ t->audio_stream_playback->stop_stream(pasi.index);
+ erase_streams.push_back(M.key);
+ } else {
+ t->audio_stream_playback->set_stream_volume(pasi.index, db);
+ }
+ }
+ for (uint32_t erase_idx = 0; erase_idx < erase_streams.size(); erase_idx++) {
+ map.erase(erase_streams[erase_idx]);
+ }
+ if (map.size() == 0) {
+ erase_maps.push_back(L.key);
+ }
+ }
+ for (uint32_t erase_idx = 0; erase_idx < erase_maps.size(); erase_idx++) {
+ t->playing_streams.erase(erase_maps[erase_idx]);
+ }
+ } break;
default: {
} //the rest don't matter
}
@@ -1772,6 +1861,8 @@ void AnimationTree::_setup_animation_player() {
return;
}
+ cache_valid = false;
+
AnimationPlayer *new_player = nullptr;
if (!animation_player.is_empty()) {
new_player = Object::cast_to<AnimationPlayer>(get_node_or_null(animation_player));
@@ -1819,6 +1910,15 @@ NodePath AnimationTree::get_advance_expression_base_node() const {
return advance_expression_base_node;
}
+void AnimationTree::set_audio_max_polyphony(int p_audio_max_polyphony) {
+ ERR_FAIL_COND(p_audio_max_polyphony < 0 || p_audio_max_polyphony > 128);
+ audio_max_polyphony = p_audio_max_polyphony;
+}
+
+int AnimationTree::get_audio_max_polyphony() const {
+ return audio_max_polyphony;
+}
+
bool AnimationTree::is_state_invalid() const {
return !state.valid;
}
@@ -1984,20 +2084,6 @@ void AnimationTree::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void AnimationTree::rename_parameter(const String &p_base, const String &p_new_base) {
- //rename values first
- for (const PropertyInfo &E : properties) {
- if (E.name.begins_with(p_base)) {
- String new_name = E.name.replace_first(p_base, p_new_base);
- property_map[new_name] = property_map[E.name];
- }
- }
-
- //update tree second
- properties_dirty = true;
- _update_properties();
-}
-
real_t AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const {
if (!input_activity_map_get.has(p_path)) {
return 0;
@@ -2034,14 +2120,15 @@ void AnimationTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_root_motion_track", "path"), &AnimationTree::set_root_motion_track);
ClassDB::bind_method(D_METHOD("get_root_motion_track"), &AnimationTree::get_root_motion_track);
+ ClassDB::bind_method(D_METHOD("set_audio_max_polyphony", "max_polyphony"), &AnimationTree::set_audio_max_polyphony);
+ ClassDB::bind_method(D_METHOD("get_audio_max_polyphony"), &AnimationTree::get_audio_max_polyphony);
+
ClassDB::bind_method(D_METHOD("get_root_motion_position"), &AnimationTree::get_root_motion_position);
ClassDB::bind_method(D_METHOD("get_root_motion_rotation"), &AnimationTree::get_root_motion_rotation);
ClassDB::bind_method(D_METHOD("get_root_motion_scale"), &AnimationTree::get_root_motion_scale);
ClassDB::bind_method(D_METHOD("_update_properties"), &AnimationTree::_update_properties);
- ClassDB::bind_method(D_METHOD("rename_parameter", "old_name", "new_name"), &AnimationTree::rename_parameter);
-
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance);
GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx");
@@ -2052,6 +2139,8 @@ void AnimationTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active");
ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_callback", "get_process_callback");
+ ADD_GROUP("Audio", "audio_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");
ADD_GROUP("Root Motion", "root_motion_");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track");
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index ab538feb58..c5c2790fae 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -35,6 +35,7 @@
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/animation.h"
+#include "scene/resources/audio_stream_polyphonic.h"
class AnimationNodeBlendTree;
class AnimationNodeStartState;
@@ -140,12 +141,12 @@ public:
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking);
virtual String get_caption() const;
+ virtual bool add_input(const String &p_name);
+ virtual void remove_input(int p_index);
+ virtual bool set_input_name(int p_input, const String &p_name);
+ virtual String get_input_name(int p_input) const;
int get_input_count() const;
- String get_input_name(int p_input);
-
- void add_input(const String &p_name);
- void set_input_name(int p_input, const String &p_name);
- void remove_input(int p_index);
+ int find_input(const String &p_name) const;
void set_filter_path(const NodePath &p_path, bool p_enable);
bool is_path_filtered(const NodePath &p_path) const;
@@ -252,10 +253,28 @@ private:
}
};
- struct TrackCacheAudio : public TrackCache {
- bool playing = false;
+ // Audio stream information for each audio stream placed on the track.
+ struct PlayingAudioStreamInfo {
+ AudioStreamPlaybackPolyphonic::ID index = -1; // ID retrieved from AudioStreamPlaybackPolyphonic.
double start = 0.0;
double len = 0.0;
+ };
+
+ // Audio track information for mixng and ending.
+ struct PlayingAudioTrackInfo {
+ HashMap<int, PlayingAudioStreamInfo> stream_info;
+ double length = 0.0;
+ double time = 0.0;
+ real_t volume = 0.0;
+ bool loop = false;
+ bool backward = false;
+ bool use_blend = false;
+ };
+
+ struct TrackCacheAudio : public TrackCache {
+ Ref<AudioStreamPolyphonic> audio_stream;
+ Ref<AudioStreamPlaybackPolyphonic> audio_stream_playback;
+ HashMap<ObjectID, PlayingAudioTrackInfo> playing_streams; // Key is Animation resource ObjectID.
TrackCacheAudio() {
type = Animation::TYPE_AUDIO;
@@ -272,6 +291,7 @@ private:
HashMap<NodePath, TrackCache *> track_cache;
HashSet<TrackCache *> playing_caches;
+ Vector<Node *> playing_audio_stream_players;
Ref<AnimationNode> root;
NodePath advance_expression_base_node = NodePath(String("."));
@@ -279,6 +299,7 @@ private:
AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE;
bool active = false;
NodePath animation_player;
+ int audio_max_polyphony = 32;
AnimationNode::State state;
bool cache_valid = false;
@@ -287,6 +308,8 @@ private:
void _setup_animation_player();
void _animation_player_changed();
void _clear_caches();
+ void _clear_playing_caches();
+ void _clear_audio_streams();
bool _update_caches(AnimationPlayer *player);
void _process_graph(double p_delta);
@@ -348,6 +371,9 @@ public:
void set_advance_expression_base_node(const NodePath &p_advance_expression_base_node);
NodePath get_advance_expression_base_node() const;
+ void set_audio_max_polyphony(int p_audio_max_polyphony);
+ int get_audio_max_polyphony() const;
+
PackedStringArray get_configuration_warnings() const override;
bool is_state_invalid() const;
@@ -363,8 +389,6 @@ public:
real_t get_connection_activity(const StringName &p_path, int p_connection) const;
void advance(double p_time);
- void rename_parameter(const String &p_base, const String &p_new_base);
-
uint64_t get_last_process_pass() const;
AnimationTree();
~AnimationTree();
diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp
index e6b258df3e..3d8d451c70 100644
--- a/scene/animation/root_motion_view.cpp
+++ b/scene/animation/root_motion_view.cpp
@@ -80,7 +80,8 @@ bool RootMotionView::get_zero_y() const {
void RootMotionView::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- immediate_material = StandardMaterial3D::get_material_for_2d(false, true, false, false, false);
+ immediate_material = StandardMaterial3D::get_material_for_2d(false, BaseMaterial3D::TRANSPARENCY_ALPHA, false);
+
first = true;
} break;
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 39d1793368..abc7814877 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -594,7 +594,7 @@ PropertyTweener::PropertyTweener(Object *p_target, NodePath p_property, Variant
}
PropertyTweener::PropertyTweener() {
- ERR_FAIL_MSG("Can't create empty PropertyTweener. Use get_tree().tween_property() or tween_property() instead.");
+ ERR_FAIL_MSG("PropertyTweener can't be created directly. Use the tween_property() method in Tween.");
}
void IntervalTweener::start() {
@@ -625,7 +625,7 @@ IntervalTweener::IntervalTweener(double p_time) {
}
IntervalTweener::IntervalTweener() {
- ERR_FAIL_MSG("Can't create empty IntervalTweener. Use get_tree().tween_interval() instead.");
+ ERR_FAIL_MSG("IntervalTweener can't be created directly. Use the tween_interval() method in Tween.");
}
Ref<CallbackTweener> CallbackTweener::set_delay(double p_delay) {
@@ -676,7 +676,7 @@ CallbackTweener::CallbackTweener(Callable p_callback) {
}
CallbackTweener::CallbackTweener() {
- ERR_FAIL_MSG("Can't create empty CallbackTweener. Use get_tree().tween_callback() instead.");
+ ERR_FAIL_MSG("CallbackTweener can't be created directly. Use the tween_callback() method in Tween.");
}
Ref<MethodTweener> MethodTweener::set_delay(double p_delay) {
@@ -769,5 +769,5 @@ MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to,
}
MethodTweener::MethodTweener() {
- ERR_FAIL_MSG("Can't create empty MethodTweener. Use get_tree().tween_method() instead.");
+ ERR_FAIL_MSG("MethodTweener can't be created directly. Use the tween_method() method in Tween.");
}
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index d40fc10441..7533a56b59 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -307,6 +307,10 @@ void AudioStreamPlayer::_bus_layout_changed() {
notify_property_list_changed();
}
+bool AudioStreamPlayer::has_stream_playback() {
+ return !stream_playbacks.is_empty();
+}
+
Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() {
ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
return stream_playbacks[stream_playbacks.size() - 1];
@@ -347,6 +351,7 @@ void AudioStreamPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_polyphony", "max_polyphony"), &AudioStreamPlayer::set_max_polyphony);
ClassDB::bind_method(D_METHOD("get_max_polyphony"), &AudioStreamPlayer::get_max_polyphony);
+ ClassDB::bind_method(D_METHOD("has_stream_playback"), &AudioStreamPlayer::has_stream_playback);
ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer::get_stream_playback);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index 5368391073..d1f6fca2ee 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -107,6 +107,7 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ bool has_stream_playback();
Ref<AudioStreamPlayback> get_stream_playback();
AudioStreamPlayer();
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index c977d9d2fb..b084cb5bea 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -3088,6 +3088,8 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
}
code_completion_options.append_array(completion_options_casei);
+ code_completion_options.append_array(completion_options_substr);
+ code_completion_options.append_array(completion_options_substr_casei);
code_completion_options.append_array(completion_options_subseq);
code_completion_options.append_array(completion_options_subseq_casei);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index f7c056316d..a930b8d972 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -644,8 +644,10 @@ Rect2 Control::get_parent_anchorable_rect() const {
parent_rect = data.parent_canvas_item->get_anchorable_rect();
} else {
#ifdef TOOLS_ENABLED
- Node *edited_root = get_tree()->get_edited_scene_root();
- if (edited_root && (this == edited_root || edited_root->is_ancestor_of(this))) {
+ Node *edited_scene_root = get_tree()->get_edited_scene_root();
+ Node *scene_root_parent = edited_scene_root ? edited_scene_root->get_parent() : nullptr;
+
+ if (scene_root_parent && get_viewport() == scene_root_parent->get_viewport()) {
parent_rect.size = Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height"));
} else {
parent_rect = get_viewport()->get_visible_rect();
@@ -692,6 +694,12 @@ Transform2D Control::get_transform() const {
return xform;
}
+void Control::_top_level_changed_on_parent() {
+ // Update root control status.
+ _notification(NOTIFICATION_EXIT_CANVAS);
+ _notification(NOTIFICATION_ENTER_CANVAS);
+}
+
/// Anchors and offsets.
void Control::_set_anchor(Side p_side, real_t p_anchor) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index a93a88e5b4..2fb5d559b6 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -292,6 +292,9 @@ private:
void _update_minimum_size();
void _size_changed();
+ void _top_level_changed() override {} // Controls don't need to do anything, only other CanvasItems.
+ void _top_level_changed_on_parent() override;
+
void _clear_size_warning();
// Input events.
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index af52f6664a..fe2eed6755 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -264,10 +264,6 @@ void GraphEdit::_scroll_moved(double) {
top_layer->queue_redraw();
minimap->queue_redraw();
queue_redraw();
-
- if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention
- emit_signal(SNAME("scroll_offset_changed"), get_scroll_ofs());
- }
}
void GraphEdit::_update_scroll_offset() {
@@ -290,6 +286,10 @@ void GraphEdit::_update_scroll_offset() {
connections_layer->set_position(-Point2(h_scroll->get_value(), v_scroll->get_value()));
set_block_minimum_size_adjust(false);
awaiting_scroll_offset_update = false;
+
+ if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention
+ emit_signal(SNAME("scroll_offset_changed"), get_scroll_ofs());
+ }
}
void GraphEdit::_update_scroll() {
@@ -920,7 +920,8 @@ void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from
scaled_points.push_back(points[i] * p_zoom);
}
- p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * get_theme_default_base_scale()), lines_antialiased);
+ // Thickness below 0.5 doesn't look good on the graph or its minimap.
+ p_where->draw_polyline_colors(scaled_points, colors, MAX(0.5, Math::floor(p_width * get_theme_default_base_scale())), lines_antialiased);
}
void GraphEdit::_connections_layer_draw() {
@@ -1088,7 +1089,7 @@ void GraphEdit::_minimap_draw() {
from_color = from_color.lerp(activity_color, E.activity);
to_color = to_color.lerp(activity_color, E.activity);
}
- _draw_connection_line(minimap, from_position, to_position, from_color, to_color, 0.1, minimap->_convert_from_graph_position(Vector2(zoom, zoom)).length());
+ _draw_connection_line(minimap, from_position, to_position, from_color, to_color, 0.5, minimap->_convert_from_graph_position(Vector2(zoom, zoom)).length());
}
// Draw the "camera" viewport.
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index dba08e16cb..16a718722c 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -84,6 +84,7 @@ void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
}
shift_selection_check_post(p_select);
+ _reset_caret_blink_timer();
}
void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
@@ -116,6 +117,7 @@ void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
}
shift_selection_check_post(p_select);
+ _reset_caret_blink_timer();
}
void LineEdit::_move_caret_start(bool p_select) {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index ddc11d97b9..0eeac2f285 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -840,6 +840,9 @@ void PopupMenu::_notification(int p_what) {
float pm_delay = pm->get_submenu_popup_delay();
set_submenu_popup_delay(pm_delay);
}
+ if (!is_embedded()) {
+ set_flag(FLAG_NO_FOCUS, true);
+ }
} break;
case NOTIFICATION_THEME_CHANGED:
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 71ee3c8d0d..f9c9906efa 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1797,7 +1797,9 @@ void RichTextLabel::_notification(int p_what) {
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- queue_redraw();
+ if (is_visible_in_tree()) {
+ queue_redraw();
+ }
} break;
case NOTIFICATION_DRAW: {
@@ -2029,7 +2031,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
}
if (b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) {
- _generate_context_menu();
+ _update_context_menu();
menu->set_position(get_screen_position() + b->get_position());
menu->reset_size();
menu->popup();
@@ -2088,7 +2090,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
}
if (k->is_action("ui_menu", true)) {
if (context_menu_enabled) {
- _generate_context_menu();
+ _update_context_menu();
menu->set_position(get_screen_position());
menu->reset_size();
menu->popup();
@@ -2665,19 +2667,26 @@ bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) {
return false;
}
-void RichTextLabel::_thread_function(void *self) {
- RichTextLabel *rtl = reinterpret_cast<RichTextLabel *>(self);
- rtl->set_physics_process_internal(true);
- rtl->_process_line_caches();
- rtl->set_physics_process_internal(false);
- rtl->updating.store(false);
- rtl->call_deferred(SNAME("queue_redraw"));
+void RichTextLabel::_thread_function(void *p_userdata) {
+ _process_line_caches();
+ updating.store(false);
+ call_deferred(SNAME("thread_end"));
+}
+
+void RichTextLabel::_thread_end() {
+ set_physics_process_internal(false);
+ if (is_visible_in_tree()) {
+ queue_redraw();
+ }
}
void RichTextLabel::_stop_thread() {
if (threaded) {
stop_thread.store(true);
- thread.wait_to_finish();
+ if (task != WorkerThreadPool::INVALID_TASK_ID) {
+ WorkerThreadPool::get_singleton()->wait_for_task_completion(task);
+ task = WorkerThreadPool::INVALID_TASK_ID;
+ }
}
}
@@ -2787,7 +2796,8 @@ bool RichTextLabel::_validate_line_caches() {
if (threaded) {
updating.store(true);
loaded.store(true);
- thread.start(RichTextLabel::_thread_function, reinterpret_cast<void *>(this));
+ task = WorkerThreadPool::get_singleton()->add_template_task(this, &RichTextLabel::_thread_function, nullptr, true, vformat("RichTextLabelShape:%x", (int64_t)get_instance_id()));
+ set_physics_process_internal(true);
loading_started = OS::get_singleton()->get_ticks_msec();
return false;
} else {
@@ -4982,7 +4992,9 @@ bool RichTextLabel::is_shortcut_keys_enabled() const {
// Context menu.
PopupMenu *RichTextLabel::get_menu() const {
- const_cast<RichTextLabel *>(this)->_generate_context_menu();
+ if (!menu) {
+ const_cast<RichTextLabel *>(this)->_generate_context_menu();
+ }
return menu;
}
@@ -5456,6 +5468,9 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_menu"), &RichTextLabel::get_menu);
ClassDB::bind_method(D_METHOD("is_menu_visible"), &RichTextLabel::is_menu_visible);
+ ClassDB::bind_method(D_METHOD("menu_option", "option"), &RichTextLabel::menu_option);
+
+ ClassDB::bind_method(D_METHOD("_thread_end"), &RichTextLabel::_thread_end);
// Note: set "bbcode_enabled" first, to avoid unnecessary "text" resets.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
@@ -5532,6 +5547,10 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(ITEM_HINT);
BIND_ENUM_CONSTANT(ITEM_DROPCAP);
BIND_ENUM_CONSTANT(ITEM_CUSTOMFX);
+
+ BIND_ENUM_CONSTANT(MENU_COPY);
+ BIND_ENUM_CONSTANT(MENU_SELECT_ALL);
+ BIND_ENUM_CONSTANT(MENU_MAX);
}
TextServer::VisibleCharactersBehavior RichTextLabel::get_visible_characters_behavior() const {
@@ -5663,19 +5682,32 @@ Size2 RichTextLabel::get_minimum_size() const {
// Context menu.
void RichTextLabel::_generate_context_menu() {
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu, false, INTERNAL_MODE_FRONT);
+ menu = memnew(PopupMenu);
+ add_child(menu, false, INTERNAL_MODE_FRONT);
+ menu->connect("id_pressed", callable_mp(this, &RichTextLabel::menu_option));
+
+ menu->add_item(RTR("Copy"), MENU_COPY);
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL);
+}
- menu->connect("id_pressed", callable_mp(this, &RichTextLabel::_menu_option));
+void RichTextLabel::_update_context_menu() {
+ if (!menu) {
+ _generate_context_menu();
}
- // Reorganize context menu.
- menu->clear();
- if (selection.enabled) {
- menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : Key::NONE);
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : Key::NONE);
+ int idx = -1;
+
+#define MENU_ITEM_ACTION_DISABLED(m_menu, m_id, m_action, m_disabled) \
+ idx = m_menu->get_item_index(m_id); \
+ if (idx >= 0) { \
+ m_menu->set_item_accelerator(idx, shortcut_keys_enabled ? _get_menu_action_accelerator(m_action) : Key::NONE); \
+ m_menu->set_item_disabled(idx, m_disabled); \
}
+
+ MENU_ITEM_ACTION_DISABLED(menu, MENU_COPY, "ui_copy", !selection.enabled)
+ MENU_ITEM_ACTION_DISABLED(menu, MENU_SELECT_ALL, "ui_text_select_all", !selection.enabled)
+
+#undef MENU_ITEM_ACTION_DISABLED
}
Key RichTextLabel::_get_menu_action_accelerator(const String &p_action) {
@@ -5703,7 +5735,7 @@ Key RichTextLabel::_get_menu_action_accelerator(const String &p_action) {
}
}
-void RichTextLabel::_menu_option(int p_option) {
+void RichTextLabel::menu_option(int p_option) {
switch (p_option) {
case MENU_COPY: {
selection_copy();
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 58b82d4672..b01fccf14c 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -31,6 +31,7 @@
#ifndef RICH_TEXT_LABEL_H
#define RICH_TEXT_LABEL_H
+#include "core/object/worker_thread_pool.h"
#include "rich_text_effect.h"
#include "scene/gui/popup_menu.h"
#include "scene/gui/scroll_bar.h"
@@ -80,6 +81,7 @@ public:
enum MenuItems {
MENU_COPY,
MENU_SELECT_ALL,
+ MENU_MAX
};
enum DefaultFont {
@@ -369,7 +371,7 @@ private:
Item *current = nullptr;
ItemFrame *current_frame = nullptr;
- Thread thread;
+ WorkerThreadPool::TaskID task = WorkerThreadPool::INVALID_TASK_ID;
Mutex data_mutex;
bool threaded = false;
std::atomic<bool> stop_thread;
@@ -409,7 +411,8 @@ private:
void _invalidate_current_line(ItemFrame *p_frame);
- static void _thread_function(void *self);
+ void _thread_function(void *p_userdata);
+ void _thread_end();
void _stop_thread();
bool _validate_line_caches();
void _process_line_caches();
@@ -452,8 +455,8 @@ private:
// Context menu.
PopupMenu *menu = nullptr;
void _generate_context_menu();
+ void _update_context_menu();
Key _get_menu_action_accelerator(const String &p_action);
- void _menu_option(int p_option);
int visible_characters = -1;
float visible_ratio = 1.0;
@@ -686,6 +689,7 @@ public:
// Context menu.
PopupMenu *get_menu() const;
bool is_menu_visible() const;
+ void menu_option(int p_option);
void parse_bbcode(const String &p_bbcode);
void append_text(const String &p_bbcode);
@@ -737,5 +741,6 @@ public:
VARIANT_ENUM_CAST(RichTextLabel::ListType);
VARIANT_ENUM_CAST(RichTextLabel::ItemType);
+VARIANT_ENUM_CAST(RichTextLabel::MenuItems);
#endif // RICH_TEXT_LABEL_H
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index ead9550b93..0c0125df76 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -115,7 +115,7 @@ void SplitContainerDragger::_notification(int p_what) {
return;
}
- Ref<Texture2D> tex = sc->get_theme_icon(SNAME("grabber"));
+ Ref<Texture2D> tex = sc->_get_grabber_icon();
draw_texture(tex, (get_size() - tex->get_size()) / 2);
} break;
}
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 7c1d2f95a9..f10e1c2cd1 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -85,7 +85,7 @@ void SubViewportContainer::set_stretch_shrink(int p_shrink) {
continue;
}
- c->set_size(get_size() / shrink);
+ c->set_size_force(get_size() / shrink);
}
queue_redraw();
@@ -116,7 +116,7 @@ void SubViewportContainer::_notification(int p_what) {
continue;
}
- c->set_size(get_size() / shrink);
+ c->set_size_force(get_size() / shrink);
}
} break;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index d9e6157489..0f39715851 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -5256,7 +5256,6 @@ void Tree::_bind_methods() {
ADD_SIGNAL(MethodInfo("empty_clicked", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("item_edited"));
ADD_SIGNAL(MethodInfo("custom_item_clicked", PropertyInfo(Variant::INT, "mouse_button_index")));
- ADD_SIGNAL(MethodInfo("item_custom_button_pressed"));
ADD_SIGNAL(MethodInfo("item_icon_double_clicked"));
ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem")));
ADD_SIGNAL(MethodInfo("check_propagated_to_item", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column")));
diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index 6eb25bf852..1f3bbff779 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -236,7 +236,6 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) {
AudioServer::get_singleton()->unlock();
if (!playback.is_null()) {
- playback->set_loop(loops);
playback->set_paused(paused);
texture = playback->get_texture();
@@ -344,6 +343,12 @@ int VideoStreamPlayer::get_buffering_msec() const {
void VideoStreamPlayer::set_audio_track(int p_track) {
audio_track = p_track;
+ if (stream.is_valid()) {
+ stream->set_audio_track(audio_track);
+ }
+ if (playback.is_valid()) {
+ playback->set_audio_track(audio_track);
+ }
}
int VideoStreamPlayer::get_audio_track() const {
diff --git a/scene/gui/video_stream_player.h b/scene/gui/video_stream_player.h
index 09ef272a9a..1fd599a9e1 100644
--- a/scene/gui/video_stream_player.h
+++ b/scene/gui/video_stream_player.h
@@ -65,7 +65,6 @@ class VideoStreamPlayer : public Control {
float volume = 1.0;
double last_audio_time = 0.0;
bool expand = false;
- bool loops = false;
int buffering_ms = 500;
int audio_track = 0;
int bus_index = 0;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 3323c0f848..906b478eb3 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -185,7 +185,7 @@ void CanvasItem::_top_level_raise_self() {
}
void CanvasItem::_enter_canvas() {
- // Resolves to nullptr if the node is toplevel.
+ // Resolves to nullptr if the node is top_level.
CanvasItem *parent_item = get_parent_item();
if (parent_item) {
@@ -400,11 +400,28 @@ void CanvasItem::set_as_top_level(bool p_top_level) {
_exit_canvas();
top_level = p_top_level;
+ _top_level_changed();
_enter_canvas();
_notify_transform();
}
+void CanvasItem::_top_level_changed() {
+ // Inform children that top_level status has changed on a parent.
+ int children = get_child_count();
+ for (int i = 0; i < children; i++) {
+ CanvasItem *child = Object::cast_to<CanvasItem>(get_child(i));
+ if (child) {
+ child->_top_level_changed_on_parent();
+ }
+ }
+}
+
+void CanvasItem::_top_level_changed_on_parent() {
+ // Inform children that top_level status has changed on a parent.
+ _top_level_changed();
+}
+
bool CanvasItem::is_set_as_top_level() const {
return top_level;
}
@@ -474,6 +491,17 @@ int CanvasItem::get_z_index() const {
return z_index;
}
+int CanvasItem::get_effective_z_index() const {
+ int effective_z_index = z_index;
+ if (is_z_relative()) {
+ CanvasItem *p = get_parent_item();
+ if (p) {
+ effective_z_index += p->get_effective_z_index();
+ }
+ }
+ return effective_z_index;
+}
+
void CanvasItem::set_y_sort_enabled(bool p_enabled) {
y_sort_enabled = p_enabled;
RS::get_singleton()->canvas_item_set_sort_children_by_y(canvas_item, y_sort_enabled);
@@ -917,6 +945,12 @@ void CanvasItem::force_update_transform() {
notification(NOTIFICATION_TRANSFORM_CHANGED);
}
+void CanvasItem::_validate_property(PropertyInfo &p_property) const {
+ if (hide_clip_children && p_property.name == "clip_children") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self);
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 644fe856ec..5fbf043159 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -106,6 +106,7 @@ private:
bool use_parent_material = false;
bool notify_local_transform = false;
bool notify_transform = false;
+ bool hide_clip_children = false;
ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED;
@@ -124,6 +125,9 @@ private:
void _propagate_visibility_changed(bool p_parent_visible_in_tree);
void _handle_visibility_change(bool p_visible);
+ virtual void _top_level_changed();
+ virtual void _top_level_changed_on_parent();
+
void _redraw_callback();
void _enter_canvas();
@@ -155,6 +159,9 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
+
+ _FORCE_INLINE_ void set_hide_clip_children(bool p_value) { hide_clip_children = p_value; }
GDVIRTUAL0(_draw)
public:
@@ -239,6 +246,7 @@ public:
void set_z_index(int p_z);
int get_z_index() const;
+ int get_effective_z_index() const;
void set_z_as_relative(bool p_enabled);
bool is_z_relative() const;
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 46ba7e67eb..0d53f740db 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -33,7 +33,7 @@
#include "scene/main/timer.h"
Error HTTPRequest::_request() {
- return client->connect_to_host(url, port, use_tls, validate_tls);
+ return client->connect_to_host(url, port, use_tls ? tls_options : nullptr);
}
Error HTTPRequest::_parse_url(const String &p_url) {
@@ -96,7 +96,7 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S
return value;
}
-Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const String &p_request_data) {
+Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, HTTPClient::Method p_method, const String &p_request_data) {
// Copy the string into a raw buffer.
Vector<uint8_t> raw_data;
@@ -108,10 +108,10 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
memcpy(w, charstr.ptr(), len);
}
- return request_raw(p_url, p_custom_headers, p_tls_validate_domain, p_method, raw_data);
+ return request_raw(p_url, p_custom_headers, p_method, raw_data);
}
-Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
+Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) {
ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(requesting, ERR_BUSY, "HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one.");
@@ -127,8 +127,6 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
return err;
}
- validate_tls = p_tls_validate_domain;
-
headers = p_custom_headers;
if (accept_gzip) {
@@ -590,10 +588,16 @@ void HTTPRequest::_timeout() {
_defer_done(RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
}
+void HTTPRequest::set_tls_options(const Ref<TLSOptions> &p_options) {
+ ERR_FAIL_COND(p_options.is_null() || p_options->is_server());
+ tls_options = p_options;
+}
+
void HTTPRequest::_bind_methods() {
- ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "tls_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
- ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "tls_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
+ ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String()));
+ ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray()));
ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request);
+ ClassDB::bind_method(D_METHOD("set_tls_options", "client_options"), &HTTPRequest::set_tls_options);
ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status);
@@ -654,6 +658,7 @@ void HTTPRequest::_bind_methods() {
HTTPRequest::HTTPRequest() {
client = Ref<HTTPClient>(HTTPClient::create());
+ tls_options = TLSOptions::client();
timer = memnew(Timer);
timer->set_one_shot(true);
timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout));
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index add4e9538d..9a91171eaf 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -68,8 +68,8 @@ private:
String url;
int port = 80;
Vector<String> headers;
- bool validate_tls = false;
bool use_tls = false;
+ Ref<TLSOptions> tls_options;
HTTPClient::Method method;
Vector<uint8_t> request_data;
@@ -125,8 +125,8 @@ protected:
static void _bind_methods();
public:
- Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
- Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
+ Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request
+ Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request
void cancel_request();
HTTPClient::Status get_http_client_status() const;
@@ -161,6 +161,8 @@ public:
void set_http_proxy(const String &p_host, int p_port);
void set_https_proxy(const String &p_host, int p_port);
+ void set_tls_options(const Ref<TLSOptions> &p_options);
+
HTTPRequest();
};
diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp
index c54e61580f..950eb2809c 100644
--- a/scene/main/multiplayer_api.cpp
+++ b/scene/main/multiplayer_api.cpp
@@ -329,9 +329,9 @@ void MultiplayerAPI::_bind_methods() {
/// MultiplayerAPIExtension
Error MultiplayerAPIExtension::poll() {
- int err = OK;
+ Error err = OK;
GDVIRTUAL_CALL(_poll, err);
- return (Error)err;
+ return err;
}
void MultiplayerAPIExtension::set_multiplayer_peer(const Ref<MultiplayerPeer> &p_peer) {
@@ -364,9 +364,9 @@ Error MultiplayerAPIExtension::rpcp(Object *p_obj, int p_peer_id, const StringNa
for (int i = 0; i < p_argcount; i++) {
args.push_back(*p_arg[i]);
}
- int ret = FAILED;
+ Error ret = FAILED;
GDVIRTUAL_CALL(_rpc, p_peer_id, p_obj, p_method, args, ret);
- return (Error)ret;
+ return ret;
}
int MultiplayerAPIExtension::get_remote_sender_id() {
@@ -376,15 +376,15 @@ int MultiplayerAPIExtension::get_remote_sender_id() {
}
Error MultiplayerAPIExtension::object_configuration_add(Object *p_object, Variant p_config) {
- int err = ERR_UNAVAILABLE;
+ Error err = ERR_UNAVAILABLE;
GDVIRTUAL_CALL(_object_configuration_add, p_object, p_config, err);
- return (Error)err;
+ return err;
}
Error MultiplayerAPIExtension::object_configuration_remove(Object *p_object, Variant p_config) {
- int err = ERR_UNAVAILABLE;
+ Error err = ERR_UNAVAILABLE;
GDVIRTUAL_CALL(_object_configuration_remove, p_object, p_config, err);
- return (Error)err;
+ return err;
}
void MultiplayerAPIExtension::_bind_methods() {
diff --git a/scene/main/multiplayer_api.h b/scene/main/multiplayer_api.h
index 0b107ee50b..a578e6f2f1 100644
--- a/scene/main/multiplayer_api.h
+++ b/scene/main/multiplayer_api.h
@@ -101,15 +101,15 @@ public:
virtual Error object_configuration_remove(Object *p_object, Variant p_config) override;
// Extensions
- GDVIRTUAL0R(int, _poll);
+ GDVIRTUAL0R(Error, _poll);
GDVIRTUAL1(_set_multiplayer_peer, Ref<MultiplayerPeer>);
GDVIRTUAL0R(Ref<MultiplayerPeer>, _get_multiplayer_peer);
GDVIRTUAL0RC(int, _get_unique_id);
GDVIRTUAL0RC(PackedInt32Array, _get_peer_ids);
- GDVIRTUAL4R(int, _rpc, int, Object *, StringName, Array);
+ GDVIRTUAL4R(Error, _rpc, int, Object *, StringName, Array);
GDVIRTUAL0RC(int, _get_remote_sender_id);
- GDVIRTUAL2R(int, _object_configuration_add, Object *, Variant);
- GDVIRTUAL2R(int, _object_configuration_remove, Object *, Variant);
+ GDVIRTUAL2R(Error, _object_configuration_add, Object *, Variant);
+ GDVIRTUAL2R(Error, _object_configuration_remove, Object *, Variant);
};
#endif // MULTIPLAYER_API_H
diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp
index 83555966d7..f3e56a1455 100644
--- a/scene/main/multiplayer_peer.cpp
+++ b/scene/main/multiplayer_peer.cpp
@@ -163,7 +163,7 @@ Error MultiplayerPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer
if (!GDVIRTUAL_CALL(_put_packet_script, a, err)) {
return FAILED;
}
- return (Error)err;
+ return err;
}
WARN_PRINT_ONCE("MultiplayerPeerExtension::_put_packet_native is unimplemented!");
return FAILED;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index de486094fe..52c1df8110 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -1987,7 +1987,16 @@ String Node::get_scene_file_path() const {
}
void Node::set_editor_description(const String &p_editor_description) {
+ if (data.editor_description == p_editor_description) {
+ return;
+ }
+
data.editor_description = p_editor_description;
+
+ if (Engine::get_singleton()->is_editor_hint() && is_inside_tree()) {
+ // Update tree so the tooltip in the Scene tree dock is also updated in the editor.
+ get_tree()->tree_changed();
+ }
}
String Node::get_editor_description() const {
@@ -2126,13 +2135,13 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c
} else if ((p_flags & DUPLICATE_USE_INSTANTIATION) && !get_scene_file_path().is_empty()) {
Ref<PackedScene> res = ResourceLoader::load(get_scene_file_path());
ERR_FAIL_COND_V(res.is_null(), nullptr);
- PackedScene::GenEditState ges = PackedScene::GEN_EDIT_STATE_DISABLED;
+ PackedScene::GenEditState edit_state = PackedScene::GEN_EDIT_STATE_DISABLED;
#ifdef TOOLS_ENABLED
if (p_flags & DUPLICATE_FROM_EDITOR) {
- ges = PackedScene::GEN_EDIT_STATE_INSTANCE;
+ edit_state = PackedScene::GEN_EDIT_STATE_INSTANCE;
}
#endif
- node = res->instantiate(ges);
+ node = res->instantiate(edit_state);
ERR_FAIL_COND_V(!node, nullptr);
node->set_scene_instance_load_placeholder(get_scene_instance_load_placeholder());
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 48cff5aa8e..7091dd0388 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -36,6 +36,7 @@
#include "core/object/message_queue.h"
#include "core/string/translation.h"
#include "core/templates/pair.h"
+#include "core/templates/sort_array.h"
#include "scene/2d/audio_listener_2d.h"
#include "scene/2d/camera_2d.h"
#include "scene/2d/collision_object_2d.h"
@@ -524,7 +525,12 @@ void Viewport::_process_picking() {
if (!physics_object_picking) {
return;
}
- if (to_screen_rect != Rect2i() && Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
+ if (Object::cast_to<Window>(this) && Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) {
+ return;
+ }
+ if (!gui.mouse_in_viewport) {
+ // Clear picking events if mouse has left viewport.
+ physics_picking_events.clear();
return;
}
@@ -664,6 +670,25 @@ void Viewport::_process_picking() {
point_params.pick_point = true;
int rc = ss2d->intersect_point(point_params, res, 64);
+ if (physics_object_picking_sort) {
+ struct ComparatorCollisionObjects {
+ bool operator()(const PhysicsDirectSpaceState2D::ShapeResult &p_a, const PhysicsDirectSpaceState2D::ShapeResult &p_b) const {
+ CollisionObject2D *a = Object::cast_to<CollisionObject2D>(p_a.collider);
+ CollisionObject2D *b = Object::cast_to<CollisionObject2D>(p_b.collider);
+ if (!a || !b) {
+ return false;
+ }
+ int za = a->get_effective_z_index();
+ int zb = b->get_effective_z_index();
+ if (za != zb) {
+ return zb < za;
+ }
+ return a->is_greater_than(b);
+ }
+ };
+ SortArray<PhysicsDirectSpaceState2D::ShapeResult, ComparatorCollisionObjects> sorter;
+ sorter.sort(res, rc);
+ }
for (int i = 0; i < rc; i++) {
if (res[i].collider_id.is_valid() && res[i].collider) {
CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider);
@@ -791,16 +816,21 @@ void Viewport::update_canvas_items() {
_update_canvas_items(this);
}
-void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) {
- if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect == p_to_screen_rect) {
+void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated) {
+ Transform2D stretch_transform_new = Transform2D();
+ if (is_size_2d_override_stretch_enabled() && p_size_2d_override.width > 0 && p_size_2d_override.height > 0) {
+ Size2 scale = Size2(p_size) / Size2(p_size_2d_override);
+ stretch_transform_new.scale(scale);
+ }
+
+ if (size == p_size && size_allocated == p_allocated && stretch_transform == stretch_transform_new && p_size_2d_override == size_2d_override) {
return;
}
size = p_size;
size_allocated = p_allocated;
size_2d_override = p_size_2d_override;
- stretch_transform = p_stretch_transform;
- to_screen_rect = p_to_screen_rect;
+ stretch_transform = stretch_transform_new;
#ifndef _3D_DISABLED
if (!use_xr) {
@@ -1042,7 +1072,30 @@ Camera2D *Viewport::get_camera_2d() const {
}
Transform2D Viewport::get_final_transform() const {
- return _get_input_pre_xform().affine_inverse() * stretch_transform * global_canvas_transform;
+ return stretch_transform * global_canvas_transform;
+}
+
+void Viewport::assign_next_enabled_camera_2d(const StringName &p_camera_group) {
+ List<Node *> camera_list;
+ get_tree()->get_nodes_in_group(p_camera_group, &camera_list);
+
+ Camera2D *new_camera = nullptr;
+ for (Node *E : camera_list) {
+ Camera2D *cam = Object::cast_to<Camera2D>(E);
+ if (!cam) {
+ continue; // Non-camera node (e.g. ParallaxBackground).
+ }
+
+ if (cam->is_enabled()) {
+ new_camera = cam;
+ break;
+ }
+ }
+
+ _camera_2d_set(new_camera);
+ if (!camera_2d) {
+ set_canvas_transform(Transform2D());
+ }
}
void Viewport::_update_canvas_items(Node *p_node) {
@@ -1109,17 +1162,6 @@ Viewport::PositionalShadowAtlasQuadrantSubdiv Viewport::get_positional_shadow_at
return positional_shadow_atlas_quadrant_subdiv[p_quadrant];
}
-Transform2D Viewport::_get_input_pre_xform() const {
- Transform2D pre_xf;
-
- if (to_screen_rect.size.x != 0 && to_screen_rect.size.y != 0) {
- pre_xf.columns[2] = -to_screen_rect.position;
- pre_xf.scale(Vector2(size) / to_screen_rect.size);
- }
-
- return pre_xf;
-}
-
Ref<InputEvent> Viewport::_make_input_local(const Ref<InputEvent> &ev) {
if (ev.is_null()) {
return ev; // No transformation defined for null event
@@ -2842,6 +2884,14 @@ bool Viewport::get_physics_object_picking() {
return physics_object_picking;
}
+void Viewport::set_physics_object_picking_sort(bool p_enable) {
+ physics_object_picking_sort = p_enable;
+}
+
+bool Viewport::get_physics_object_picking_sort() {
+ return physics_object_picking_sort;
+}
+
Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
Transform2D xf = stretch_transform * global_canvas_transform;
return xf.xform(p_viewport_coords);
@@ -3776,6 +3826,8 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_physics_object_picking", "enable"), &Viewport::set_physics_object_picking);
ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
+ ClassDB::bind_method(D_METHOD("set_physics_object_picking_sort", "enable"), &Viewport::set_physics_object_picking_sort);
+ ClassDB::bind_method(D_METHOD("get_physics_object_picking_sort"), &Viewport::get_physics_object_picking_sort);
ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid);
ClassDB::bind_method(D_METHOD("push_text_input", "text"), &Viewport::push_text_input);
@@ -3927,6 +3979,7 @@ void Viewport::_bind_methods() {
#endif
ADD_GROUP("Physics", "physics_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking"), "set_physics_object_picking", "get_physics_object_picking");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_object_picking_sort"), "set_physics_object_picking_sort", "get_physics_object_picking_sort");
ADD_GROUP("GUI", "gui_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_disable_input"), "set_disable_input", "is_input_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gui_snap_controls_to_pixels"), "set_snap_controls_to_pixels", "is_snap_controls_to_pixels_enabled");
@@ -4098,9 +4151,26 @@ Viewport::~Viewport() {
/////////////////////////////////
void SubViewport::set_size(const Size2i &p_size) {
- _set_size(p_size, _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
+ _internal_set_size(p_size);
+}
+
+void SubViewport::set_size_force(const Size2i &p_size) {
+ // Use only for setting the size from the parent SubViewportContainer with enabled stretch mode.
+ // Don't expose function to scripting.
+ _internal_set_size(p_size, true);
+}
+void SubViewport::_internal_set_size(const Size2i &p_size, bool p_force) {
SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
+ if (!p_force && c && c->is_stretch_enabled()) {
+#ifdef DEBUG_ENABLED
+ WARN_PRINT("Can't change the size of a `SubViewport` with a `SubViewportContainer` parent that has `stretch` enabled. Set `SubViewportContainer.stretch` to `false` to allow changing the size manually.");
+#endif // DEBUG_ENABLED
+ return;
+ }
+
+ _set_size(p_size, _get_size_2d_override(), true);
+
if (c) {
c->update_minimum_size();
}
@@ -4111,7 +4181,7 @@ Size2i SubViewport::get_size() const {
}
void SubViewport::set_size_2d_override(const Size2i &p_size) {
- _set_size(_get_size(), p_size, Rect2i(), _stretch_transform(), true);
+ _set_size(_get_size(), p_size, true);
}
Size2i SubViewport::get_size_2d_override() const {
@@ -4124,7 +4194,7 @@ void SubViewport::set_size_2d_override_stretch(bool p_enable) {
}
size_2d_override_stretch = p_enable;
- _set_size(_get_size(), _get_size_2d_override(), Rect2i(), _stretch_transform(), true);
+ _set_size(_get_size(), _get_size_2d_override(), true);
}
bool SubViewport::is_size_2d_override_stretch_enabled() const {
@@ -4153,17 +4223,6 @@ DisplayServer::WindowID SubViewport::get_window_id() const {
return DisplayServer::INVALID_WINDOW_ID;
}
-Transform2D SubViewport::_stretch_transform() {
- Transform2D transform;
- Size2i view_size_2d_override = _get_size_2d_override();
- if (size_2d_override_stretch && view_size_2d_override.width > 0 && view_size_2d_override.height > 0) {
- Size2 scale = Size2(_get_size()) / Size2(view_size_2d_override);
- transform.scale(scale);
- }
-
- return transform;
-}
-
Transform2D SubViewport::get_screen_transform() const {
Transform2D container_transform;
SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
@@ -4175,7 +4234,7 @@ Transform2D SubViewport::get_screen_transform() const {
} else {
WARN_PRINT_ONCE("SubViewport is not a child of a SubViewportContainer. get_screen_transform doesn't return the actual screen position.");
}
- return container_transform * Viewport::get_screen_transform();
+ return container_transform * get_final_transform();
}
Transform2D SubViewport::get_popup_base_transform() const {
@@ -4184,13 +4243,13 @@ Transform2D SubViewport::get_popup_base_transform() const {
}
SubViewportContainer *c = Object::cast_to<SubViewportContainer>(get_parent());
if (!c) {
- return Viewport::get_screen_transform();
+ return get_final_transform();
}
Transform2D container_transform;
if (c->is_stretch_enabled()) {
container_transform.scale(Vector2(c->get_stretch_shrink(), c->get_stretch_shrink()));
}
- return c->get_screen_transform() * container_transform * Viewport::get_screen_transform();
+ return c->get_screen_transform() * container_transform * get_final_transform();
}
void SubViewport::_notification(int p_what) {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index d5d5201e9a..4144eaabb9 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -246,6 +246,7 @@ private:
bool snap_2d_vertices_to_pixel = false;
bool physics_object_picking = false;
+ bool physics_object_picking_sort = false;
List<Ref<InputEvent>> physics_picking_events;
ObjectID physics_object_capture;
ObjectID physics_object_over;
@@ -275,7 +276,6 @@ private:
Ref<World2D> world_2d;
- Rect2i to_screen_rect;
StringName input_group;
StringName gui_input_group;
StringName shortcut_input_group;
@@ -408,8 +408,6 @@ private:
void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2());
void _gui_cleanup_internal_state(Ref<InputEvent> p_event);
- _FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
-
Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev);
friend class Control;
@@ -471,7 +469,7 @@ private:
uint64_t event_count = 0;
protected:
- void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated);
+ void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, bool p_allocated);
Size2i _get_size() const;
Size2i _get_size_2d_override() const;
@@ -510,7 +508,8 @@ public:
void set_global_canvas_transform(const Transform2D &p_transform);
Transform2D get_global_canvas_transform() const;
- Transform2D get_final_transform() const;
+ virtual Transform2D get_final_transform() const;
+ void assign_next_enabled_camera_2d(const StringName &p_camera_group);
void gui_set_root_order_dirty();
@@ -576,6 +575,8 @@ public:
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
+ void set_physics_object_picking_sort(bool p_enable);
+ bool get_physics_object_picking_sort();
Variant gui_get_drag_data() const;
@@ -648,6 +649,8 @@ public:
void set_canvas_cull_mask_bit(uint32_t p_layer, bool p_enable);
bool get_canvas_cull_mask_bit(uint32_t p_layer) const;
+ virtual bool is_size_2d_override_stretch_enabled() const { return true; }
+
virtual Transform2D get_screen_transform() const;
virtual Transform2D get_popup_base_transform() const { return Transform2D(); }
@@ -753,21 +756,23 @@ private:
ClearMode clear_mode = CLEAR_MODE_ALWAYS;
bool size_2d_override_stretch = false;
+ void _internal_set_size(const Size2i &p_size, bool p_force = false);
+
protected:
static void _bind_methods();
virtual DisplayServer::WindowID get_window_id() const override;
- Transform2D _stretch_transform();
void _notification(int p_what);
public:
void set_size(const Size2i &p_size);
Size2i get_size() const;
+ void set_size_force(const Size2i &p_size);
void set_size_2d_override(const Size2i &p_size);
Size2i get_size_2d_override() const;
void set_size_2d_override_stretch(bool p_enable);
- bool is_size_2d_override_stretch_enabled() const;
+ bool is_size_2d_override_stretch_enabled() const override;
void set_update_mode(UpdateMode p_mode);
UpdateMode get_update_mode() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 869d12b4df..33946246b0 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -905,16 +905,13 @@ void Window::_update_viewport_size() {
Size2i final_size;
Size2i final_size_override;
Rect2i attach_to_screen_rect(Point2i(), size);
- Transform2D stretch_transform_new;
float font_oversampling = 1.0;
+ window_transform = Transform2D();
if (content_scale_mode == CONTENT_SCALE_MODE_DISABLED || content_scale_size.x == 0 || content_scale_size.y == 0) {
font_oversampling = content_scale_factor;
final_size = size;
final_size_override = Size2(size) / content_scale_factor;
-
- stretch_transform_new = Transform2D();
- stretch_transform_new.scale(Size2(content_scale_factor, content_scale_factor));
} else {
//actual screen video mode
Size2 video_mode = size;
@@ -990,20 +987,24 @@ void Window::_update_viewport_size() {
attach_to_screen_rect = Rect2(margin, screen_size);
font_oversampling = (screen_size.x / viewport_size.x) * content_scale_factor;
- Size2 scale = Vector2(screen_size) / Vector2(final_size_override);
- stretch_transform_new.scale(scale);
-
+ window_transform.translate_local(margin);
} break;
case CONTENT_SCALE_MODE_VIEWPORT: {
final_size = (viewport_size / content_scale_factor).floor();
attach_to_screen_rect = Rect2(margin, screen_size);
+ window_transform.translate_local(margin);
+ if (final_size.x != 0 && final_size.y != 0) {
+ Transform2D scale_transform;
+ scale_transform.scale(Vector2(attach_to_screen_rect.size) / Vector2(final_size));
+ window_transform *= scale_transform;
+ }
} break;
}
}
bool allocate = is_inside_tree() && visible && (window_id != DisplayServer::INVALID_WINDOW_ID || embedder != nullptr);
- _set_size(final_size, final_size_override, attach_to_screen_rect, stretch_transform_new, allocate);
+ _set_size(final_size, final_size_override, allocate);
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
RenderingServer::get_singleton()->viewport_attach_to_screen(get_viewport_rid(), attach_to_screen_rect, window_id);
@@ -2114,26 +2115,30 @@ bool Window::is_auto_translating() const {
return auto_translate;
}
+Transform2D Window::get_final_transform() const {
+ return window_transform * stretch_transform * global_canvas_transform;
+}
+
Transform2D Window::get_screen_transform() const {
Transform2D embedder_transform;
if (_get_embedder()) {
embedder_transform.translate_local(get_position());
embedder_transform = _get_embedder()->get_screen_transform() * embedder_transform;
}
- return embedder_transform * Viewport::get_screen_transform();
+ return embedder_transform * get_final_transform();
}
Transform2D Window::get_popup_base_transform() const {
if (is_embedding_subwindows()) {
return Transform2D();
}
- Transform2D window_transform;
- window_transform.set_origin(get_position());
- window_transform *= Viewport::get_screen_transform();
+ Transform2D popup_base_transform;
+ popup_base_transform.set_origin(get_position());
+ popup_base_transform *= get_final_transform();
if (_get_embedder()) {
- return _get_embedder()->get_popup_base_transform() * window_transform;
+ return _get_embedder()->get_popup_base_transform() * popup_base_transform;
}
- return window_transform;
+ return popup_base_transform;
}
void Window::_bind_methods() {
@@ -2336,6 +2341,7 @@ void Window::_bind_methods() {
ADD_SIGNAL(MethodInfo("visibility_changed"));
ADD_SIGNAL(MethodInfo("about_to_popup"));
ADD_SIGNAL(MethodInfo("theme_changed"));
+ ADD_SIGNAL(MethodInfo("dpi_changed"));
ADD_SIGNAL(MethodInfo("titlebar_changed"));
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
diff --git a/scene/main/window.h b/scene/main/window.h
index 182caf5f0c..9861fefc68 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -173,6 +173,8 @@ private:
Viewport *embedder = nullptr;
+ Transform2D window_transform;
+
friend class Viewport; //friend back, can call the methods below
void _window_input(const Ref<InputEvent> &p_ev);
@@ -374,6 +376,7 @@ public:
//
+ virtual Transform2D get_final_transform() const override;
virtual Transform2D get_screen_transform() const override;
virtual Transform2D get_popup_base_transform() const override;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 7bebf1cfd3..39fc03f9f1 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -393,6 +393,8 @@ void register_scene_types() {
GDREGISTER_CLASS(LineEdit);
GDREGISTER_CLASS(VideoStreamPlayer);
+ GDREGISTER_VIRTUAL_CLASS(VideoStreamPlayback);
+ GDREGISTER_VIRTUAL_CLASS(VideoStream);
#ifndef ADVANCED_GUI_DISABLED
GDREGISTER_CLASS(FileDialog);
@@ -906,7 +908,6 @@ void register_scene_types() {
#ifndef _3D_DISABLED
GDREGISTER_CLASS(AudioStreamPlayer3D);
#endif
- GDREGISTER_ABSTRACT_CLASS(VideoStream);
GDREGISTER_CLASS(AudioStreamWAV);
GDREGISTER_CLASS(AudioStreamPolyphonic);
GDREGISTER_ABSTRACT_CLASS(AudioStreamPlaybackPolyphonic);
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index cb3c865f05..bfbc92a8d4 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -127,6 +127,10 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
}
}
return true;
+ } else if (what == "use_blend") {
+ if (track_get_type(track) == TYPE_AUDIO) {
+ audio_track_set_use_blend(track, p_value);
+ }
} else if (what == "interp") {
track_set_interpolation_type(track, InterpolationType(p_value.operator int()));
} else if (what == "loop_wrap") {
@@ -528,7 +532,10 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
}
return true;
-
+ } else if (what == "use_blend") {
+ if (track_get_type(track) == TYPE_AUDIO) {
+ r_ret = audio_track_is_use_blend(track);
+ }
} else if (what == "interp") {
r_ret = track_get_interpolation_type(track);
} else if (what == "loop_wrap") {
@@ -834,6 +841,9 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/loop_wrap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, "tracks/" + itos(i) + "/keys", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
}
+ if (track_get_type(i) == TYPE_AUDIO) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/use_blend", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
+ }
}
}
@@ -3581,6 +3591,27 @@ real_t Animation::audio_track_get_key_end_offset(int p_track, int p_key) const {
return at->values[p_key].value.end_offset;
}
+void Animation::audio_track_set_use_blend(int p_track, bool p_enable) {
+ ERR_FAIL_INDEX(p_track, tracks.size());
+ Track *t = tracks[p_track];
+ ERR_FAIL_COND(t->type != TYPE_AUDIO);
+
+ AudioTrack *at = static_cast<AudioTrack *>(t);
+
+ at->use_blend = p_enable;
+ emit_changed();
+}
+
+bool Animation::audio_track_is_use_blend(int p_track) const {
+ ERR_FAIL_INDEX_V(p_track, tracks.size(), false);
+ Track *t = tracks[p_track];
+ ERR_FAIL_COND_V(t->type != TYPE_AUDIO, false);
+
+ AudioTrack *at = static_cast<AudioTrack *>(t);
+
+ return at->use_blend;
+}
+
//
int Animation::animation_track_insert_key(int p_track, double p_time, const StringName &p_animation) {
@@ -3813,6 +3844,8 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("audio_track_get_key_stream", "track_idx", "key_idx"), &Animation::audio_track_get_key_stream);
ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_set_use_blend", "track_idx", "enable"), &Animation::audio_track_set_use_blend);
+ ClassDB::bind_method(D_METHOD("audio_track_is_use_blend", "track_idx"), &Animation::audio_track_is_use_blend);
ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key);
ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 00a0761e0a..2c2ddb7095 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -213,6 +213,7 @@ private:
struct AudioTrack : public Track {
Vector<TKey<AudioKey>> values;
+ bool use_blend = true;
AudioTrack() {
type = TYPE_AUDIO;
@@ -447,6 +448,8 @@ public:
Ref<Resource> audio_track_get_key_stream(int p_track, int p_key) const;
real_t audio_track_get_key_start_offset(int p_track, int p_key) const;
real_t audio_track_get_key_end_offset(int p_track, int p_key) const;
+ void audio_track_set_use_blend(int p_track, bool p_enable);
+ bool audio_track_is_use_blend(int p_track) const;
int animation_track_insert_key(int p_track, double p_time, const StringName &p_animation);
void animation_track_set_key_animation(int p_track, int p_key, const StringName &p_animation);
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
index c73f8ca0b0..759d189bfa 100644
--- a/scene/resources/bone_map.cpp
+++ b/scene/resources/bone_map.cpp
@@ -152,7 +152,6 @@ void BoneMap::_validate_bone_map() {
} else {
bone_map.clear();
}
- emit_signal("retarget_option_updated");
}
void BoneMap::_bind_methods() {
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index 5dc4e64c2e..5309e54846 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -88,8 +88,10 @@ void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector<Vector2> points = _get_points();
Vector<Color> col = { p_color };
RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+
if (is_collision_outline_enabled()) {
points.push_back(points[0]);
+ col = { Color(p_color, 1.0) };
RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
}
}
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index a15dfc0a54..0b207c33ca 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -84,6 +84,7 @@ void CircleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
if (is_collision_outline_enabled()) {
points.push_back(points[0]);
+ col = { Color(p_color, 1.0) };
RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
}
}
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index e51b48a4b1..7f19dd63e6 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -76,13 +76,14 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
return;
}
- Vector<Color> col;
- col.push_back(p_color);
+ Vector<Color> col = { p_color };
RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
+
if (is_collision_outline_enabled()) {
+ col = { Color(p_color, 1.0) };
RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
- // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`.
- RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0);
+ // Draw the last segment.
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], Color(p_color, 1.0));
}
}
diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp
index 4e51bbaa73..aabaa54505 100644
--- a/scene/resources/fog_material.cpp
+++ b/scene/resources/fog_material.cpp
@@ -159,7 +159,7 @@ uniform sampler3D density_texture: hint_default_white;
void fog() {
DENSITY = density * clamp(exp2(-height_falloff * (WORLD_POSITION.y - OBJECT_POSITION.y)), 0.0, 1.0);
DENSITY *= texture(density_texture, UVW).r;
- DENSITY *= pow(clamp(-SDF / min(min(EXTENTS.x, EXTENTS.y), EXTENTS.z), 0.0, 1.0), edge_fade);
+ DENSITY *= pow(clamp(-2.0 * SDF / min(min(SIZE.x, SIZE.y), SIZE.z), 0.0, 1.0), edge_fade);
ALBEDO = albedo.rgb;
EMISSION = emission.rgb;
}
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index e5a1adff20..0f7985bee6 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -2712,6 +2712,9 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
for (const StringName &E : theme_types) {
if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f == this) {
+ continue;
+ }
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2729,6 +2732,9 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
for (const StringName &E : theme_types) {
if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f == this) {
+ continue;
+ }
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2739,11 +2745,13 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
// If they don't exist, use any type to return the default/empty value.
Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
- if (f.is_valid()) {
- theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ if (f != this) {
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
}
- return f;
}
return Ref<Font>();
@@ -3061,6 +3069,9 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
for (const StringName &E : theme_types) {
if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f == this) {
+ continue;
+ }
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -3078,6 +3089,9 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
for (const StringName &E : theme_types) {
if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (f == this) {
+ continue;
+ }
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -3088,11 +3102,13 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
// If they don't exist, use any type to return the default/empty value.
Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
- if (f.is_valid()) {
- theme_font = f;
- theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ if (f != this) {
+ if (f.is_valid()) {
+ theme_font = f;
+ theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
+ }
+ return f;
}
- return f;
}
return Ref<Font>();
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 55b633a40c..672581bbe2 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -452,6 +452,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
new_indices.resize(index_count);
Vector<float> merged_normals_f32 = vector3_to_float32_array(merged_normals.ptr(), merged_normals.size());
+ const int simplify_options = SurfaceTool::SIMPLIFY_LOCK_BORDER;
size_t new_index_count = SurfaceTool::simplify_with_attrib_func(
(unsigned int *)new_indices.ptrw(),
@@ -460,6 +461,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
sizeof(float) * 3, // Vertex stride
index_target,
max_mesh_error,
+ simplify_options,
&mesh_error,
merged_normals_f32.ptr(),
normal_weights.ptr(), 3);
@@ -1058,6 +1060,8 @@ struct EditorSceneFormatImporterMeshLightmapSurface {
String name;
};
+static const uint32_t custom_shift[RS::ARRAY_CUSTOM_COUNT] = { Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM1_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM2_SHIFT, Mesh::ARRAY_FORMAT_CUSTOM3_SHIFT };
+
Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &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.");
@@ -1178,9 +1182,6 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
return ERR_CANT_CREATE;
}
- //remove surfaces
- clear();
-
//create surfacetools for each surface..
LocalVector<Ref<SurfaceTool>> surfaces_tools;
@@ -1190,9 +1191,16 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
st->begin(Mesh::PRIMITIVE_TRIANGLES);
st->set_material(lightmap_surfaces[i].material);
st->set_meta("name", lightmap_surfaces[i].name);
+
+ for (int custom_i = 0; custom_i < RS::ARRAY_CUSTOM_COUNT; custom_i++) {
+ st->set_custom_format(custom_i, (SurfaceTool::CustomFormat)((lightmap_surfaces[i].format >> custom_shift[custom_i]) & RS::ARRAY_FORMAT_CUSTOM_MASK));
+ }
surfaces_tools.push_back(st); //stay there
}
+ //remove surfaces
+ clear();
+
print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
//go through all indices
@@ -1229,6 +1237,11 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) {
surfaces_tools[surface]->set_weights(v.weights);
}
+ for (int custom_i = 0; custom_i < RS::ARRAY_CUSTOM_COUNT; custom_i++) {
+ if ((lightmap_surfaces[surface].format >> custom_shift[custom_i]) & RS::ARRAY_FORMAT_CUSTOM_MASK) {
+ surfaces_tools[surface]->set_custom(custom_i, v.custom[custom_i]);
+ }
+ }
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
surfaces_tools[surface]->set_uv2(uv2);
@@ -1238,10 +1251,11 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
}
//generate surfaces
- for (Ref<SurfaceTool> &tool : surfaces_tools) {
+ for (int i = 0; i < lightmap_surfaces.size(); i++) {
+ Ref<SurfaceTool> &tool = surfaces_tools[i];
tool->index();
Array arrays = tool->commit_to_arrays();
- add_surface(tool->get_primitive_type(), arrays, Array(), Dictionary(), tool->get_material(), tool->get_meta("name"));
+ add_surface(tool->get_primitive_type(), arrays, Array(), Dictionary(), tool->get_material(), tool->get_meta("name"), lightmap_surfaces[i].format);
}
set_lightmap_size_hint(Size2(size_x, size_y));
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index f4aa0637f7..7e84814ab3 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -2316,71 +2316,51 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_refraction_texture_channel()
return refraction_texture_channel;
}
-Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y, bool p_msdf, bool p_no_depth, bool p_fixed_size, TextureFilter p_filter, RID *r_shader_rid) {
- int64_t hash = 0;
- if (p_shaded) {
- hash |= 1 << 0;
- }
- if (p_transparent) {
- hash |= 1 << 1;
- }
- if (p_cut_alpha) {
- hash |= 1 << 2;
- }
- if (p_opaque_prepass) {
- hash |= 1 << 3;
- }
- if (p_double_sided) {
- hash |= 1 << 4;
- }
- if (p_billboard) {
- hash |= 1 << 5;
- }
- if (p_billboard_y) {
- hash |= 1 << 6;
- }
- if (p_msdf) {
- hash |= 1 << 7;
- }
- if (p_no_depth) {
- hash |= 1 << 8;
- }
- if (p_fixed_size) {
- hash |= 1 << 9;
- }
- hash = hash_murmur3_one_64(p_filter, hash);
-
- if (materials_for_2d.has(hash)) {
+Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, Transparency p_transparency, bool p_double_sided, bool p_billboard, bool p_billboard_y, bool p_msdf, bool p_no_depth, bool p_fixed_size, TextureFilter p_filter, AlphaAntiAliasing p_alpha_antialiasing_mode, RID *r_shader_rid) {
+ uint64_t key = 0;
+ key |= ((int8_t)p_shaded & 0x01) << 0;
+ key |= ((int8_t)p_transparency & 0x07) << 1; // Bits 1-3.
+ key |= ((int8_t)p_double_sided & 0x01) << 4;
+ key |= ((int8_t)p_billboard & 0x01) << 5;
+ key |= ((int8_t)p_billboard_y & 0x01) << 6;
+ key |= ((int8_t)p_msdf & 0x01) << 7;
+ key |= ((int8_t)p_no_depth & 0x01) << 8;
+ key |= ((int8_t)p_fixed_size & 0x01) << 9;
+ key |= ((int8_t)p_filter & 0x07) << 10; // Bits 10-12.
+ key |= ((int8_t)p_alpha_antialiasing_mode & 0x07) << 13; // Bits 13-15.
+
+ if (materials_for_2d.has(key)) {
if (r_shader_rid) {
- *r_shader_rid = materials_for_2d[hash]->get_shader_rid();
+ *r_shader_rid = materials_for_2d[key]->get_shader_rid();
}
- return materials_for_2d[hash];
+ return materials_for_2d[key];
}
Ref<StandardMaterial3D> material;
material.instantiate();
material->set_shading_mode(p_shaded ? SHADING_MODE_PER_PIXEL : SHADING_MODE_UNSHADED);
- material->set_transparency(p_transparent ? (p_opaque_prepass ? TRANSPARENCY_ALPHA_DEPTH_PRE_PASS : (p_cut_alpha ? TRANSPARENCY_ALPHA_SCISSOR : TRANSPARENCY_ALPHA)) : TRANSPARENCY_DISABLED);
+ material->set_transparency(p_transparency);
material->set_cull_mode(p_double_sided ? CULL_DISABLED : CULL_BACK);
material->set_flag(FLAG_SRGB_VERTEX_COLOR, true);
material->set_flag(FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
material->set_flag(FLAG_ALBEDO_TEXTURE_MSDF, p_msdf);
material->set_flag(FLAG_DISABLE_DEPTH_TEST, p_no_depth);
material->set_flag(FLAG_FIXED_SIZE, p_fixed_size);
+ material->set_alpha_antialiasing(p_alpha_antialiasing_mode);
material->set_texture_filter(p_filter);
if (p_billboard || p_billboard_y) {
material->set_flag(FLAG_BILLBOARD_KEEP_SCALE, true);
material->set_billboard_mode(p_billboard_y ? BILLBOARD_FIXED_Y : BILLBOARD_ENABLED);
}
- materials_for_2d[hash] = material;
+ materials_for_2d[key] = material;
if (r_shader_rid) {
- *r_shader_rid = materials_for_2d[hash]->get_shader_rid();
+ *r_shader_rid = materials_for_2d[key]->get_shader_rid();
}
- return materials_for_2d[hash];
+ return materials_for_2d[key];
}
void BaseMaterial3D::set_on_top_of_alpha() {
diff --git a/scene/resources/material.h b/scene/resources/material.h
index fe1448cd4c..5ea9a807d4 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -760,7 +760,7 @@ public:
static void finish_shaders();
static void flush_changes();
- static Ref<Material> get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false, bool p_msdf = false, bool p_no_depth = false, bool p_fixed_size = false, TextureFilter p_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RID *r_shader_rid = nullptr);
+ static Ref<Material> get_material_for_2d(bool p_shaded, Transparency p_transparency, bool p_double_sided, bool p_billboard = false, bool p_billboard_y = false, bool p_msdf = false, bool p_no_depth = false, bool p_fixed_size = false, TextureFilter p_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, AlphaAntiAliasing p_alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF, RID *r_shader_rid = nullptr);
virtual RID get_shader_rid() const override;
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index 7e1b42c80b..1d13f07b12 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -278,7 +278,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const {
void NavigationMesh::set_filter_baking_aabb(const AABB &p_aabb) {
filter_baking_aabb = p_aabb;
- notify_property_list_changed();
+ emit_changed();
}
AABB NavigationMesh::get_filter_baking_aabb() const {
@@ -287,7 +287,7 @@ AABB NavigationMesh::get_filter_baking_aabb() const {
void NavigationMesh::set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset) {
filter_baking_aabb_offset = p_aabb_offset;
- notify_property_list_changed();
+ emit_changed();
}
Vector3 NavigationMesh::get_filter_baking_aabb_offset() const {
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index e497a628aa..1e9038139e 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -43,7 +43,7 @@
#include "scene/main/missing_node.h"
#include "scene/property_utils.h"
-#define PACKED_SCENE_VERSION 2
+#define PACKED_SCENE_VERSION 3
#define META_POINTER_PROPERTY_BASE "metadata/_editor_prop_ptr_"
bool SceneState::can_instantiate() const {
return nodes.size() > 0;
@@ -314,7 +314,19 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
//must make a copy, because this res is local to scene
}
}
- } else if (p_edit_state == GEN_EDIT_STATE_INSTANCE) {
+ }
+ if (value.get_type() == Variant::ARRAY) {
+ Array set_array = value;
+ bool is_get_valid = false;
+ Variant get_value = node->get(snames[nprops[j].name], &is_get_valid);
+ if (is_get_valid && get_value.get_type() == Variant::ARRAY) {
+ Array get_array = get_value;
+ if (!set_array.is_same_typed(get_array)) {
+ value = Array(set_array, get_array.get_typed_builtin(), get_array.get_typed_class_name(), get_array.get_typed_script());
+ }
+ }
+ }
+ if (p_edit_state == GEN_EDIT_STATE_INSTANCE && value.get_type() != Variant::OBJECT) {
value = value.duplicate(true); // Duplicate arrays and dictionaries for the editor
}
@@ -1282,6 +1294,9 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
for (int j = 0; j < cd.binds.size(); j++) {
cd.binds.write[j] = r[idx++];
}
+ if (version >= 3) {
+ cd.unbinds = r[idx++];
+ }
}
}
@@ -1368,6 +1383,7 @@ Dictionary SceneState::get_bundled_scene() const {
for (int j = 0; j < cd.binds.size(); j++) {
rconns.push_back(cd.binds[j]);
}
+ rconns.push_back(cd.unbinds);
}
d["conns"] = rconns;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 86ed0001dd..ef1f6459e9 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -257,7 +257,7 @@ void PrimitiveMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, "suffix:m"), "set_custom_aabb", "get_custom_aabb");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "add_uv2"), "set_add_uv2", "get_add_uv2");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv2_padding"), "set_uv2_padding", "get_uv2_padding");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "uv2_padding", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"), "set_uv2_padding", "get_uv2_padding");
GDVIRTUAL_BIND(_create_mesh_array);
}
diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index 84c147b4b4..65b1653293 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -79,11 +79,7 @@ void RectangleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
stroke_points.write[3] = Vector2(-size.x, size.y) * 0.5;
stroke_points.write[4] = -size * 0.5;
- Vector<Color> stroke_colors;
- stroke_colors.resize(5);
- for (int i = 0; i < 5; i++) {
- stroke_colors.write[i] = (p_color);
- }
+ Vector<Color> stroke_colors = { Color(p_color, 1.0) };
RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, stroke_points, stroke_colors);
}
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 0ba177f882..3006da5309 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -636,6 +636,18 @@ Error ResourceLoaderText::load() {
}
}
+ if (value.get_type() == Variant::ARRAY) {
+ Array set_array = value;
+ bool is_get_valid = false;
+ Variant get_value = res->get(assign, &is_get_valid);
+ if (is_get_valid && get_value.get_type() == Variant::ARRAY) {
+ Array get_array = get_value;
+ if (!set_array.is_same_typed(get_array)) {
+ value = Array(set_array, get_array.get_typed_builtin(), get_array.get_typed_class_name(), get_array.get_typed_script());
+ }
+ }
+ }
+
if (set_valid) {
res->set(assign, value);
}
@@ -746,6 +758,18 @@ Error ResourceLoaderText::load() {
}
}
+ if (value.get_type() == Variant::ARRAY) {
+ Array set_array = value;
+ bool is_get_valid = false;
+ Variant get_value = resource->get(assign, &is_get_valid);
+ if (is_get_valid && get_value.get_type() == Variant::ARRAY) {
+ Array get_array = get_value;
+ if (!set_array.is_same_typed(get_array)) {
+ value = Array(set_array, get_array.get_typed_builtin(), get_array.get_typed_class_name(), get_array.get_typed_script());
+ }
+ }
+ }
+
if (set_valid) {
resource->set(assign, value);
}
@@ -2355,15 +2379,15 @@ Error ResourceFormatSaverText::set_uid(const String &p_path, ResourceUID::ID p_u
String local_path = ProjectSettings::get_singleton()->localize_path(p_path);
Error err = OK;
{
- Ref<FileAccess> fo = FileAccess::open(p_path, FileAccess::READ);
- if (fo.is_null()) {
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
+ if (file.is_null()) {
ERR_FAIL_V(ERR_CANT_OPEN);
}
ResourceLoaderText loader;
loader.local_path = local_path;
loader.res_path = loader.local_path;
- err = loader.set_uid(fo, p_uid);
+ err = loader.set_uid(file, p_uid);
}
if (err == OK) {
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index a09dbd50cf..fd2be9ba22 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -55,6 +55,12 @@ void Shader::set_path(const String &p_path, bool p_take_over) {
RS::get_singleton()->shader_set_path_hint(shader, p_path);
}
+void Shader::set_include_path(const String &p_path) {
+ // Used only if the shader does not have a resource path set,
+ // for example during loading stage or when created by code.
+ include_path = p_path;
+}
+
void Shader::set_code(const String &p_code) {
for (Ref<ShaderInclude> E : include_dependencies) {
E->disconnect(SNAME("changed"), callable_mp(this, &Shader::_dependency_changed));
@@ -80,11 +86,15 @@ void Shader::set_code(const String &p_code) {
HashSet<Ref<ShaderInclude>> new_include_dependencies;
{
+ String path = get_path();
+ if (path.is_empty()) {
+ path = include_path;
+ }
// Preprocessor must run here and not in the server because:
// 1) Need to keep track of include dependencies at resource level
// 2) Server does not do interaction with Resource filetypes, this is a scene level feature.
ShaderPreprocessor preprocessor;
- preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
+ preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
}
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
@@ -231,6 +241,7 @@ Ref<Resource> ResourceFormatLoaderShader::load(const String &p_path, const Strin
String str;
str.parse_utf8((const char *)buffer.ptr(), buffer.size());
+ shader->set_include_path(p_path);
shader->set_code(str);
if (r_error) {
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 55608b6c11..ca889940ef 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -56,6 +56,7 @@ private:
Mode mode = MODE_SPATIAL;
HashSet<Ref<ShaderInclude>> include_dependencies;
String code;
+ String include_path;
HashMap<StringName, HashMap<int, Ref<Texture2D>>> default_textures;
@@ -72,6 +73,7 @@ public:
virtual Mode get_mode() const;
virtual void set_path(const String &p_path, bool p_take_over = false) override;
+ void set_include_path(const String &p_path);
void set_code(const String &p_code);
String get_code() const;
diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp
index cd5e9861f7..68137cbec0 100644
--- a/scene/resources/shader_include.cpp
+++ b/scene/resources/shader_include.cpp
@@ -45,9 +45,14 @@ void ShaderInclude::set_code(const String &p_code) {
}
{
+ String path = get_path();
+ if (path.is_empty()) {
+ path = include_path;
+ }
+
String pp_code;
ShaderPreprocessor preprocessor;
- preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_dependencies);
+ preprocessor.preprocess(p_code, path, pp_code, nullptr, nullptr, nullptr, &new_dependencies);
}
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
@@ -64,6 +69,10 @@ String ShaderInclude::get_code() const {
return code;
}
+void ShaderInclude::set_include_path(const String &p_path) {
+ include_path = p_path;
+}
+
void ShaderInclude::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_code", "code"), &ShaderInclude::set_code);
ClassDB::bind_method(D_METHOD("get_code"), &ShaderInclude::get_code);
@@ -86,6 +95,7 @@ Ref<Resource> ResourceFormatLoaderShaderInclude::load(const String &p_path, cons
String str;
str.parse_utf8((const char *)buffer.ptr(), buffer.size());
+ shader_inc->set_include_path(p_path);
shader_inc->set_code(str);
if (r_error) {
diff --git a/scene/resources/shader_include.h b/scene/resources/shader_include.h
index 04f4f5cf84..a8949b327e 100644
--- a/scene/resources/shader_include.h
+++ b/scene/resources/shader_include.h
@@ -42,6 +42,7 @@ class ShaderInclude : public Resource {
private:
String code;
+ String include_path;
HashSet<Ref<ShaderInclude>> dependencies;
void _dependency_changed();
@@ -51,6 +52,8 @@ protected:
public:
void set_code(const String &p_text);
String get_code() const;
+
+ void set_include_path(const String &p_path);
};
class ResourceFormatLoaderShaderInclude : public ResourceFormatLoader {
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index fbbe98d022..9e0b856ecd 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -1007,7 +1007,7 @@ void StyleBoxLine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_begin", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_begin", "get_grow_begin");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "grow_end", PROPERTY_HINT_RANGE, "-300,300,1,suffix:px"), "set_grow_end", "get_grow_end");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10,suffix:px"), "set_thickness", "get_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,100,suffix:px"), "set_thickness", "get_thickness");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 5a2b917b9a..16cc1c3370 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -1307,7 +1307,8 @@ Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_coun
}
float error;
- uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold, &error);
+ const int simplify_options = SIMPLIFY_LOCK_BORDER;
+ uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold, simplify_options, &error);
ERR_FAIL_COND_V(index_count == 0, lod);
lod.resize(index_count);
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index 00438c4a53..77318bb061 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -74,11 +74,16 @@ public:
SKIN_8_WEIGHTS
};
+ enum {
+ /* Do not move vertices that are located on the topological border (vertices on triangle edges that don't have a paired triangle). Useful for simplifying portions of the larger mesh. */
+ SIMPLIFY_LOCK_BORDER = 1 << 0, // From meshopt_SimplifyLockBorder
+ };
+
typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count);
static OptimizeVertexCacheFunc optimize_vertex_cache_func;
- typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *r_error);
+ typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, unsigned int options, float *r_error);
static SimplifyFunc simplify_func;
- typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float *result_error, const float *attributes, const float *attribute_weights, size_t attribute_count);
+ typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float *result_error, const float *attributes, const float *attribute_weights, size_t attribute_count);
static SimplifyWithAttribFunc simplify_with_attrib_func;
typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
static SimplifyScaleFunc simplify_scale_func;
diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp
new file mode 100644
index 0000000000..ee1a47c338
--- /dev/null
+++ b/scene/resources/video_stream.cpp
@@ -0,0 +1,198 @@
+/**************************************************************************/
+/* video_stream.cpp */
+/**************************************************************************/
+/* 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. */
+/**************************************************************************/
+
+#include "video_stream.h"
+
+#include "core/config/project_settings.h"
+#include "servers/audio_server.h"
+
+// VideoStreamPlayback starts here.
+
+void VideoStreamPlayback::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("mix_audio", "num_frames", "buffer", "offset"), &VideoStreamPlayback::mix_audio, DEFVAL(PackedFloat32Array()), DEFVAL(0));
+ GDVIRTUAL_BIND(_stop);
+ GDVIRTUAL_BIND(_play);
+ GDVIRTUAL_BIND(_is_playing);
+ GDVIRTUAL_BIND(_set_paused, "paused");
+ GDVIRTUAL_BIND(_is_paused);
+ GDVIRTUAL_BIND(_get_length);
+ GDVIRTUAL_BIND(_get_playback_position);
+ GDVIRTUAL_BIND(_seek, "time");
+ GDVIRTUAL_BIND(_set_audio_track, "idx");
+ GDVIRTUAL_BIND(_get_texture);
+ GDVIRTUAL_BIND(_update, "delta");
+ GDVIRTUAL_BIND(_get_channels);
+ GDVIRTUAL_BIND(_get_mix_rate);
+}
+
+VideoStreamPlayback::VideoStreamPlayback() {
+}
+
+VideoStreamPlayback::~VideoStreamPlayback() {
+}
+
+void VideoStreamPlayback::stop() {
+ GDVIRTUAL_CALL(_stop);
+}
+
+void VideoStreamPlayback::play() {
+ GDVIRTUAL_CALL(_play);
+}
+
+bool VideoStreamPlayback::is_playing() const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_is_playing, ret)) {
+ return ret;
+ }
+ return false;
+}
+
+void VideoStreamPlayback::set_paused(bool p_paused) {
+ GDVIRTUAL_CALL(_is_playing, p_paused);
+}
+
+bool VideoStreamPlayback::is_paused() const {
+ bool ret;
+ if (GDVIRTUAL_CALL(_is_paused, ret)) {
+ return ret;
+ }
+ return false;
+}
+
+double VideoStreamPlayback::get_length() const {
+ double ret;
+ if (GDVIRTUAL_CALL(_get_length, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+double VideoStreamPlayback::get_playback_position() const {
+ double ret;
+ if (GDVIRTUAL_CALL(_get_playback_position, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+void VideoStreamPlayback::seek(double p_time) {
+ GDVIRTUAL_CALL(_seek, p_time);
+}
+
+void VideoStreamPlayback::set_audio_track(int p_idx) {
+ GDVIRTUAL_CALL(_set_audio_track, p_idx);
+}
+
+Ref<Texture2D> VideoStreamPlayback::get_texture() const {
+ Ref<Texture2D> ret;
+ if (GDVIRTUAL_CALL(_get_texture, ret)) {
+ return ret;
+ }
+ return nullptr;
+}
+
+void VideoStreamPlayback::update(double p_delta) {
+ if (!GDVIRTUAL_CALL(_update, p_delta)) {
+ ERR_FAIL_MSG("VideoStreamPlayback::update unimplemented");
+ }
+}
+
+void VideoStreamPlayback::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) {
+ mix_callback = p_callback;
+ mix_udata = p_userdata;
+}
+
+int VideoStreamPlayback::get_channels() const {
+ int ret;
+ if (GDVIRTUAL_CALL(_get_channels, ret)) {
+ _channel_count = ret;
+ return ret;
+ }
+ return 0;
+}
+
+int VideoStreamPlayback::get_mix_rate() const {
+ int ret;
+ if (GDVIRTUAL_CALL(_get_mix_rate, ret)) {
+ return ret;
+ }
+ return 0;
+}
+
+int VideoStreamPlayback::mix_audio(int num_frames, PackedFloat32Array buffer, int offset) {
+ if (num_frames <= 0) {
+ return 0;
+ }
+ if (!mix_callback) {
+ return -1;
+ }
+ ERR_FAIL_INDEX_V(offset, buffer.size(), -1);
+ ERR_FAIL_INDEX_V((_channel_count < 1 ? 1 : _channel_count) * num_frames - 1, buffer.size() - offset, -1);
+ return mix_callback(mix_udata, buffer.ptr() + offset, num_frames);
+}
+
+/* --- NOTE VideoStream starts here. ----- */
+
+Ref<VideoStreamPlayback> VideoStream::instantiate_playback() {
+ Ref<VideoStreamPlayback> ret;
+ if (GDVIRTUAL_CALL(_instantiate_playback, ret)) {
+ ERR_FAIL_COND_V_MSG(ret.is_null(), nullptr, "Plugin returned null playback");
+ ret->set_audio_track(audio_track);
+ return ret;
+ }
+ return nullptr;
+}
+
+void VideoStream::set_file(const String &p_file) {
+ file = p_file;
+}
+
+String VideoStream::get_file() {
+ return file;
+}
+
+void VideoStream::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStream::set_file);
+ ClassDB::bind_method(D_METHOD("get_file"), &VideoStream::get_file);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "file"), "set_file", "get_file");
+
+ GDVIRTUAL_BIND(_instantiate_playback);
+}
+
+VideoStream::VideoStream() {
+}
+
+VideoStream::~VideoStream() {
+}
+
+void VideoStream::set_audio_track(int p_track) {
+ audio_track = p_track;
+}
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index f83c621d0a..b91a7acf35 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -31,6 +31,7 @@
#ifndef VIDEO_STREAM_H
#define VIDEO_STREAM_H
+#include "core/io/file_access.h"
#include "scene/resources/texture.h"
class VideoStreamPlayback : public Resource {
@@ -39,40 +40,77 @@ class VideoStreamPlayback : public Resource {
public:
typedef int (*AudioMixCallback)(void *p_udata, const float *p_data, int p_frames);
- virtual void stop() = 0;
- virtual void play() = 0;
+protected:
+ AudioMixCallback mix_callback = nullptr;
+ void *mix_udata = nullptr;
+ mutable int _channel_count = 0; // Used only to assist with bounds checking in mix_audio.
+
+ static void _bind_methods();
+ GDVIRTUAL0(_stop);
+ GDVIRTUAL0(_play);
+ GDVIRTUAL0RC(bool, _is_playing);
+ GDVIRTUAL1(_set_paused, bool);
+ GDVIRTUAL0RC(bool, _is_paused);
+ GDVIRTUAL0RC(double, _get_length);
+ GDVIRTUAL0RC(double, _get_playback_position);
+ GDVIRTUAL1(_seek, double);
+ GDVIRTUAL1(_set_audio_track, int);
+ GDVIRTUAL0RC(Ref<Texture2D>, _get_texture);
+ GDVIRTUAL1(_update, double);
+ GDVIRTUAL0RC(int, _get_channels);
+ GDVIRTUAL0RC(int, _get_mix_rate);
+
+ int mix_audio(int num_frames, PackedFloat32Array buffer = {}, int offset = 0);
- virtual bool is_playing() const = 0;
+public:
+ VideoStreamPlayback();
+ virtual ~VideoStreamPlayback();
- virtual void set_paused(bool p_paused) = 0;
- virtual bool is_paused() const = 0;
+ virtual void stop();
+ virtual void play();
- virtual void set_loop(bool p_enable) = 0;
- virtual bool has_loop() const = 0;
+ virtual bool is_playing() const;
- virtual double get_length() const = 0;
+ virtual void set_paused(bool p_paused);
+ virtual bool is_paused() const;
- virtual double get_playback_position() const = 0;
- virtual void seek(double p_time) = 0;
+ virtual double get_length() const;
- virtual void set_audio_track(int p_idx) = 0;
+ virtual double get_playback_position() const;
+ virtual void seek(double p_time);
- virtual Ref<Texture2D> get_texture() const = 0;
+ virtual void set_audio_track(int p_idx);
- virtual void update(double p_delta) = 0;
+ virtual Ref<Texture2D> get_texture() const;
+ virtual void update(double p_delta);
- virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) = 0;
- virtual int get_channels() const = 0;
- virtual int get_mix_rate() const = 0;
+ virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata);
+ virtual int get_channels() const;
+ virtual int get_mix_rate() const;
};
class VideoStream : public Resource {
GDCLASS(VideoStream, Resource);
- OBJ_SAVE_TYPE(VideoStream); // Saves derived classes with common type so they can be interchanged.
+ OBJ_SAVE_TYPE(VideoStream);
+
+protected:
+ static void
+ _bind_methods();
+
+ GDVIRTUAL0R(Ref<VideoStreamPlayback>, _instantiate_playback);
+
+ String file;
+ int audio_track = 0;
public:
- virtual void set_audio_track(int p_track) = 0;
- virtual Ref<VideoStreamPlayback> instantiate_playback() = 0;
+ void set_file(const String &p_file);
+ String get_file();
+
+ virtual void set_audio_track(int p_track);
+ virtual Ref<VideoStreamPlayback> instantiate_playback();
+
+ VideoStream();
+ ~VideoStream();
};
#endif // VIDEO_STREAM_H
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index bfcf5cb137..3a6d40d22c 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -427,7 +427,10 @@ void VisualShaderNodeCustom::update_ports() {
if (!GDVIRTUAL_CALL(_get_input_port_name, i, port.name)) {
port.name = "in" + itos(i);
}
- if (!GDVIRTUAL_CALL(_get_input_port_type, i, port.type)) {
+ PortType port_type;
+ if (GDVIRTUAL_CALL(_get_input_port_type, i, port_type)) {
+ port.type = (int)port_type;
+ } else {
port.type = (int)PortType::PORT_TYPE_SCALAR;
}
@@ -445,7 +448,10 @@ void VisualShaderNodeCustom::update_ports() {
if (!GDVIRTUAL_CALL(_get_output_port_name, i, port.name)) {
port.name = "out" + itos(i);
}
- if (!GDVIRTUAL_CALL(_get_output_port_type, i, port.type)) {
+ PortType port_type;
+ if (GDVIRTUAL_CALL(_get_output_port_type, i, port_type)) {
+ port.type = (int)port_type;
+ } else {
port.type = (int)PortType::PORT_TYPE_SCALAR;
}
@@ -809,6 +815,8 @@ void VisualShader::remove_node(Type p_type, int p_id) {
if (E->get().from_node == p_id) {
g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id);
g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false);
+ } else if (E->get().to_node == p_id) {
+ g->nodes[E->get().from_node].next_connected_nodes.erase(p_id);
}
}
E = N;
@@ -975,6 +983,7 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from
c.to_node = p_to_node;
c.to_port = p_to_port;
g->connections.push_back(c);
+ g->nodes[p_from_node].next_connected_nodes.push_back(p_to_node);
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
@@ -1008,6 +1017,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
c.to_node = p_to_node;
c.to_port = p_to_port;
g->connections.push_back(c);
+ g->nodes[p_from_node].next_connected_nodes.push_back(p_to_node);
g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
@@ -1023,6 +1033,7 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
for (const List<Connection>::Element *E = g->connections.front(); E; E = E->next()) {
if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
g->connections.erase(E);
+ g->nodes[p_from_node].next_connected_nodes.erase(p_to_node);
g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node);
g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false);
g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false);
@@ -2702,6 +2713,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "eye_offset", "EYE_OFFSET" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
@@ -2736,6 +2748,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "eye_offset", "EYE_OFFSET" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
@@ -2936,7 +2949,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "world_position", "WORLD_POSITION" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "object_position", "OBJECT_POSITION" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "uvw", "UVW" },
- { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "extents", "EXTENTS" },
+ { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "size", "SIZE" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "sdf", "SDF" },
{ Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" },
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 0d53589fa5..2838a49209 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -122,7 +122,8 @@ private:
struct Node {
Ref<VisualShaderNode> node;
Vector2 position;
- List<int> prev_connected_nodes;
+ LocalVector<int> prev_connected_nodes;
+ LocalVector<int> next_connected_nodes;
};
struct Graph {
@@ -199,6 +200,16 @@ public: // internal methods
Vector2 get_node_position(Type p_type, int p_id) const;
Ref<VisualShaderNode> get_node(Type p_type, int p_id) const;
+ _FORCE_INLINE_ Ref<VisualShaderNode> get_node_unchecked(Type p_type, int p_id) const {
+ return graph[p_type].nodes[p_id].node;
+ }
+ _FORCE_INLINE_ void get_next_connected_nodes(Type p_type, int p_id, LocalVector<int> &r_list) const {
+ r_list = graph[p_type].nodes[p_id].next_connected_nodes;
+ }
+ _FORCE_INLINE_ void get_prev_connected_nodes(Type p_type, int p_id, LocalVector<int> &r_list) const {
+ r_list = graph[p_type].nodes[p_id].prev_connected_nodes;
+ }
+
Vector<int> get_node_list(Type p_type) const;
int get_valid_node_id(Type p_type) const;
@@ -369,12 +380,12 @@ protected:
GDVIRTUAL0RC(String, _get_name)
GDVIRTUAL0RC(String, _get_description)
GDVIRTUAL0RC(String, _get_category)
- GDVIRTUAL0RC(int, _get_return_icon_type)
+ GDVIRTUAL0RC(PortType, _get_return_icon_type)
GDVIRTUAL0RC(int, _get_input_port_count)
- GDVIRTUAL1RC(int, _get_input_port_type, int)
+ GDVIRTUAL1RC(PortType, _get_input_port_type, int)
GDVIRTUAL1RC(String, _get_input_port_name, int)
GDVIRTUAL0RC(int, _get_output_port_count)
- GDVIRTUAL1RC(int, _get_output_port_type, int)
+ GDVIRTUAL1RC(PortType, _get_output_port_type, int)
GDVIRTUAL1RC(String, _get_output_port_name, int)
GDVIRTUAL4RC(String, _get_code, TypedArray<String>, TypedArray<String>, Shader::Mode, VisualShader::Type)
GDVIRTUAL2RC(String, _get_func_code, Shader::Mode, VisualShader::Type)
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 12be0f46a6..0695492e7f 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -6923,15 +6923,34 @@ void VisualShaderNodeSwitch::_bind_methods() { // static
}
String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ bool use_mix = false;
+ switch (op_type) {
+ case OP_TYPE_FLOAT: {
+ use_mix = true;
+ } break;
+ case OP_TYPE_VECTOR_2D: {
+ use_mix = true;
+ } break;
+ case OP_TYPE_VECTOR_3D: {
+ use_mix = true;
+ } break;
+ case OP_TYPE_VECTOR_4D: {
+ use_mix = true;
+ } break;
+ default: {
+ } break;
+ }
+
String code;
- code += " if(" + p_input_vars[0] + ")\n";
- code += " {\n";
- code += " " + p_output_vars[0] + " = " + p_input_vars[1] + ";\n";
- code += " }\n";
- code += " else\n";
- code += " {\n";
- code += " " + p_output_vars[0] + " = " + p_input_vars[2] + ";\n";
- code += " }\n";
+ if (use_mix) {
+ code += " " + p_output_vars[0] + " = mix(" + p_input_vars[2] + ", " + p_input_vars[1] + ", float(" + p_input_vars[0] + "));\n";
+ } else {
+ code += " if (" + p_input_vars[0] + ") {\n";
+ code += " " + p_output_vars[0] + " = " + p_input_vars[1] + ";\n";
+ code += " } else {\n";
+ code += " " + p_output_vars[0] + " = " + p_input_vars[2] + ";\n";
+ code += " }\n";
+ }
return code;
}
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index c35f7360b5..c7304da358 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -43,10 +43,25 @@ RID World2D::get_canvas() const {
}
RID World2D::get_space() const {
+ if (space.is_null()) {
+ space = PhysicsServer2D::get_singleton()->space_create();
+ PhysicsServer2D::get_singleton()->space_set_active(space, true);
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_GET("physics/2d/default_gravity"));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_GET("physics/2d/default_gravity_vector"));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_GET("physics/2d/default_linear_damp"));
+ PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_GET("physics/2d/default_angular_damp"));
+ }
return space;
}
RID World2D::get_navigation_map() const {
+ if (navigation_map.is_null()) {
+ navigation_map = NavigationServer2D::get_singleton()->map_create();
+ NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
+ NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_GET("navigation/2d/default_cell_size"));
+ NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_GET("navigation/2d/default_edge_connection_margin"));
+ NavigationServer2D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_GET("navigation/2d/default_link_connection_radius"));
+ }
return navigation_map;
}
@@ -64,26 +79,11 @@ void World2D::_bind_methods() {
}
PhysicsDirectSpaceState2D *World2D::get_direct_space_state() {
- return PhysicsServer2D::get_singleton()->space_get_direct_state(space);
+ return PhysicsServer2D::get_singleton()->space_get_direct_state(get_space());
}
World2D::World2D() {
canvas = RenderingServer::get_singleton()->canvas_create();
-
- // Create and configure space2D to be more friendly with pixels than meters
- space = PhysicsServer2D::get_singleton()->space_create();
- PhysicsServer2D::get_singleton()->space_set_active(space, true);
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/2d/default_gravity", 980.0));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/2d/default_gravity_vector", Vector2(0, 1)));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), 0.1));
- PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), 1.0));
-
- // Create and configure the navigation_map to be more friendly with pixels than meters.
- navigation_map = NavigationServer2D::get_singleton()->map_create();
- NavigationServer2D::get_singleton()->map_set_active(navigation_map, true);
- NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 1));
- NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 1));
- NavigationServer2D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/2d/default_link_connection_radius", 4));
}
World2D::~World2D() {
@@ -91,6 +91,10 @@ World2D::~World2D() {
ERR_FAIL_NULL(PhysicsServer2D::get_singleton());
ERR_FAIL_NULL(NavigationServer2D::get_singleton());
RenderingServer::get_singleton()->free(canvas);
- PhysicsServer2D::get_singleton()->free(space);
- NavigationServer2D::get_singleton()->free(navigation_map);
+ if (space.is_valid()) {
+ PhysicsServer2D::get_singleton()->free(space);
+ }
+ if (navigation_map.is_valid()) {
+ NavigationServer2D::get_singleton()->free(navigation_map);
+ }
}
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index 92239ed167..0b3b9df7dc 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -43,8 +43,8 @@ class World2D : public Resource {
GDCLASS(World2D, Resource);
RID canvas;
- RID space;
- RID navigation_map;
+ mutable RID space;
+ mutable RID navigation_map;
HashSet<Viewport *> viewports;
diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp
index 536edd334b..82c056d5ee 100644
--- a/scene/resources/world_3d.cpp
+++ b/scene/resources/world_3d.cpp
@@ -51,10 +51,25 @@ void World3D::_remove_camera(Camera3D *p_camera) {
}
RID World3D::get_space() const {
+ if (space.is_null()) {
+ space = PhysicsServer3D::get_singleton()->space_create();
+ PhysicsServer3D::get_singleton()->space_set_active(space, true);
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_GET("physics/3d/default_gravity"));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_GET("physics/3d/default_gravity_vector"));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_GET("physics/3d/default_linear_damp"));
+ PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_GET("physics/3d/default_angular_damp"));
+ }
return space;
}
RID World3D::get_navigation_map() const {
+ if (navigation_map.is_null()) {
+ navigation_map = NavigationServer3D::get_singleton()->map_create();
+ NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
+ NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_GET("navigation/3d/default_cell_size"));
+ NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_GET("navigation/3d/default_edge_connection_margin"));
+ NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_GET("navigation/3d/default_link_connection_radius"));
+ }
return navigation_map;
}
@@ -114,7 +129,7 @@ Ref<CameraAttributes> World3D::get_camera_attributes() const {
}
PhysicsDirectSpaceState3D *World3D::get_direct_space_state() {
- return PhysicsServer3D::get_singleton()->space_get_direct_state(space);
+ return PhysicsServer3D::get_singleton()->space_get_direct_state(get_space());
}
void World3D::_bind_methods() {
@@ -138,27 +153,19 @@ void World3D::_bind_methods() {
}
World3D::World3D() {
- space = PhysicsServer3D::get_singleton()->space_create();
scenario = RenderingServer::get_singleton()->scenario_create();
-
- PhysicsServer3D::get_singleton()->space_set_active(space, true);
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY, GLOBAL_DEF_BASIC("physics/3d/default_gravity", 9.8));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF_BASIC("physics/3d/default_gravity_vector", Vector3(0, -1, 0)));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_LINEAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/default_linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), 0.1));
- PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/default_angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), 0.1));
-
- navigation_map = NavigationServer3D::get_singleton()->map_create();
- NavigationServer3D::get_singleton()->map_set_active(navigation_map, true);
- NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25));
- NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25));
- NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/3d/default_link_connection_radius", 1.0));
}
World3D::~World3D() {
- ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
ERR_FAIL_NULL(RenderingServer::get_singleton());
+ ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
- PhysicsServer3D::get_singleton()->free(space);
+
RenderingServer::get_singleton()->free(scenario);
- NavigationServer3D::get_singleton()->free(navigation_map);
+ if (space.is_valid()) {
+ PhysicsServer3D::get_singleton()->free(space);
+ }
+ if (navigation_map.is_valid()) {
+ NavigationServer3D::get_singleton()->free(navigation_map);
+ }
}
diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h
index 7cbc9f08c9..518fff64e2 100644
--- a/scene/resources/world_3d.h
+++ b/scene/resources/world_3d.h
@@ -45,9 +45,9 @@ class World3D : public Resource {
GDCLASS(World3D, Resource);
private:
- RID space;
- RID navigation_map;
RID scenario;
+ mutable RID space;
+ mutable RID navigation_map;
Ref<Environment> environment;
Ref<Environment> fallback_environment;
diff --git a/scene/resources/world_boundary_shape_2d.cpp b/scene/resources/world_boundary_shape_2d.cpp
index 49f0873a3e..35cb8ef13d 100644
--- a/scene/resources/world_boundary_shape_2d.cpp
+++ b/scene/resources/world_boundary_shape_2d.cpp
@@ -76,11 +76,12 @@ real_t WorldBoundaryShape2D::get_distance() const {
void WorldBoundaryShape2D::draw(const RID &p_to_rid, const Color &p_color) {
Vector2 point = get_distance() * get_normal();
+ real_t line_width = 3.0;
Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 };
- RS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3);
- Vector2 l2[2] = { point, point + get_normal() * 30 };
- RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3);
+ RS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, line_width);
+ Vector2 l2[2] = { point + get_normal().normalized() * (0.5 * line_width), point + get_normal() * 30 };
+ RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, line_width);
}
Rect2 WorldBoundaryShape2D::get_rect() const {