diff options
Diffstat (limited to 'scene')
218 files changed, 5956 insertions, 4520 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index decb3d0dd8..257e334873 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -158,14 +158,14 @@ void AnimatedSprite2D::_notification(int p_what) { return; } - double speed = frames->get_animation_speed(animation) * speed_scale; - if (speed == 0) { - return; //do nothing - } - double remaining = get_process_delta_time(); while (remaining) { + double speed = frames->get_animation_speed(animation) * speed_scale; + if (speed == 0) { + return; // Do nothing. + } + if (timeout <= 0) { timeout = _get_frame_duration(); @@ -247,7 +247,6 @@ void AnimatedSprite2D::_notification(int p_what) { } texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false); - } break; } } diff --git a/scene/2d/audio_listener_2d.cpp b/scene/2d/audio_listener_2d.cpp index 8fae339756..eb463864e1 100644 --- a/scene/2d/audio_listener_2d.cpp +++ b/scene/2d/audio_listener_2d.cpp @@ -67,6 +67,7 @@ void AudioListener2D::_notification(int p_what) { make_current(); } } break; + case NOTIFICATION_EXIT_TREE: { if (!get_tree()->is_node_being_edited(this)) { if (is_current()) { diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index f8e30c2462..c1328badfb 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -36,70 +36,72 @@ #include "scene/resources/world_2d.h" void AudioStreamPlayer2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this); - if (autoplay && !Engine::get_singleton()->is_editor_hint()) { - play(); - } - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this); + if (autoplay && !Engine::get_singleton()->is_editor_hint()) { + play(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - stop(); - AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); - } + case NOTIFICATION_EXIT_TREE: { + stop(); + AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); + } break; - if (p_what == NOTIFICATION_PAUSED) { - if (!can_process()) { - // Node can't process so we start fading out to silence - set_stream_paused(true); - } - } + case NOTIFICATION_PAUSED: { + if (!can_process()) { + // Node can't process so we start fading out to silence. + set_stream_paused(true); + } + } break; - if (p_what == NOTIFICATION_UNPAUSED) { - set_stream_paused(false); - } + case NOTIFICATION_UNPAUSED: { + set_stream_paused(false); + } break; - if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - //update anything related to position first, if possible of course - if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { - _update_panning(); - } + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // Update anything related to position first, if possible of course. + if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { + _update_panning(); + } - if (setplay.get() >= 0 && stream.is_valid()) { - active.set(); - Ref<AudioStreamPlayback> new_playback = stream->instance_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); - setplay.set(-1); - } + if (setplay.get() >= 0 && stream.is_valid()) { + active.set(); + Ref<AudioStreamPlayback> new_playback = stream->instance_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); + setplay.set(-1); + } - if (!stream_playbacks.is_empty() && active.is_set()) { - // Stop playing if no longer active. - Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; - for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { - if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { - playbacks_to_remove.push_back(playback); + if (!stream_playbacks.is_empty() && active.is_set()) { + // Stop playing if no longer active. + Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { + playbacks_to_remove.push_back(playback); + } + } + // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. + for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { + stream_playbacks.erase(playback); + } + if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { + // This node is no longer actively playing audio. + active.clear(); + set_physics_process_internal(false); + } + if (!playbacks_to_remove.is_empty()) { + emit_signal(SNAME("finished")); } } - // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. - for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { - stream_playbacks.erase(playback); - } - if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { - // This node is no longer actively playing audio. - active.clear(); - set_physics_process_internal(false); - } - if (!playbacks_to_remove.is_empty()) { - emit_signal(SNAME("finished")); - } - } - while (stream_playbacks.size() > max_polyphony) { - AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]); - stream_playbacks.remove_at(0); - } + while (stream_playbacks.size() > max_polyphony) { + AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]); + stream_playbacks.remove_at(0); + } + } break; } } diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 548cd5de9a..390e6685b1 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -206,15 +206,7 @@ Transform2D Camera2D::get_camera_transform() { if (rotating) { xform.set_rotation(angle); } - xform.set_origin(screen_rect.position /*.floor()*/); - - /* - if (0) { - xform = get_global_transform() * xform; - } else { - xform.elements[2]+=get_global_transform().get_origin(); - } -*/ + xform.set_origin(screen_rect.position); return (xform).affine_inverse(); } @@ -224,14 +216,14 @@ void Camera2D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { _update_scroll(); - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_processing_internal() && !is_physics_processing_internal()) { _update_scroll(); } - } break; + case NOTIFICATION_ENTER_TREE: { ERR_FAIL_COND(!is_inside_tree()); if (custom_viewport && ObjectDB::get_instance(custom_viewport_id)) { @@ -256,8 +248,8 @@ void Camera2D::_notification(int p_what) { _update_process_callback(); _update_scroll(); first = true; - } break; + case NOTIFICATION_EXIT_TREE: { if (is_current()) { if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) { @@ -269,8 +261,8 @@ void Camera2D::_notification(int p_what) { remove_from_group(group_name); remove_from_group(canvas_group_name); viewport = nullptr; - } break; + #ifdef TOOLS_ENABLED case NOTIFICATION_DRAW: { if (!is_inside_tree() || !Engine::get_singleton()->is_editor_hint()) { diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index d0abed4a0c..7f7eae51a6 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -31,27 +31,32 @@ #include "canvas_modulate.h" void CanvasModulate::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_CANVAS) { - if (is_visible_in_tree()) { - RS::get_singleton()->canvas_set_modulate(get_canvas(), color); - add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } + switch (p_what) { + case NOTIFICATION_ENTER_CANVAS: { + if (is_visible_in_tree()) { + RS::get_singleton()->canvas_set_modulate(get_canvas(), color); + add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } + } break; - } else if (p_what == NOTIFICATION_EXIT_CANVAS) { - if (is_visible_in_tree()) { - RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); - remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } - } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (is_visible_in_tree()) { - RS::get_singleton()->canvas_set_modulate(get_canvas(), color); - add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } else { - RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); - remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); - } + case NOTIFICATION_EXIT_CANVAS: { + if (is_visible_in_tree()) { + RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); + remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible_in_tree()) { + RS::get_singleton()->canvas_set_modulate(get_canvas(), color); + add_to_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } else { + RS::get_singleton()->canvas_set_modulate(get_canvas(), Color(1, 1, 1, 1)); + remove_from_group("_canvas_modulate_" + itos(get_canvas().get_id())); + } - update_configuration_warnings(); + update_configuration_warnings(); + } break; } } diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 2923b287be..e3939130ec 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -102,26 +102,20 @@ void CollisionPolygon2D::_notification(int p_what) { _build_polygon(); _update_in_shape_owner(); } - - /*if (Engine::get_singleton()->is_editor_hint()) { - //display above all else - set_z_as_relative(false); - set_z_index(RS::CANVAS_ITEM_Z_MAX - 1); - }*/ - } break; + case NOTIFICATION_ENTER_TREE: { if (parent) { _update_in_shape_owner(); } - } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { _update_in_shape_owner(true); } - } break; + case NOTIFICATION_UNPARENTED: { if (parent) { parent->remove_shape_owner(owner_id); diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index a0520ca28f..db9a745436 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -59,34 +59,28 @@ void CollisionShape2D::_notification(int p_what) { } _update_in_shape_owner(); } - - /*if (Engine::get_singleton()->is_editor_hint()) { - //display above all else - set_z_as_relative(false); - set_z_index(RS::CANVAS_ITEM_Z_MAX - 1); - }*/ - } break; + case NOTIFICATION_ENTER_TREE: { if (parent) { _update_in_shape_owner(); } - } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { _update_in_shape_owner(true); } - } break; + case NOTIFICATION_UNPARENTED: { if (parent) { parent->remove_shape_owner(owner_id); } owner_id = 0; parent = nullptr; - } break; + case NOTIFICATION_DRAW: { ERR_FAIL_COND(!is_inside_tree()); diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 4673a99082..cd2153b132 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -1091,9 +1091,11 @@ void CPUParticles2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { set_process_internal(emitting); } break; + case NOTIFICATION_EXIT_TREE: { _set_redraw(false); } break; + case NOTIFICATION_DRAW: { // first update before rendering to avoid one frame delay after emitting starts if (emitting && (time == 0)) { @@ -1111,9 +1113,11 @@ void CPUParticles2D::_notification(int p_what) { RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); } break; + case NOTIFICATION_INTERNAL_PROCESS: { _update_internal(); } break; + case NOTIFICATION_TRANSFORM_CHANGED: { inv_emission_transform = get_global_transform().affine_inverse(); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 11c036ac9c..8b0840e7c8 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -377,154 +377,157 @@ void GPUParticles2D::restart() { } void GPUParticles2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - RID texture_rid; - Size2 size; - if (texture.is_valid()) { - texture_rid = texture->get_rid(); - size = texture->get_size(); - } else { - size = Size2(1, 1); - } - - if (trail_enabled) { - RS::get_singleton()->mesh_clear(mesh); - PackedVector2Array points; - PackedVector2Array uvs; - PackedInt32Array bone_indices; - PackedFloat32Array bone_weights; - PackedInt32Array indices; - - int total_segments = trail_sections * trail_section_subdivisions; - real_t depth = size.height * trail_sections; - - for (int j = 0; j <= total_segments; j++) { - real_t v = j; - v /= total_segments; - - real_t y = depth * v; - y = (depth * 0.5) - y; - - int bone = j / trail_section_subdivisions; - real_t blend = 1.0 - real_t(j % trail_section_subdivisions) / real_t(trail_section_subdivisions); - - real_t s = size.width; - - points.push_back(Vector2(-s * 0.5, 0)); - points.push_back(Vector2(+s * 0.5, 0)); - - uvs.push_back(Vector2(0, v)); - uvs.push_back(Vector2(1, v)); - - for (int i = 0; i < 2; i++) { - bone_indices.push_back(bone); - bone_indices.push_back(MIN(trail_sections, bone + 1)); - bone_indices.push_back(0); - bone_indices.push_back(0); + switch (p_what) { + case NOTIFICATION_DRAW: { + RID texture_rid; + Size2 size; + if (texture.is_valid()) { + texture_rid = texture->get_rid(); + size = texture->get_size(); + } else { + size = Size2(1, 1); + } - bone_weights.push_back(blend); - bone_weights.push_back(1.0 - blend); - bone_weights.push_back(0); - bone_weights.push_back(0); + if (trail_enabled) { + RS::get_singleton()->mesh_clear(mesh); + PackedVector2Array points; + PackedVector2Array uvs; + PackedInt32Array bone_indices; + PackedFloat32Array bone_weights; + PackedInt32Array indices; + + int total_segments = trail_sections * trail_section_subdivisions; + real_t depth = size.height * trail_sections; + + for (int j = 0; j <= total_segments; j++) { + real_t v = j; + v /= total_segments; + + real_t y = depth * v; + y = (depth * 0.5) - y; + + int bone = j / trail_section_subdivisions; + real_t blend = 1.0 - real_t(j % trail_section_subdivisions) / real_t(trail_section_subdivisions); + + real_t s = size.width; + + points.push_back(Vector2(-s * 0.5, 0)); + points.push_back(Vector2(+s * 0.5, 0)); + + uvs.push_back(Vector2(0, v)); + uvs.push_back(Vector2(1, v)); + + for (int i = 0; i < 2; i++) { + bone_indices.push_back(bone); + bone_indices.push_back(MIN(trail_sections, bone + 1)); + bone_indices.push_back(0); + bone_indices.push_back(0); + + bone_weights.push_back(blend); + bone_weights.push_back(1.0 - blend); + bone_weights.push_back(0); + bone_weights.push_back(0); + } + + if (j > 0) { + int base = j * 2 - 2; + indices.push_back(base + 0); + indices.push_back(base + 1); + indices.push_back(base + 2); + + indices.push_back(base + 1); + indices.push_back(base + 3); + indices.push_back(base + 2); + } } - if (j > 0) { - int base = j * 2 - 2; - indices.push_back(base + 0); - indices.push_back(base + 1); - indices.push_back(base + 2); - - indices.push_back(base + 1); - indices.push_back(base + 3); - indices.push_back(base + 2); + Array arr; + arr.resize(RS::ARRAY_MAX); + arr[RS::ARRAY_VERTEX] = points; + arr[RS::ARRAY_TEX_UV] = uvs; + arr[RS::ARRAY_BONES] = bone_indices; + arr[RS::ARRAY_WEIGHTS] = bone_weights; + arr[RS::ARRAY_INDEX] = indices; + + RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + + Vector<Transform3D> xforms; + for (int i = 0; i <= trail_sections; i++) { + Transform3D xform; + /* + xform.origin.y = depth / 2.0 - size.height * real_t(i); + xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */ + xforms.push_back(xform); } - } - Array arr; - arr.resize(RS::ARRAY_MAX); - arr[RS::ARRAY_VERTEX] = points; - arr[RS::ARRAY_TEX_UV] = uvs; - arr[RS::ARRAY_BONES] = bone_indices; - arr[RS::ARRAY_WEIGHTS] = bone_weights; - arr[RS::ARRAY_INDEX] = indices; - - RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); - - Vector<Transform3D> xforms; - for (int i = 0; i <= trail_sections; i++) { - Transform3D xform; - /* - xform.origin.y = depth / 2.0 - size.height * real_t(i); - xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */ - xforms.push_back(xform); - } - - RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms); + RS::get_singleton()->particles_set_trail_bind_poses(particles, xforms); - } else { - RS::get_singleton()->mesh_clear(mesh); + } else { + RS::get_singleton()->mesh_clear(mesh); - Vector<Vector2> points = { - Vector2(-size.x / 2.0, -size.y / 2.0), - Vector2(size.x / 2.0, -size.y / 2.0), - Vector2(size.x / 2.0, size.y / 2.0), - Vector2(-size.x / 2.0, size.y / 2.0) - }; + Vector<Vector2> points = { + Vector2(-size.x / 2.0, -size.y / 2.0), + Vector2(size.x / 2.0, -size.y / 2.0), + Vector2(size.x / 2.0, size.y / 2.0), + Vector2(-size.x / 2.0, size.y / 2.0) + }; - Vector<Vector2> uvs = { - Vector2(0, 0), - Vector2(1, 0), - Vector2(1, 1), - Vector2(0, 1) - }; + Vector<Vector2> uvs = { + Vector2(0, 0), + Vector2(1, 0), + Vector2(1, 1), + Vector2(0, 1) + }; - Vector<int> indices = { 0, 1, 2, 0, 2, 3 }; + Vector<int> indices = { 0, 1, 2, 0, 2, 3 }; - Array arr; - arr.resize(RS::ARRAY_MAX); - arr[RS::ARRAY_VERTEX] = points; - arr[RS::ARRAY_TEX_UV] = uvs; - arr[RS::ARRAY_INDEX] = indices; + Array arr; + arr.resize(RS::ARRAY_MAX); + arr[RS::ARRAY_VERTEX] = points; + arr[RS::ARRAY_TEX_UV] = uvs; + arr[RS::ARRAY_INDEX] = indices; - RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); - RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform3D>()); - } - RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid); + RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform3D>()); + } + RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid); #ifdef TOOLS_ENABLED - if (show_visibility_rect) { - draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); - } + if (show_visibility_rect) { + draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); + } #endif - } - - if (p_what == NOTIFICATION_ENTER_TREE) { - if (sub_emitter != NodePath()) { - _attach_sub_emitter(); - } - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - RS::get_singleton()->particles_set_subemitter(particles, RID()); - } + } break; - if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { - if (can_process()) { - RS::get_singleton()->particles_set_speed_scale(particles, speed_scale); - } else { - RS::get_singleton()->particles_set_speed_scale(particles, 0); - } - } + case NOTIFICATION_ENTER_TREE: { + if (sub_emitter != NodePath()) { + _attach_sub_emitter(); + } + } break; + + case NOTIFICATION_EXIT_TREE: { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } break; + + case NOTIFICATION_PAUSED: + case NOTIFICATION_UNPAUSED: { + if (can_process()) { + RS::get_singleton()->particles_set_speed_scale(particles, speed_scale); + } else { + RS::get_singleton()->particles_set_speed_scale(particles, 0); + } + } break; - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - _update_particle_emission_transform(); - } + case NOTIFICATION_TRANSFORM_CHANGED: { + _update_particle_emission_transform(); + } break; - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (one_shot && !is_emitting()) { - notify_property_list_changed(); - set_process_internal(false); - } + case NOTIFICATION_INTERNAL_PROCESS: { + if (one_shot && !is_emitting()) { + notify_property_list_changed(); + set_process_internal(false); + } + } break; } } diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index 62a77fb969..c2773191ea 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -128,7 +128,7 @@ void Joint2D::set_node_a(const NodePath &p_node_a) { return; } - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); } @@ -145,7 +145,7 @@ void Joint2D::set_node_b(const NodePath &p_node_b) { return; } - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); } @@ -159,14 +159,18 @@ NodePath Joint2D::get_node_b() const { void Joint2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { + case NOTIFICATION_POST_ENTER_TREE: { + if (is_configured()) { + _disconnect_signals(); + } _update_joint(); } break; + case NOTIFICATION_EXIT_TREE: { - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); - _update_joint(true); } + _update_joint(true); } break; } } @@ -186,7 +190,9 @@ void Joint2D::set_exclude_nodes_from_collision(bool p_enable) { if (exclude_from_collision == p_enable) { return; } - + if (is_configured()) { + _disconnect_signals(); + } _update_joint(true); exclude_from_collision = p_enable; _update_joint(); diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index f496e1aac2..ba168eeb86 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -192,21 +192,24 @@ Light2D::BlendMode Light2D::get_blend_mode() const { } void Light2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas()); - _update_light_visibility(); - } - - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform()); - } - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - _update_light_visibility(); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID()); - _update_light_visibility(); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, get_canvas()); + _update_light_visibility(); + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { + RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform()); + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + _update_light_visibility(); + } break; + + case NOTIFICATION_EXIT_TREE: { + RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID()); + _update_light_visibility(); + } break; } } diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 0a7e4c8841..0310817592 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -29,9 +29,9 @@ /*************************************************************************/ #include "light_occluder_2d.h" -#include "core/math/geometry_2d.h" #include "core/config/engine.h" +#include "core/math/geometry_2d.h" #define LINE_GRAB_WIDTH 8 @@ -158,42 +158,46 @@ void LightOccluder2D::_poly_changed() { } void LightOccluder2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_CANVAS) { - RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas()); - RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); - RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); - } - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); - } - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); - } - - if (p_what == NOTIFICATION_DRAW) { - if (Engine::get_singleton()->is_editor_hint()) { - if (occluder_polygon.is_valid()) { - Vector<Vector2> poly = occluder_polygon->get_polygon(); - - if (poly.size()) { - if (occluder_polygon->is_closed()) { - Vector<Color> color; - color.push_back(Color(0, 0, 0, 0.6)); - draw_polygon(Variant(poly), color); - } else { - int ps = poly.size(); - const Vector2 *r = poly.ptr(); - for (int i = 0; i < ps - 1; i++) { - draw_line(r[i], r[i + 1], Color(0, 0, 0, 0.6), 3); + switch (p_what) { + case NOTIFICATION_ENTER_CANVAS: { + RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas()); + RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); + RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { + RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + RS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible_in_tree()); + } break; + + case NOTIFICATION_DRAW: { + if (Engine::get_singleton()->is_editor_hint()) { + if (occluder_polygon.is_valid()) { + Vector<Vector2> poly = occluder_polygon->get_polygon(); + + if (poly.size()) { + if (occluder_polygon->is_closed()) { + Vector<Color> color; + color.push_back(Color(0, 0, 0, 0.6)); + draw_polygon(Variant(poly), color); + } else { + int ps = poly.size(); + const Vector2 *r = poly.ptr(); + for (int i = 0; i < ps - 1; i++) { + draw_line(r[i], r[i + 1], Color(0, 0, 0, 0.6), 3); + } } } } } - } - } + } break; - if (p_what == NOTIFICATION_EXIT_CANVAS) { - RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID()); + case NOTIFICATION_EXIT_CANVAS: { + RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID()); + } break; } } diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 7f2290bdc7..2716bb2e25 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -228,9 +228,9 @@ Line2D::LineCapMode Line2D::get_end_cap_mode() const { void Line2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_DRAW: + case NOTIFICATION_DRAW: { _draw(); - break; + } break; } } @@ -247,10 +247,7 @@ float Line2D::get_sharp_limit() const { } void Line2D::set_round_precision(int p_precision) { - if (p_precision < 1) { - p_precision = 1; - } - _round_precision = p_precision; + _round_precision = MAX(1, p_precision); update(); } @@ -409,7 +406,7 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode"); ADD_GROUP("Border", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sharp_limit"), "set_sharp_limit", "get_sharp_limit"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision"), "set_round_precision", "get_round_precision"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision", PROPERTY_HINT_RANGE, "1,32,1"), "set_round_precision", "get_round_precision"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "get_antialiased"); BIND_ENUM_CONSTANT(LINE_JOINT_SHARP); diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index 5f8a46ad2e..178addd62d 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -29,13 +29,16 @@ /*************************************************************************/ #include "mesh_instance_2d.h" + #include "scene/scene_string_names.h" void MeshInstance2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - if (mesh.is_valid()) { - draw_mesh(mesh, texture); - } + switch (p_what) { + case NOTIFICATION_DRAW: { + if (mesh.is_valid()) { + draw_mesh(mesh, texture); + } + } break; } } diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp index e1af99d931..8f72ff1757 100644 --- a/scene/2d/multimesh_instance_2d.cpp +++ b/scene/2d/multimesh_instance_2d.cpp @@ -29,13 +29,16 @@ /*************************************************************************/ #include "multimesh_instance_2d.h" + #include "scene/scene_string_names.h" void MultiMeshInstance2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - if (multimesh.is_valid()) { - draw_multimesh(multimesh, texture); - } + switch (p_what) { + case NOTIFICATION_DRAW: { + if (multimesh.is_valid()) { + draw_multimesh(multimesh, texture); + } + } break; } } diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 1bbf7236c5..78b5a39e9a 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -97,10 +97,12 @@ void NavigationAgent2D::_notification(int p_what) { } set_physics_process_internal(true); } break; + case NOTIFICATION_EXIT_TREE: { agent_parent = nullptr; set_physics_process_internal(false); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position()); diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 90d993f20b..65f7adb7a6 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -63,17 +63,21 @@ void NavigationObstacle2D::_notification(int p_what) { } set_physics_process_internal(true); } break; + case NOTIFICATION_EXIT_TREE: { parent_node2d = nullptr; set_physics_process_internal(false); } break; + case NOTIFICATION_PARENTED: { parent_node2d = Object::cast_to<Node2D>(get_parent()); reevaluate_agent_radius(); } break; + case NOTIFICATION_UNPARENTED: { parent_node2d = nullptr; } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (parent_node2d) { NavigationServer2D::get_singleton()->agent_set_position(agent, parent_node2d->get_global_position()); diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 99d8b0f604..34ac02a82a 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -406,15 +406,18 @@ void NavigationRegion2D::_notification(int p_what) { NavigationServer2D::get_singleton_mut()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } } break; + case NOTIFICATION_TRANSFORM_CHANGED: { NavigationServer2D::get_singleton()->region_set_transform(region, get_global_transform()); } break; + case NOTIFICATION_EXIT_TREE: { NavigationServer2D::get_singleton()->region_set_map(region, RID()); if (enabled) { NavigationServer2D::get_singleton_mut()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } } break; + case NOTIFICATION_DRAW: { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) { Vector<Vector2> verts = navpoly->get_vertices(); diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index f75baaab0f..dcbb6507f5 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "parallax_background.h" + #include "parallax_layer.h" void ParallaxBackground::_notification(int p_what) { @@ -36,8 +37,8 @@ void ParallaxBackground::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { group_name = "__cameras_" + itos(get_viewport().get_id()); add_to_group(group_name); - } break; + case NOTIFICATION_EXIT_TREE: { remove_from_group(group_name); } break; diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index ff572c9b9a..849412a7ae 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -99,6 +99,7 @@ void ParallaxLayer::_notification(int p_what) { orig_scale = get_scale(); _update_mirroring(); } break; + case NOTIFICATION_EXIT_TREE: { if (Engine::get_singleton()->is_editor_hint()) { break; diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 742756113f..d001652ca3 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -86,36 +86,41 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc #endif void Path2D::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW && curve.is_valid()) { - //draw the curve!! + switch (p_what) { + // Draw the curve if navigation debugging is enabled. + case NOTIFICATION_DRAW: { + if (!curve.is_valid()) { + break; + } - if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) { - return; - } + if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) { + return; + } - if (curve->get_point_count() < 2) { - return; - } + if (curve->get_point_count() < 2) { + return; + } #ifdef TOOLS_ENABLED - const real_t line_width = 2 * EDSCALE; + const real_t line_width = 2 * EDSCALE; #else - const real_t line_width = 2; + const real_t line_width = 2; #endif - const Color color = Color(0.5, 0.6, 1.0, 0.7); + const Color color = Color(0.5, 0.6, 1.0, 0.7); - _cached_draw_pts.resize(curve->get_point_count() * 8); - int count = 0; + _cached_draw_pts.resize(curve->get_point_count() * 8); + int count = 0; - for (int i = 0; i < curve->get_point_count(); i++) { - for (int j = 0; j < 8; j++) { - real_t frac = j * (1.0 / 8.0); - Vector2 p = curve->interpolate(i, frac); - _cached_draw_pts.set(count++, p); + for (int i = 0; i < curve->get_point_count(); i++) { + for (int j = 0; j < 8; j++) { + real_t frac = j * (1.0 / 8.0); + Vector2 p = curve->interpolate(i, frac); + _cached_draw_pts.set(count++, p); + } } - } - draw_polyline(_cached_draw_pts, color, line_width, true); + draw_polyline(_cached_draw_pts, color, line_width, true); + } break; } } @@ -226,8 +231,8 @@ void PathFollow2D::_notification(int p_what) { if (path) { _update_transform(); } - } break; + case NOTIFICATION_EXIT_TREE: { path = nullptr; } break; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index fb611addf8..eb4d9d6445 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -906,7 +906,7 @@ void RigidDynamicBody2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); //used for warnings and only in editor + set_notify_local_transform(true); // Used for warnings and only in editor. } } break; @@ -1168,7 +1168,7 @@ bool CharacterBody2D::move_and_slide() { if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) { current_platform_velocity = current_platform_velocity.slide(up_direction); } - motion_velocity += current_platform_velocity; + velocity += current_platform_velocity; } } @@ -1176,7 +1176,7 @@ bool CharacterBody2D::move_and_slide() { } void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { - Vector2 motion = motion_velocity * p_delta; + Vector2 motion = velocity * p_delta; Vector2 motion_slide_up = motion.slide(up_direction); Vector2 prev_floor_normal = floor_normal; @@ -1194,7 +1194,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // If the platform's ceiling push down the body. bool apply_ceiling_velocity = false; bool first_slide = true; - bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0; + bool vel_dir_facing_up = velocity.dot(up_direction) > 0; Vector2 last_travel; for (int iteration = 0; iteration < max_slides; ++iteration) { @@ -1211,26 +1211,26 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo motion_results.push_back(result); _set_collision_direction(result); - // If we hit a ceiling platform, we set the vertical motion_velocity to at least the platform one. + // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. if (on_ceiling && result.collider_velocity != Vector2() && result.collider_velocity.dot(up_direction) < 0) { // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (result.collision_normal + up_direction).length() < 0.01) { apply_ceiling_velocity = true; Vector2 ceiling_vertical_velocity = up_direction * up_direction.dot(result.collider_velocity); - Vector2 motion_vertical_velocity = up_direction * up_direction.dot(motion_velocity); + Vector2 motion_vertical_velocity = up_direction * up_direction.dot(velocity); if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { - motion_velocity = ceiling_vertical_velocity + motion_velocity.slide(up_direction); + velocity = ceiling_vertical_velocity + velocity.slide(up_direction); } } } - if (on_floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) { + if (on_floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { Transform2D gt = get_global_transform(); if (result.travel.length() <= margin + CMP_EPSILON) { gt.elements[2] -= result.travel; } set_global_transform(gt); - motion_velocity = Vector2(); + velocity = Vector2(); last_motion = Vector2(); motion = Vector2(); break; @@ -1254,7 +1254,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo } // Determines if you are on the ground. _snap_on_floor(true, false); - motion_velocity = Vector2(); + velocity = Vector2(); last_motion = Vector2(); motion = Vector2(); break; @@ -1276,7 +1276,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Regular sliding, the last part of the test handle the case when you don't want to slide on the ceiling. else if ((sliding_enabled || !on_floor) && (!on_ceiling || slide_on_ceiling || !vel_dir_facing_up) && !apply_ceiling_velocity) { Vector2 slide_motion = result.remainder.slide(result.collision_normal); - if (slide_motion.dot(motion_velocity) > 0.0) { + if (slide_motion.dot(velocity) > 0.0) { motion = slide_motion; } else { motion = Vector2(); @@ -1284,10 +1284,10 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (slide_on_ceiling && on_ceiling) { // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. if (vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(result.collision_normal); + velocity = velocity.slide(result.collision_normal); } else { // Avoid acceleration in slope when falling. - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } } } @@ -1295,7 +1295,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo else { motion = result.remainder; if (on_ceiling && !slide_on_ceiling && vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); motion = motion.slide(up_direction); } } @@ -1329,23 +1329,23 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Scales the horizontal velocity according to the wall slope. if (is_on_wall_only() && motion_slide_up.dot(motion_results.get(0).collision_normal) < 0) { - Vector2 slide_motion = motion_velocity.slide(motion_results.get(0).collision_normal); + Vector2 slide_motion = velocity.slide(motion_results.get(0).collision_normal); if (motion_slide_up.dot(slide_motion) < 0) { - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } else { - // Keeps the vertical motion from motion_velocity and add the horizontal motion of the projection. - motion_velocity = up_direction * up_direction.dot(motion_velocity) + slide_motion.slide(up_direction); + // Keeps the vertical motion from velocity and add the horizontal motion of the projection. + velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); } } // Reset the gravity accumulation when touching the ground. if (on_floor && !vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); } } void CharacterBody2D::_move_and_slide_floating(double p_delta) { - Vector2 motion = motion_velocity * p_delta; + Vector2 motion = velocity * p_delta; platform_rid = RID(); platform_object_id = ObjectID(); @@ -1370,7 +1370,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) { break; } - if (wall_min_slide_angle != 0 && result.get_angle(-motion_velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + if (wall_min_slide_angle != 0 && result.get_angle(-velocity.normalized()) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { motion = Vector2(); } else if (first_slide) { Vector2 motion_slide_norm = result.remainder.slide(result.collision_normal).normalized(); @@ -1379,7 +1379,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) { motion = result.remainder.slide(result.collision_normal); } - if (motion.dot(motion_velocity) <= 0.0) { + if (motion.dot(velocity) <= 0.0) { motion = Vector2(); } } @@ -1471,12 +1471,12 @@ void CharacterBody2D::_set_platform_data(const PhysicsServer2D::MotionResult &p_ platform_layer = PhysicsServer2D::get_singleton()->body_get_collision_layer(platform_rid); } -const Vector2 &CharacterBody2D::get_motion_velocity() const { - return motion_velocity; +const Vector2 &CharacterBody2D::get_velocity() const { + return velocity; } -void CharacterBody2D::set_motion_velocity(const Vector2 &p_velocity) { - motion_velocity = p_velocity; +void CharacterBody2D::set_velocity(const Vector2 &p_velocity) { + velocity = p_velocity; } bool CharacterBody2D::is_on_floor() const { @@ -1697,8 +1697,8 @@ void CharacterBody2D::_notification(int p_what) { void CharacterBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide); - ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody2D::set_motion_velocity); - ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody2D::get_motion_velocity); + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity); ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); @@ -1750,7 +1750,7 @@ void CharacterBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_motion_velocity", "get_motion_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index cfaa2570fb..8d9e31d4dd 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -337,8 +337,8 @@ public: }; bool move_and_slide(); - const Vector2 &get_motion_velocity() const; - void set_motion_velocity(const Vector2 &p_velocity); + const Vector2 &get_velocity() const; + void set_velocity(const Vector2 &p_velocity); bool is_on_floor() const; bool is_on_floor_only() const; @@ -378,7 +378,7 @@ private: Vector2 up_direction = Vector2(0.0, -1.0); uint32_t moving_platform_floor_layers = UINT32_MAX; uint32_t moving_platform_wall_layers = 0; - Vector2 motion_velocity; + Vector2 velocity; Vector2 floor_normal; Vector2 platform_velocity; diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 1f4dec6864..1fe4adb4db 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -428,15 +428,6 @@ Vector<Color> Polygon2D::get_vertex_colors() const { void Polygon2D::set_texture(const Ref<Texture2D> &p_texture) { texture = p_texture; - - /*if (texture.is_valid()) { - uint32_t flags=texture->get_flags(); - flags&=~Texture::FLAG_REPEAT; - if (tex_tile) - flags|=Texture::FLAG_REPEAT; - - texture->set_flags(flags); - }*/ update(); } diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index 67aff9c520..518593cee1 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -90,6 +90,7 @@ void Position2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { update(); } break; + case NOTIFICATION_DRAW: { if (!is_inside_tree()) { break; @@ -97,7 +98,6 @@ void Position2D::_notification(int p_what) { if (Engine::get_singleton()->is_editor_hint()) { _draw_cross(); } - } break; } } diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 8b69d52c32..37db9211e1 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -150,11 +150,11 @@ void RayCast2D::_notification(int p_what) { } } } break; + case NOTIFICATION_EXIT_TREE: { if (enabled) { set_physics_process_internal(false); } - } break; case NOTIFICATION_DRAW: { @@ -163,16 +163,13 @@ void RayCast2D::_notification(int p_what) { break; } _draw_debug_shape(); - } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) { break; } - _update_raycast_state(); - } break; } } diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index e9431efde3..429f0f6f6f 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -115,8 +115,8 @@ void RemoteTransform2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { _update_cache(); - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_inside_tree()) { break; @@ -125,7 +125,6 @@ void RemoteTransform2D::_notification(int p_what) { if (cache.is_valid()) { _update_remote(); } - } break; } } diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index 24199c96b5..a2c5d73b59 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -201,6 +201,7 @@ void ShapeCast2D::_notification(int p_what) { } } } break; + case NOTIFICATION_EXIT_TREE: { if (enabled) { set_physics_process_internal(false); @@ -254,6 +255,7 @@ void ShapeCast2D::_notification(int p_what) { } #endif } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) { break; diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index a12147b7fd..360650c724 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -93,223 +93,228 @@ void Bone2D::_get_property_list(List<PropertyInfo> *p_list) const { } void Bone2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - Node *parent = get_parent(); - parent_bone = Object::cast_to<Bone2D>(parent); - skeleton = nullptr; - while (parent) { - skeleton = Object::cast_to<Skeleton2D>(parent); - if (skeleton) { - break; - } - if (!Object::cast_to<Bone2D>(parent)) { - break; //skeletons must be chained to Bone2Ds. - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + Node *parent = get_parent(); + parent_bone = Object::cast_to<Bone2D>(parent); + skeleton = nullptr; + while (parent) { + skeleton = Object::cast_to<Skeleton2D>(parent); + if (skeleton) { + break; + } + if (!Object::cast_to<Bone2D>(parent)) { + break; //skeletons must be chained to Bone2Ds. + } - parent = parent->get_parent(); - } + parent = parent->get_parent(); + } - if (skeleton) { - Skeleton2D::Bone bone; - bone.bone = this; - skeleton->bones.push_back(bone); - skeleton->_make_bone_setup_dirty(); - } + if (skeleton) { + Skeleton2D::Bone bone; + bone.bone = this; + skeleton->bones.push_back(bone); + skeleton->_make_bone_setup_dirty(); + } - cache_transform = get_transform(); - copy_transform_to_cache = true; + cache_transform = get_transform(); + copy_transform_to_cache = true; #ifdef TOOLS_ENABLED - // Only draw the gizmo in the editor! - if (Engine::get_singleton()->is_editor_hint() == false) { - return; - } + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; + } - update(); + update(); #endif // TOOLS_ENABLED - } + } break; - else if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (skeleton) { - skeleton->_make_transform_dirty(); - } - if (copy_transform_to_cache) { - cache_transform = get_transform(); - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (skeleton) { + skeleton->_make_transform_dirty(); + } + if (copy_transform_to_cache) { + cache_transform = get_transform(); + } #ifdef TOOLS_ENABLED - // Only draw the gizmo in the editor! - if (Engine::get_singleton()->is_editor_hint() == false) { - return; - } + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; + } - update(); + update(); - if (get_parent()) { - Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent()); - if (parent_bone) { - parent_bone->update(); + if (get_parent()) { + Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent()); + if (parent_bone) { + parent_bone->update(); + } } - } #endif // TOOLS_ENABLED - } + } break; - else if (p_what == NOTIFICATION_MOVED_IN_PARENT) { - if (skeleton) { - skeleton->_make_bone_setup_dirty(); - } - if (copy_transform_to_cache) { - cache_transform = get_transform(); - } - } + case NOTIFICATION_MOVED_IN_PARENT: { + if (skeleton) { + skeleton->_make_bone_setup_dirty(); + } + if (copy_transform_to_cache) { + cache_transform = get_transform(); + } + } break; - else if (p_what == NOTIFICATION_EXIT_TREE) { - if (skeleton) { - for (int i = 0; i < skeleton->bones.size(); i++) { - if (skeleton->bones[i].bone == this) { - skeleton->bones.remove_at(i); - break; + case NOTIFICATION_EXIT_TREE: { + if (skeleton) { + for (int i = 0; i < skeleton->bones.size(); i++) { + if (skeleton->bones[i].bone == this) { + skeleton->bones.remove_at(i); + break; + } } + skeleton->_make_bone_setup_dirty(); + skeleton = nullptr; } - skeleton->_make_bone_setup_dirty(); - skeleton = nullptr; - } - parent_bone = nullptr; - set_transform(cache_transform); - } + parent_bone = nullptr; + set_transform(cache_transform); + } break; + + case NOTIFICATION_READY: { + if (autocalculate_length_and_angle) { + calculate_length_and_rotation(); + } + } break; - else if (p_what == NOTIFICATION_READY) { - if (autocalculate_length_and_angle) { - calculate_length_and_rotation(); - } - } #ifdef TOOLS_ENABLED - else if (p_what == NOTIFICATION_EDITOR_PRE_SAVE || p_what == NOTIFICATION_EDITOR_POST_SAVE) { - Transform2D tmp_trans = get_transform(); - set_transform(cache_transform); - cache_transform = tmp_trans; - } - // Bone2D Editor gizmo drawing: + case NOTIFICATION_EDITOR_PRE_SAVE: + case NOTIFICATION_EDITOR_POST_SAVE: { + Transform2D tmp_trans = get_transform(); + set_transform(cache_transform); + cache_transform = tmp_trans; + } break; + + // Bone2D Editor gizmo drawing: #ifndef _MSC_VER #warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin #endif - else if (p_what == NOTIFICATION_DRAW) { - // Only draw the gizmo in the editor! - if (Engine::get_singleton()->is_editor_hint() == false) { - return; - } - - if (editor_gizmo_rid.is_null()) { - editor_gizmo_rid = RenderingServer::get_singleton()->canvas_item_create(); - RenderingServer::get_singleton()->canvas_item_set_parent(editor_gizmo_rid, get_canvas_item()); - RenderingServer::get_singleton()->canvas_item_set_z_as_relative_to_parent(editor_gizmo_rid, true); - RenderingServer::get_singleton()->canvas_item_set_z_index(editor_gizmo_rid, 10); - } - RenderingServer::get_singleton()->canvas_item_clear(editor_gizmo_rid); - - if (!_editor_show_bone_gizmo) { - return; - } - - // Undo scaling - Transform2D editor_gizmo_trans = Transform2D(); - editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale()); - RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans); - - Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); - Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); - Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); - Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); - Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); - - bool Bone2D_found = false; - for (int i = 0; i < get_child_count(); i++) { - Bone2D *child_node = nullptr; - child_node = Object::cast_to<Bone2D>(get_child(i)); - if (!child_node) { - continue; + case NOTIFICATION_DRAW: { + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; } - Bone2D_found = true; - - Vector<Vector2> bone_shape; - Vector<Vector2> bone_shape_outline; - _editor_get_bone_shape(&bone_shape, &bone_shape_outline, child_node); - - Vector<Color> colors; - if (has_meta("_local_pose_override_enabled_")) { - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - } else { - colors.push_back(bone_color1); - colors.push_back(bone_color2); - colors.push_back(bone_color1); - colors.push_back(bone_color2); + if (editor_gizmo_rid.is_null()) { + editor_gizmo_rid = RenderingServer::get_singleton()->canvas_item_create(); + RenderingServer::get_singleton()->canvas_item_set_parent(editor_gizmo_rid, get_canvas_item()); + RenderingServer::get_singleton()->canvas_item_set_z_as_relative_to_parent(editor_gizmo_rid, true); + RenderingServer::get_singleton()->canvas_item_set_z_index(editor_gizmo_rid, 10); } + RenderingServer::get_singleton()->canvas_item_clear(editor_gizmo_rid); - Vector<Color> outline_colors; - if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - } else { - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); + if (!_editor_show_bone_gizmo) { + return; } - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); - } - - if (!Bone2D_found) { - Vector<Vector2> bone_shape; - Vector<Vector2> bone_shape_outline; + // Undo scaling + Transform2D editor_gizmo_trans = Transform2D(); + editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale()); + RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans); + + Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); + Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); + Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); + Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); + Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); + + bool Bone2D_found = false; + for (int i = 0; i < get_child_count(); i++) { + Bone2D *child_node = nullptr; + child_node = Object::cast_to<Bone2D>(get_child(i)); + if (!child_node) { + continue; + } + Bone2D_found = true; + + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + + _editor_get_bone_shape(&bone_shape, &bone_shape_outline, child_node); + + Vector<Color> colors; + if (has_meta("_local_pose_override_enabled_")) { + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + } else { + colors.push_back(bone_color1); + colors.push_back(bone_color2); + colors.push_back(bone_color1); + colors.push_back(bone_color2); + } - _editor_get_bone_shape(&bone_shape, &bone_shape_outline, nullptr); + Vector<Color> outline_colors; + if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + } else { + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + } - Vector<Color> colors; - if (has_meta("_local_pose_override_enabled_")) { - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - } else { - colors.push_back(bone_color1); - colors.push_back(bone_color2); - colors.push_back(bone_color1); - colors.push_back(bone_color2); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); } - Vector<Color> outline_colors; - if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - } else { - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - } + if (!Bone2D_found) { + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + + _editor_get_bone_shape(&bone_shape, &bone_shape_outline, nullptr); + + Vector<Color> colors; + if (has_meta("_local_pose_override_enabled_")) { + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + } else { + colors.push_back(bone_color1); + colors.push_back(bone_color2); + colors.push_back(bone_color1); + colors.push_back(bone_color2); + } - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); - RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); - } + Vector<Color> outline_colors; + if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + } else { + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + } + + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); + } + } break; +#endif // TOOLS_ENABLED } -#endif // TOOLS_ENALBED } #ifdef TOOLS_ENABLED diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index 389fa0388f..facd164a0e 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -122,11 +122,6 @@ void Sprite2D::_notification(int p_what) { RID ci = get_canvas_item(); - /* - texture->draw(ci,Point2()); - break; - */ - Rect2 src_rect, dst_rect; bool filter_clip_enabled; _get_rects(src_rect, dst_rect, filter_clip_enabled); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index cd39e08682..db33e6561a 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -489,6 +489,7 @@ void TileMap::_notification(int p_what) { _clear_internals(); _recreate_internals(); } break; + case NOTIFICATION_EXIT_TREE: { _clear_internals(); } break; @@ -980,7 +981,7 @@ void TileMap::_recompute_rect_cache() { void TileMap::_rendering_notification(int p_what) { switch (p_what) { - case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: { + case NOTIFICATION_VISIBILITY_CHANGED: { bool visible = is_visible_in_tree(); for (int layer = 0; layer < (int)layers.size(); layer++) { for (KeyValue<Vector2i, TileMapQuadrant> &E_quadrant : layers[layer].quadrant_map) { @@ -997,7 +998,8 @@ void TileMap::_rendering_notification(int p_what) { } } } break; - case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { + + case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_inside_tree()) { return; } @@ -1016,7 +1018,8 @@ void TileMap::_rendering_notification(int p_what) { } } } break; - case CanvasItem::NOTIFICATION_DRAW: { + + case NOTIFICATION_DRAW: { if (tile_set.is_valid()) { RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), is_y_sort_enabled()); } @@ -1369,7 +1372,7 @@ void TileMap::draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSe void TileMap::_physics_notification(int p_what) { switch (p_what) { - case CanvasItem::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { bool in_editor = false; #ifdef TOOLS_ENABLED in_editor = Engine::get_singleton()->is_editor_hint(); @@ -1382,7 +1385,8 @@ void TileMap::_physics_notification(int p_what) { set_notify_local_transform(true); } } break; - case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { + + case NOTIFICATION_TRANSFORM_CHANGED: { bool in_editor = false; #ifdef TOOLS_ENABLED in_editor = Engine::get_singleton()->is_editor_hint(); @@ -1404,6 +1408,7 @@ void TileMap::_physics_notification(int p_what) { } } } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { bool in_editor = false; #ifdef TOOLS_ENABLED @@ -1600,7 +1605,7 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { void TileMap::_navigation_notification(int p_what) { switch (p_what) { - case CanvasItem::NOTIFICATION_TRANSFORM_CHANGED: { + case NOTIFICATION_TRANSFORM_CHANGED: { if (is_inside_tree()) { for (int layer = 0; layer < (int)layers.size(); layer++) { Transform2D tilemap_xform = get_global_transform(); @@ -1992,6 +1997,10 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c } } +void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) { + set_cell(p_layer, p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); +} + int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSet::INVALID_SOURCE); @@ -3617,7 +3626,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_visibility_mode", "navigation_visibility_mode"), &TileMap::set_navigation_visibility_mode); ClassDB::bind_method(D_METHOD("get_navigation_visibility_mode"), &TileMap::get_navigation_visibility_mode); - ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE)); + ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell); ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id); ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords); ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 0da04bfeae..a0655dea2a 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -321,7 +321,8 @@ public: VisibilityMode get_navigation_visibility_mode(); // Cells accessors. - void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE); + void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); + void erase_cell(int p_layer, const Vector2i &p_coords); int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const; diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index ff186b01f2..9a68c17269 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -134,8 +134,8 @@ void TouchScreenButton::_notification(int p_what) { draw_set_transform_matrix(get_canvas_transform().translated(pos)); shape->draw(get_canvas_item(), draw_col); } - } break; + case NOTIFICATION_ENTER_TREE: { if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY) { return; @@ -145,13 +145,14 @@ void TouchScreenButton::_notification(int p_what) { if (!Engine::get_singleton()->is_editor_hint()) { set_process_input(is_visible_in_tree()); } - } break; + case NOTIFICATION_EXIT_TREE: { if (is_pressed()) { _release(true); } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (Engine::get_singleton()->is_editor_hint()) { break; @@ -165,6 +166,7 @@ void TouchScreenButton::_notification(int p_what) { } } } break; + case NOTIFICATION_PAUSED: { if (is_pressed()) { _release(); diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp index a7c2ae5bb1..4bceaf71c6 100644 --- a/scene/2d/visible_on_screen_notifier_2d.cpp +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -75,15 +75,16 @@ Rect2 VisibleOnScreenNotifier2D::get_rect() const { void VisibleOnScreenNotifier2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - //get_world_2d()-> on_screen = false; RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit)); } break; + case NOTIFICATION_DRAW: { if (Engine::get_singleton()->is_editor_hint()) { draw_rect(rect, Color(1, 0.5, 1, 0.2)); } } break; + case NOTIFICATION_EXIT_TREE: { on_screen = false; RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), false, Rect2(), Callable(), Callable()); @@ -169,21 +170,23 @@ void VisibleOnScreenEnabler2D::_update_enable_mode(bool p_enable) { } } void VisibleOnScreenEnabler2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } - node_id = ObjectID(); - Node *node = get_node(enable_node_path); - if (node) { - node_id = node->get_instance_id(); - node->set_process_mode(PROCESS_MODE_DISABLED); - } - } + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - node_id = ObjectID(); + case NOTIFICATION_EXIT_TREE: { + node_id = ObjectID(); + } break; } } diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index 5123a6eb6c..78c968a3d4 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -344,10 +344,14 @@ void Area3D::_clear_monitoring() { } void Area3D::_notification(int p_what) { - if (p_what == NOTIFICATION_EXIT_TREE) { - _clear_monitoring(); - } else if (p_what == NOTIFICATION_ENTER_TREE) { - _initialize_wind(); + switch (p_what) { + case NOTIFICATION_EXIT_TREE: { + _clear_monitoring(); + } break; + + case NOTIFICATION_ENTER_TREE: { + _initialize_wind(); + } break; } } diff --git a/scene/3d/audio_listener_3d.cpp b/scene/3d/audio_listener_3d.cpp index 0eb7588958..1ead9bb384 100644 --- a/scene/3d/audio_listener_3d.cpp +++ b/scene/3d/audio_listener_3d.cpp @@ -85,9 +85,11 @@ void AudioListener3D::_notification(int p_what) { make_current(); } } break; + case NOTIFICATION_TRANSFORM_CHANGED: { _request_listener_update(); } break; + case NOTIFICATION_EXIT_WORLD: { if (!get_tree()->is_node_being_edited(this)) { if (is_current()) { @@ -100,7 +102,6 @@ void AudioListener3D::_notification(int p_what) { } get_viewport()->_audio_listener_3d_remove(this); - } break; } } diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 3b52974b8e..b17201f86b 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -239,80 +239,82 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const { } void AudioStreamPlayer3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - velocity_tracker->reset(get_global_transform().origin); - AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this); - if (autoplay && !Engine::get_singleton()->is_editor_hint()) { - play(); - } - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + velocity_tracker->reset(get_global_transform().origin); + AudioServer::get_singleton()->add_listener_changed_callback(_listener_changed_cb, this); + if (autoplay && !Engine::get_singleton()->is_editor_hint()) { + play(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - stop(); - AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); - } + case NOTIFICATION_EXIT_TREE: { + stop(); + AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); + } break; - if (p_what == NOTIFICATION_PAUSED) { - if (!can_process()) { - // Node can't process so we start fading out to silence - set_stream_paused(true); - } - } + case NOTIFICATION_PAUSED: { + if (!can_process()) { + // Node can't process so we start fading out to silence. + set_stream_paused(true); + } + } break; - if (p_what == NOTIFICATION_UNPAUSED) { - set_stream_paused(false); - } + case NOTIFICATION_UNPAUSED: { + set_stream_paused(false); + } break; - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { - velocity_tracker->update_position(get_global_transform().origin); - } - } + case NOTIFICATION_TRANSFORM_CHANGED: { + if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { + velocity_tracker->update_position(get_global_transform().origin); + } + } break; - if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - //update anything related to position first, if possible of course - Vector<AudioFrame> volume_vector; - if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { - volume_vector = _update_panning(); - } + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // Update anything related to position first, if possible of course. + Vector<AudioFrame> volume_vector; + if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) { + volume_vector = _update_panning(); + } - if (setplay.get() >= 0 && stream.is_valid()) { - active.set(); - Ref<AudioStreamPlayback> new_playback = stream->instance_playback(); - ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); - Map<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); - setplay.set(-1); - } + if (setplay.get() >= 0 && stream.is_valid()) { + active.set(); + Ref<AudioStreamPlayback> new_playback = stream->instance_playback(); + ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); + Map<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); + setplay.set(-1); + } - if (!stream_playbacks.is_empty() && active.is_set()) { - // Stop playing if no longer active. - Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; - for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { - if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { - playbacks_to_remove.push_back(playback); + if (!stream_playbacks.is_empty() && active.is_set()) { + // Stop playing if no longer active. + Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { + playbacks_to_remove.push_back(playback); + } + } + // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. + for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { + stream_playbacks.erase(playback); + } + if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { + // This node is no longer actively playing audio. + active.clear(); + set_physics_process_internal(false); + } + if (!playbacks_to_remove.is_empty()) { + emit_signal(SNAME("finished")); } } - // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. - for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { - stream_playbacks.erase(playback); - } - if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { - // This node is no longer actively playing audio. - active.clear(); - set_physics_process_internal(false); - } - if (!playbacks_to_remove.is_empty()) { - emit_signal(SNAME("finished")); - } - } - while (stream_playbacks.size() > max_polyphony) { - AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]); - stream_playbacks.remove_at(0); - } + while (stream_playbacks.size() > max_polyphony) { + AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]); + stream_playbacks.remove_at(0); + } + } break; } } diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index 73a4dcd1f7..8623c7d8b6 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -340,17 +340,20 @@ void BoneAttachment3D::_notification(int p_what) { } _check_bind(); } break; + case NOTIFICATION_EXIT_TREE: { _check_unbind(); } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { _transform_changed(); } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (_override_dirty) { _override_dirty = false; } - } + } break; } } diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 2c95010eb4..4eace17cc0 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -82,12 +82,6 @@ void Camera3D::_update_camera() { RenderingServer::get_singleton()->camera_set_transform(camera, get_camera_transform()); - // here goes listener stuff - /* - if (viewport_ptr && is_inside_scene() && is_current()) - get_viewport()->_camera_3d_transform_changed_notify(); - */ - if (get_tree()->is_node_being_edited(this) || !is_current()) { return; } @@ -108,14 +102,15 @@ void Camera3D::_notification(int p_what) { if (current || first_camera) { viewport->_camera_3d_set(this); } - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { _request_camera_update(); if (doppler_tracking != DOPPLER_TRACKING_DISABLED) { velocity_tracker->update_position(get_global_transform().origin); } } break; + case NOTIFICATION_EXIT_WORLD: { if (!get_tree()->is_node_being_edited(this)) { if (is_current()) { @@ -131,13 +126,14 @@ void Camera3D::_notification(int p_what) { viewport->_camera_3d_remove(this); viewport = nullptr; } - } break; + case NOTIFICATION_BECAME_CURRENT: { if (viewport) { viewport->find_world_3d()->_register_camera(this); } } break; + case NOTIFICATION_LOST_CURRENT: { if (viewport) { viewport->find_world_3d()->_remove_camera(this); diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index 7926175459..88ef44b71f 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -93,18 +93,19 @@ void CollisionPolygon3D::_notification(int p_what) { _update_in_shape_owner(); } } break; + case NOTIFICATION_ENTER_TREE: { if (parent) { _update_in_shape_owner(); } - } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { _update_in_shape_owner(true); } - } break; + case NOTIFICATION_UNPARENTED: { if (parent) { parent->remove_shape_owner(owner_id); diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 773095b377..e1a0e1427b 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -87,16 +87,19 @@ void CollisionShape3D::_notification(int p_what) { _update_in_shape_owner(); } } break; + case NOTIFICATION_ENTER_TREE: { if (parent) { _update_in_shape_owner(); } } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { _update_in_shape_owner(true); } } break; + case NOTIFICATION_UNPARENTED: { if (parent) { parent->remove_shape_owner(owner_id); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index e3d551d782..ab28a83806 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -39,10 +39,6 @@ AABB CPUParticles3D::get_aabb() const { return AABB(); } -Vector<Face3> CPUParticles3D::get_faces(uint32_t p_usage_particle_flags) const { - return Vector<Face3>(); -} - void CPUParticles3D::set_emitting(bool p_emitting) { if (emitting == p_emitting) { return; @@ -1251,65 +1247,67 @@ void CPUParticles3D::_update_render_thread() { } void CPUParticles3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - set_process_internal(emitting); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + set_process_internal(emitting); - // first update before rendering to avoid one frame delay after emitting starts - if (emitting && (time == 0)) { - _update_internal(); - } - } + // first update before rendering to avoid one frame delay after emitting starts + if (emitting && (time == 0)) { + _update_internal(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - _set_redraw(false); - } + case NOTIFICATION_EXIT_TREE: { + _set_redraw(false); + } break; - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - // first update before rendering to avoid one frame delay after emitting starts - if (emitting && (time == 0)) { + case NOTIFICATION_VISIBILITY_CHANGED: { + // first update before rendering to avoid one frame delay after emitting starts + if (emitting && (time == 0)) { + _update_internal(); + } + } break; + + case NOTIFICATION_INTERNAL_PROCESS: { _update_internal(); - } - } + } break; - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - _update_internal(); - } + case NOTIFICATION_TRANSFORM_CHANGED: { + inv_emission_transform = get_global_transform().affine_inverse(); - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - inv_emission_transform = get_global_transform().affine_inverse(); + if (!local_coords) { + int pc = particles.size(); + + float *w = particle_data.ptrw(); + const Particle *r = particles.ptr(); + float *ptr = w; + + for (int i = 0; i < pc; i++) { + Transform3D t = inv_emission_transform * r[i].transform; + + if (r[i].active) { + ptr[0] = t.basis.elements[0][0]; + ptr[1] = t.basis.elements[0][1]; + ptr[2] = t.basis.elements[0][2]; + ptr[3] = t.origin.x; + ptr[4] = t.basis.elements[1][0]; + ptr[5] = t.basis.elements[1][1]; + ptr[6] = t.basis.elements[1][2]; + ptr[7] = t.origin.y; + ptr[8] = t.basis.elements[2][0]; + ptr[9] = t.basis.elements[2][1]; + ptr[10] = t.basis.elements[2][2]; + ptr[11] = t.origin.z; + } else { + memset(ptr, 0, sizeof(float) * 12); + } - if (!local_coords) { - int pc = particles.size(); - - float *w = particle_data.ptrw(); - const Particle *r = particles.ptr(); - float *ptr = w; - - for (int i = 0; i < pc; i++) { - Transform3D t = inv_emission_transform * r[i].transform; - - if (r[i].active) { - ptr[0] = t.basis.elements[0][0]; - ptr[1] = t.basis.elements[0][1]; - ptr[2] = t.basis.elements[0][2]; - ptr[3] = t.origin.x; - ptr[4] = t.basis.elements[1][0]; - ptr[5] = t.basis.elements[1][1]; - ptr[6] = t.basis.elements[1][2]; - ptr[7] = t.origin.y; - ptr[8] = t.basis.elements[2][0]; - ptr[9] = t.basis.elements[2][1]; - ptr[10] = t.basis.elements[2][2]; - ptr[11] = t.origin.z; - } else { - memset(ptr, 0, sizeof(float) * 12); + ptr += 20; } - ptr += 20; + can_update.set(); } - - can_update.set(); - } + } break; } } diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index bd736bdf24..5eeb5e75d3 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -201,7 +201,6 @@ protected: public: AABB get_aabb() const override; - Vector<Face3> get_faces(uint32_t p_usage_flags) const override; void set_emitting(bool p_emitting); void set_amount(int p_amount); diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index dfac9055f5..8d0edfd1f3 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -152,10 +152,6 @@ AABB Decal::get_aabb() const { return aabb; } -Vector<Face3> Decal::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void Decal::_validate_property(PropertyInfo &property) const { if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) { property.usage = PROPERTY_USAGE_NO_EDITOR; diff --git a/scene/3d/decal.h b/scene/3d/decal.h index 740dd2c407..d5990272c6 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -104,7 +104,6 @@ public: uint32_t get_cull_mask() const; virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; Decal(); ~Decal(); diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h index 68d5c58169..556a92ad3f 100644 --- a/scene/3d/fog_volume.h +++ b/scene/3d/fog_volume.h @@ -62,7 +62,6 @@ public: Ref<Material> get_material() const; virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); } TypedArray<String> get_configuration_warnings() const override; FogVolume(); diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index aaaa728838..9fe2210de6 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -36,10 +36,6 @@ AABB GPUParticles3D::get_aabb() const { return AABB(); } -Vector<Face3> GPUParticles3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void GPUParticles3D::set_emitting(bool p_emitting) { RS::get_singleton()->particles_set_emitting(particles, p_emitting); @@ -423,38 +419,41 @@ NodePath GPUParticles3D::get_sub_emitter() const { } void GPUParticles3D::_notification(int p_what) { - if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { - if (can_process()) { - RS::get_singleton()->particles_set_speed_scale(particles, speed_scale); - } else { - RS::get_singleton()->particles_set_speed_scale(particles, 0); - } - } - - // Use internal process when emitting and one_shot is on so that when - // the shot ends the editor can properly update - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (one_shot && !is_emitting()) { - notify_property_list_changed(); - set_process_internal(false); - } - } + switch (p_what) { + case NOTIFICATION_PAUSED: + case NOTIFICATION_UNPAUSED: { + if (can_process()) { + RS::get_singleton()->particles_set_speed_scale(particles, speed_scale); + } else { + RS::get_singleton()->particles_set_speed_scale(particles, 0); + } + } break; + + // Use internal process when emitting and one_shot is on so that when + // the shot ends the editor can properly update. + case NOTIFICATION_INTERNAL_PROCESS: { + if (one_shot && !is_emitting()) { + notify_property_list_changed(); + set_process_internal(false); + } + } break; - if (p_what == NOTIFICATION_ENTER_TREE) { - if (sub_emitter != NodePath()) { - _attach_sub_emitter(); - } - } + case NOTIFICATION_ENTER_TREE: { + if (sub_emitter != NodePath()) { + _attach_sub_emitter(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - RS::get_singleton()->particles_set_subemitter(particles, RID()); - } + case NOTIFICATION_EXIT_TREE: { + RS::get_singleton()->particles_set_subemitter(particles, RID()); + } break; - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - // make sure particles are updated before rendering occurs if they were active before - if (is_visible_in_tree() && !RS::get_singleton()->particles_is_inactive(particles)) { - RS::get_singleton()->particles_request_process(particles); - } + case NOTIFICATION_VISIBILITY_CHANGED: { + // Make sure particles are updated before rendering occurs if they were active before. + if (is_visible_in_tree() && !RS::get_singleton()->particles_is_inactive(particles)) { + RS::get_singleton()->particles_request_process(particles); + } + } break; } } diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index 54ae84628a..f3eb52d124 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -98,7 +98,6 @@ protected: public: AABB get_aabb() const override; - Vector<Face3> get_faces(uint32_t p_usage_flags) const override; void set_emitting(bool p_emitting); void set_amount(int p_amount); diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 54fbc720ce..6f94df284a 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -584,47 +584,49 @@ GPUParticlesCollisionSDF3D::~GPUParticlesCollisionSDF3D() { //////////////////////////// void GPUParticlesCollisionHeightField3D::_notification(int p_what) { - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (update_mode == UPDATE_MODE_ALWAYS) { - RS::get_singleton()->particles_collision_height_field_update(_get_collision()); - } + switch (p_what) { + case NOTIFICATION_INTERNAL_PROCESS: { + if (update_mode == UPDATE_MODE_ALWAYS) { + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + } - if (follow_camera_mode && get_viewport()) { - Camera3D *cam = get_viewport()->get_camera_3d(); - if (cam) { - Transform3D xform = get_global_transform(); - Vector3 x_axis = xform.basis.get_axis(Vector3::AXIS_X).normalized(); - Vector3 z_axis = xform.basis.get_axis(Vector3::AXIS_Z).normalized(); - float x_len = xform.basis.get_scale().x; - float z_len = xform.basis.get_scale().z; + if (follow_camera_mode && get_viewport()) { + Camera3D *cam = get_viewport()->get_camera_3d(); + if (cam) { + Transform3D xform = get_global_transform(); + Vector3 x_axis = xform.basis.get_axis(Vector3::AXIS_X).normalized(); + Vector3 z_axis = xform.basis.get_axis(Vector3::AXIS_Z).normalized(); + float x_len = xform.basis.get_scale().x; + float z_len = xform.basis.get_scale().z; - Vector3 cam_pos = cam->get_global_transform().origin; - Transform3D new_xform = xform; + Vector3 cam_pos = cam->get_global_transform().origin; + Transform3D new_xform = xform; - while (x_axis.dot(cam_pos - new_xform.origin) > x_len) { - new_xform.origin += x_axis * x_len; - } - while (x_axis.dot(cam_pos - new_xform.origin) < -x_len) { - new_xform.origin -= x_axis * x_len; - } + while (x_axis.dot(cam_pos - new_xform.origin) > x_len) { + new_xform.origin += x_axis * x_len; + } + while (x_axis.dot(cam_pos - new_xform.origin) < -x_len) { + new_xform.origin -= x_axis * x_len; + } - while (z_axis.dot(cam_pos - new_xform.origin) > z_len) { - new_xform.origin += z_axis * z_len; - } - while (z_axis.dot(cam_pos - new_xform.origin) < -z_len) { - new_xform.origin -= z_axis * z_len; - } + while (z_axis.dot(cam_pos - new_xform.origin) > z_len) { + new_xform.origin += z_axis * z_len; + } + while (z_axis.dot(cam_pos - new_xform.origin) < -z_len) { + new_xform.origin -= z_axis * z_len; + } - if (new_xform != xform) { - set_global_transform(new_xform); - RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + if (new_xform != xform) { + set_global_transform(new_xform); + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + } } } - } - } + } break; - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + case NOTIFICATION_TRANSFORM_CHANGED: { + RS::get_singleton()->particles_collision_height_field_update(_get_collision()); + } break; } } diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h index b6de1d83fc..fdd2fa4b18 100644 --- a/scene/3d/gpu_particles_collision_3d.h +++ b/scene/3d/gpu_particles_collision_3d.h @@ -50,8 +50,6 @@ public: void set_cull_mask(uint32_t p_cull_mask); uint32_t get_cull_mask() const; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); } - ~GPUParticlesCollision3D(); }; @@ -274,8 +272,6 @@ public: void set_directionality(real_t p_directionality); real_t get_directionality() const; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override { return Vector<Face3>(); } - ~GPUParticlesAttractor3D(); }; diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp index bd47ab3462..ce7c0d8292 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/joint_3d.cpp @@ -124,7 +124,7 @@ void Joint3D::set_node_a(const NodePath &p_node_a) { return; } - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); } @@ -141,7 +141,7 @@ void Joint3D::set_node_b(const NodePath &p_node_b) { return; } - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); } @@ -166,14 +166,18 @@ int Joint3D::get_solver_priority() const { void Joint3D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_READY: { + case NOTIFICATION_POST_ENTER_TREE: { + if (is_configured()) { + _disconnect_signals(); + } _update_joint(); } break; + case NOTIFICATION_EXIT_TREE: { - if (joint.is_valid()) { + if (is_configured()) { _disconnect_signals(); - _update_joint(true); } + _update_joint(true); } break; } } @@ -182,6 +186,10 @@ void Joint3D::set_exclude_nodes_from_collision(bool p_enable) { if (exclude_from_collision == p_enable) { return; } + if (is_configured()) { + _disconnect_signals(); + } + _update_joint(true); exclude_from_collision = p_enable; _update_joint(); } diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index d88bb815bc..e7e164d7da 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -74,6 +74,43 @@ bool Light3D::is_negative() const { return negative; } +void Light3D::set_enable_distance_fade(bool p_enable) { + distance_fade_enabled = p_enable; + RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length); + notify_property_list_changed(); +} + +bool Light3D::is_distance_fade_enabled() const { + return distance_fade_enabled; +} + +void Light3D::set_distance_fade_begin(real_t p_distance) { + distance_fade_begin = p_distance; + RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length); +} + +real_t Light3D::get_distance_fade_begin() const { + return distance_fade_begin; +} + +void Light3D::set_distance_fade_shadow(real_t p_distance) { + distance_fade_shadow = p_distance; + RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length); +} + +real_t Light3D::get_distance_fade_shadow() const { + return distance_fade_shadow; +} + +void Light3D::set_distance_fade_length(real_t p_length) { + distance_fade_length = p_length; + RS::get_singleton()->light_set_distance_fade(light, distance_fade_enabled, distance_fade_begin, distance_fade_shadow, distance_fade_length); +} + +real_t Light3D::get_distance_fade_length() const { + return distance_fade_length; +} + void Light3D::set_cull_mask(uint32_t p_cull_mask) { cull_mask = p_cull_mask; RS::get_singleton()->light_set_cull_mask(light, p_cull_mask); @@ -94,15 +131,6 @@ Color Light3D::get_color() const { return color; } -void Light3D::set_shadow_color(const Color &p_shadow_color) { - shadow_color = p_shadow_color; - RS::get_singleton()->light_set_shadow_color(light, p_shadow_color); -} - -Color Light3D::get_shadow_color() const { - return shadow_color; -} - void Light3D::set_shadow_reverse_cull_face(bool p_enable) { reverse_cull = p_enable; RS::get_singleton()->light_set_reverse_cull_face_mode(light, reverse_cull); @@ -128,10 +156,6 @@ AABB Light3D::get_aabb() const { return AABB(); } -Vector<Face3> Light3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void Light3D::set_bake_mode(BakeMode p_mode) { bake_mode = p_mode; RS::get_singleton()->light_set_bake_mode(light, RS::LightBakeMode(p_mode)); @@ -177,12 +201,11 @@ void Light3D::_update_visibility() { } void Light3D::_notification(int p_what) { - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - _update_visibility(); - } - - if (p_what == NOTIFICATION_ENTER_TREE) { - _update_visibility(); + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: + case NOTIFICATION_ENTER_TREE: { + _update_visibility(); + } break; } } @@ -196,7 +219,7 @@ bool Light3D::is_editor_only() const { } void Light3D::_validate_property(PropertyInfo &property) const { - if (!shadow && (property.name == "shadow_color" || property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur")) { + if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) { property.usage = PROPERTY_USAGE_NO_EDITOR; } @@ -204,6 +227,11 @@ void Light3D::_validate_property(PropertyInfo &property) const { // Angular distance is only used in DirectionalLight3D. property.usage = PROPERTY_USAGE_NONE; } + + if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length")) { + property.usage = PROPERTY_USAGE_NO_EDITOR; + } + VisualInstance3D::_validate_property(property); } @@ -223,15 +251,24 @@ void Light3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cull_mask", "cull_mask"), &Light3D::set_cull_mask); ClassDB::bind_method(D_METHOD("get_cull_mask"), &Light3D::get_cull_mask); + ClassDB::bind_method(D_METHOD("set_enable_distance_fade", "enable"), &Light3D::set_enable_distance_fade); + ClassDB::bind_method(D_METHOD("is_distance_fade_enabled"), &Light3D::is_distance_fade_enabled); + + ClassDB::bind_method(D_METHOD("set_distance_fade_begin", "distance"), &Light3D::set_distance_fade_begin); + ClassDB::bind_method(D_METHOD("get_distance_fade_begin"), &Light3D::get_distance_fade_begin); + + ClassDB::bind_method(D_METHOD("set_distance_fade_shadow", "distance"), &Light3D::set_distance_fade_shadow); + ClassDB::bind_method(D_METHOD("get_distance_fade_shadow"), &Light3D::get_distance_fade_shadow); + + ClassDB::bind_method(D_METHOD("set_distance_fade_length", "distance"), &Light3D::set_distance_fade_length); + ClassDB::bind_method(D_METHOD("get_distance_fade_length"), &Light3D::get_distance_fade_length); + ClassDB::bind_method(D_METHOD("set_color", "color"), &Light3D::set_color); ClassDB::bind_method(D_METHOD("get_color"), &Light3D::get_color); ClassDB::bind_method(D_METHOD("set_shadow_reverse_cull_face", "enable"), &Light3D::set_shadow_reverse_cull_face); ClassDB::bind_method(D_METHOD("get_shadow_reverse_cull_face"), &Light3D::get_shadow_reverse_cull_face); - ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light3D::set_shadow_color); - ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light3D::get_shadow_color); - ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light3D::set_bake_mode); ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light3D::get_bake_mode); @@ -251,13 +288,17 @@ void Light3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow"); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_shadow_color", "get_shadow_color"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_normal_bias", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0.1,8,0.01"), "set_param", "get_param", PARAM_SHADOW_BLUR); + ADD_GROUP("Distance Fade", "distance_fade_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_begin", "get_distance_fade_begin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_shadow", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_shadow", "get_distance_fade_shadow"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater"), "set_distance_fade_length", "get_distance_fade_length"); ADD_GROUP("Editor", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only"); ADD_GROUP("", ""); @@ -392,6 +433,12 @@ void DirectionalLight3D::_validate_property(PropertyInfo &property) const { property.usage = PROPERTY_USAGE_NONE; } + if (property.name == "distance_fade_enabled" || property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length") { + // Not relevant for DirectionalLight3D, as the light LOD system only pertains to point lights. + // For DirectionalLight3D, `directional_shadow_max_distance` can be used instead. + property.usage = PROPERTY_USAGE_NONE; + } + Light3D::_validate_property(property); } diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index d5d2aee43d..ed9e0bdfff 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -70,11 +70,14 @@ public: private: Color color; real_t param[PARAM_MAX] = {}; - Color shadow_color; bool shadow = false; bool negative = false; bool reverse_cull = false; uint32_t cull_mask = 0; + bool distance_fade_enabled = false; + real_t distance_fade_begin = 40.0; + real_t distance_fade_shadow = 50.0; + real_t distance_fade_length = 10.0; RS::LightType type = RenderingServer::LIGHT_DIRECTIONAL; bool editor_only = false; void _update_visibility(); @@ -107,15 +110,24 @@ public: void set_negative(bool p_enable); bool is_negative() const; + void set_enable_distance_fade(bool p_enable); + bool is_distance_fade_enabled() const; + + void set_distance_fade_begin(real_t p_distance); + real_t get_distance_fade_begin() const; + + void set_distance_fade_shadow(real_t p_distance); + real_t get_distance_fade_shadow() const; + + void set_distance_fade_length(real_t p_length); + real_t get_distance_fade_length() const; + void set_cull_mask(uint32_t p_cull_mask); uint32_t get_cull_mask() const; void set_color(const Color &p_color); Color get_color() const; - void set_shadow_color(const Color &p_shadow_color); - Color get_shadow_color() const; - void set_shadow_reverse_cull_face(bool p_enable); bool get_shadow_reverse_cull_face() const; @@ -126,7 +138,6 @@ public: Ref<Texture2D> get_projector() const; virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; Light3D(); ~Light3D(); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 825742da35..c74654b4bd 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -982,7 +982,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } config->set_value("remap", "importer", "2d_array_texture"); - config->set_value("remap", "type", "StreamTexture2DArray"); + config->set_value("remap", "type", "CompressedTexture2DArray"); if (!config->has_section_key("params", "compress/mode")) { config->set_value("params", "compress/mode", 2); //user may want another compression, so leave it be } @@ -1176,16 +1176,18 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } void LightmapGI::_notification(int p_what) { - if (p_what == NOTIFICATION_POST_ENTER_TREE) { - if (light_data.is_valid()) { - _assign_lightmaps(); - } - } + switch (p_what) { + case NOTIFICATION_POST_ENTER_TREE: { + if (light_data.is_valid()) { + _assign_lightmaps(); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - if (light_data.is_valid()) { - _clear_lightmaps(); - } + case NOTIFICATION_EXIT_TREE: { + if (light_data.is_valid()) { + _clear_lightmaps(); + } + } break; } } @@ -1261,10 +1263,6 @@ AABB LightmapGI::get_aabb() const { return AABB(); } -Vector<Face3> LightmapGI::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void LightmapGI::set_use_denoiser(bool p_enable) { use_denoiser = p_enable; } diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index 66acf4f487..d29d7a7c28 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -267,7 +267,6 @@ public: GenerateProbes get_generate_probes() const; AABB get_aabb() const override; - Vector<Face3> get_faces(uint32_t p_usage_flags) const override; BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr); LightmapGI(); diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index 58ff512130..31c33a6b61 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -219,18 +219,6 @@ AABB MeshInstance3D::get_aabb() const { return AABB(); } -Vector<Face3> MeshInstance3D::get_faces(uint32_t p_usage_flags) const { - if (!(p_usage_flags & (FACES_SOLID | FACES_ENCLOSING))) { - return Vector<Face3>(); - } - - if (mesh.is_null()) { - return Vector<Face3>(); - } - - return mesh->get_faces(); -} - Node *MeshInstance3D::create_trimesh_collision_node() { if (mesh.is_null()) { return nullptr; @@ -328,8 +316,10 @@ void MeshInstance3D::create_multiple_convex_collisions() { } void MeshInstance3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - _resolve_skeleton_path(); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + _resolve_skeleton_path(); + } break; } } diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h index 03ee3cd608..0bf5c32410 100644 --- a/scene/3d/mesh_instance_3d.h +++ b/scene/3d/mesh_instance_3d.h @@ -93,7 +93,6 @@ public: void create_debug_tangents(); virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; MeshInstance3D(); ~MeshInstance3D(); diff --git a/scene/3d/multimesh_instance_3d.cpp b/scene/3d/multimesh_instance_3d.cpp index 34b1e86435..d197388fad 100644 --- a/scene/3d/multimesh_instance_3d.cpp +++ b/scene/3d/multimesh_instance_3d.cpp @@ -49,10 +49,6 @@ Ref<MultiMesh> MultiMeshInstance3D::get_multimesh() const { return multimesh; } -Vector<Face3> MultiMeshInstance3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - AABB MultiMeshInstance3D::get_aabb() const { if (multimesh.is_null()) { return AABB(); diff --git a/scene/3d/multimesh_instance_3d.h b/scene/3d/multimesh_instance_3d.h index d03b24eb4e..111f1e9c09 100644 --- a/scene/3d/multimesh_instance_3d.h +++ b/scene/3d/multimesh_instance_3d.h @@ -44,8 +44,6 @@ protected: // bind helpers public: - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; - void set_multimesh(const Ref<MultiMesh> &p_multimesh); Ref<MultiMesh> get_multimesh() const; diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index e90971845e..c4f062f0f9 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -103,10 +103,12 @@ void NavigationAgent3D::_notification(int p_what) { } set_physics_process_internal(true); } break; + case NOTIFICATION_EXIT_TREE: { agent_parent = nullptr; set_physics_process_internal(false); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin); diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index ba6c50d98c..308545b2cc 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -63,17 +63,21 @@ void NavigationObstacle3D::_notification(int p_what) { } set_physics_process_internal(true); } break; + case NOTIFICATION_EXIT_TREE: { parent_node3d = nullptr; set_physics_process_internal(false); } break; + case NOTIFICATION_PARENTED: { parent_node3d = Object::cast_to<Node3D>(get_parent()); reevaluate_agent_radius(); } break; + case NOTIFICATION_UNPARENTED: { parent_node3d = nullptr; } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (parent_node3d) { NavigationServer3D::get_singleton()->agent_set_position(agent, parent_node3d->get_global_transform().origin); diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 1e298e0137..8f0fd8706d 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -93,12 +93,12 @@ void NavigationRegion3D::_notification(int p_what) { add_child(dm); debug_view = dm; } - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform()); - } break; + case NOTIFICATION_EXIT_TREE: { NavigationServer3D::get_singleton()->region_set_map(region, RID()); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index cad1201d63..62cc7c143b 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -147,8 +147,8 @@ void Node3D::_notification(int p_what) { notification(NOTIFICATION_ENTER_WORLD); _update_visibility_parent(true); - } break; + case NOTIFICATION_EXIT_TREE: { notification(NOTIFICATION_EXIT_WORLD, true); if (xform_change.in_list()) { @@ -162,6 +162,7 @@ void Node3D::_notification(int p_what) { data.top_level_active = false; _update_visibility_parent(true); } break; + case NOTIFICATION_ENTER_WORLD: { data.inside_world = true; data.viewport = nullptr; @@ -192,6 +193,7 @@ void Node3D::_notification(int p_what) { } #endif } break; + case NOTIFICATION_EXIT_WORLD: { #ifdef TOOLS_ENABLED clear_gizmos(); @@ -203,7 +205,6 @@ void Node3D::_notification(int p_what) { data.viewport = nullptr; data.inside_world = false; - } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -213,9 +214,6 @@ void Node3D::_notification(int p_what) { } #endif } break; - - default: { - } } } diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp index 231817526c..b82f05544b 100644 --- a/scene/3d/occluder_instance_3d.cpp +++ b/scene/3d/occluder_instance_3d.cpp @@ -122,8 +122,10 @@ AABB Occluder3D::get_aabb() const { } void Occluder3D::_notification(int p_what) { - if (p_what == NOTIFICATION_POSTINITIALIZE) { - _update(); + switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + _update(); + } break; } } @@ -190,7 +192,6 @@ void QuadOccluder3D::set_size(const Vector2 &p_size) { } size = p_size.max(Vector2()); - ; _update(); } @@ -235,7 +236,6 @@ void BoxOccluder3D::set_size(const Vector3 &p_size) { } size = Vector3(MAX(p_size.x, 0.0f), MAX(p_size.y, 0.0f), MAX(p_size.z, 0.0f)); - ; _update(); } @@ -433,10 +433,6 @@ AABB OccluderInstance3D::get_aabb() const { return AABB(); } -Vector<Face3> OccluderInstance3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) { if (occluder == p_occluder) { return; diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h index 669ddba775..ed6610074e 100644 --- a/scene/3d/occluder_instance_3d.h +++ b/scene/3d/occluder_instance_3d.h @@ -194,7 +194,6 @@ public: Ref<Occluder3D> get_occluder() const; virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; void set_bake_mask(uint32_t p_mask); uint32_t get_bake_mask() const; diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 6e1c9ef781..5fd28a6ff3 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -30,9 +30,6 @@ #include "path_3d.h" -void Path3D::_notification(int p_what) { -} - void Path3D::_curve_changed() { if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) { update_gizmos(); @@ -223,8 +220,8 @@ void PathFollow3D::_notification(int p_what) { _update_transform(false); } } - } break; + case NOTIFICATION_EXIT_TREE: { path = nullptr; } break; diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index 32ca5a1beb..e9ab557693 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -42,7 +42,6 @@ class Path3D : public Node3D { void _curve_changed(); protected: - void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 13a38f3b9f..47baa9e023 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -601,7 +601,7 @@ void RigidDynamicBody3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); //used for warnings and only in editor + set_notify_local_transform(true); // Used for warnings and only in editor. } } break; @@ -1169,7 +1169,7 @@ bool CharacterBody3D::move_and_slide() { for (int i = 0; i < 3; i++) { if (locked_axis & (1 << i)) { - motion_velocity[i] = 0.0; + velocity[i] = 0.0; } } @@ -1239,7 +1239,7 @@ bool CharacterBody3D::move_and_slide() { if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) { current_platform_velocity = current_platform_velocity.slide(up_direction); } - motion_velocity += current_platform_velocity; + velocity += current_platform_velocity; } } @@ -1247,7 +1247,7 @@ bool CharacterBody3D::move_and_slide() { } void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_floor) { - Vector3 motion = motion_velocity * p_delta; + Vector3 motion = velocity * p_delta; Vector3 motion_slide_up = motion.slide(up_direction); Vector3 prev_floor_normal = floor_normal; @@ -1267,7 +1267,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // If the platform's ceiling push down the body. bool apply_ceiling_velocity = false; bool first_slide = true; - bool vel_dir_facing_up = motion_velocity.dot(up_direction) > 0; + bool vel_dir_facing_up = velocity.dot(up_direction) > 0; Vector3 total_travel; for (int iteration = 0; iteration < max_slides; ++iteration) { @@ -1287,26 +1287,26 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo CollisionState result_state; _set_collision_direction(result, result_state); - // If we hit a ceiling platform, we set the vertical motion_velocity to at least the platform one. + // If we hit a ceiling platform, we set the vertical velocity to at least the platform one. if (collision_state.ceiling && platform_ceiling_velocity != Vector3() && platform_ceiling_velocity.dot(up_direction) < 0) { // If ceiling sliding is on, only apply when the ceiling is flat or when the motion is upward. if (!slide_on_ceiling || motion.dot(up_direction) < 0 || (ceiling_normal + up_direction).length() < 0.01) { apply_ceiling_velocity = true; Vector3 ceiling_vertical_velocity = up_direction * up_direction.dot(platform_ceiling_velocity); - Vector3 motion_vertical_velocity = up_direction * up_direction.dot(motion_velocity); + Vector3 motion_vertical_velocity = up_direction * up_direction.dot(velocity); if (motion_vertical_velocity.dot(up_direction) > 0 || ceiling_vertical_velocity.length_squared() > motion_vertical_velocity.length_squared()) { - motion_velocity = ceiling_vertical_velocity + motion_velocity.slide(up_direction); + velocity = ceiling_vertical_velocity + velocity.slide(up_direction); } } } - if (collision_state.floor && floor_stop_on_slope && (motion_velocity.normalized() + up_direction).length() < 0.01) { + if (collision_state.floor && floor_stop_on_slope && (velocity.normalized() + up_direction).length() < 0.01) { Transform3D gt = get_global_transform(); if (result.travel.length() <= margin + CMP_EPSILON) { gt.origin -= result.travel; } set_global_transform(gt); - motion_velocity = Vector3(); + velocity = Vector3(); motion = Vector3(); last_motion = Vector3(); break; @@ -1367,11 +1367,11 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Scales the horizontal velocity according to the wall slope. if (vel_dir_facing_up) { - Vector3 slide_motion = motion_velocity.slide(result.collisions[0].normal); - // Keeps the vertical motion from motion_velocity and add the horizontal motion of the projection. - motion_velocity = up_direction * up_direction.dot(motion_velocity) + slide_motion.slide(up_direction); + Vector3 slide_motion = velocity.slide(result.collisions[0].normal); + // Keeps the vertical motion from velocity and add the horizontal motion of the projection. + velocity = up_direction * up_direction.dot(velocity) + slide_motion.slide(up_direction); } else { - motion_velocity = motion_velocity.slide(forward); + velocity = velocity.slide(forward); } // Allow only lateral motion along previous floor when already on floor. @@ -1401,7 +1401,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (stop_all_motion) { motion = Vector3(); - motion_velocity = Vector3(); + velocity = Vector3(); } } } @@ -1412,7 +1412,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo real_t motion_angle = Math::abs(Math::acos(-horizontal_normal.dot(motion_slide_up.normalized()))); if (motion_angle < wall_min_slide_angle) { motion = up_direction * motion.dot(up_direction); - motion_velocity = up_direction * motion_velocity.dot(up_direction); + velocity = up_direction * velocity.dot(up_direction); apply_default_sliding = false; } @@ -1425,7 +1425,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo const PhysicsServer3D::MotionCollision &collision = result.collisions[0]; Vector3 slide_motion = result.remainder.slide(collision.normal); - if (collision_state.floor && !collision_state.wall) { + if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_equal_approx(Vector3())) { // Slide using the intersection between the motion plane and the floor plane, // in order to keep the direction intact. real_t motion_length = slide_motion.length(); @@ -1437,7 +1437,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo slide_motion *= motion_length; } - if (slide_motion.dot(motion_velocity) > 0.0) { + if (slide_motion.dot(velocity) > 0.0) { motion = slide_motion; } else { motion = Vector3(); @@ -1446,10 +1446,10 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo if (slide_on_ceiling && result_state.ceiling) { // Apply slide only in the direction of the input motion, otherwise just stop to avoid jittering when moving against a wall. if (vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(collision.normal); + velocity = velocity.slide(collision.normal); } else { // Avoid acceleration in slope when falling. - motion_velocity = up_direction * up_direction.dot(motion_velocity); + velocity = up_direction * up_direction.dot(velocity); } } } @@ -1457,7 +1457,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo else { motion = result.remainder; if (result_state.ceiling && !slide_on_ceiling && vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); motion = motion.slide(up_direction); } } @@ -1502,12 +1502,12 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo // Reset the gravity accumulation when touching the ground. if (collision_state.floor && !vel_dir_facing_up) { - motion_velocity = motion_velocity.slide(up_direction); + velocity = velocity.slide(up_direction); } } void CharacterBody3D::_move_and_slide_floating(double p_delta) { - Vector3 motion = motion_velocity * p_delta; + Vector3 motion = velocity * p_delta; platform_rid = RID(); platform_object_id = ObjectID(); @@ -1534,7 +1534,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { break; } - if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-motion_velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { + if (wall_min_slide_angle != 0 && Math::acos(wall_normal.dot(-velocity.normalized())) < wall_min_slide_angle + FLOOR_ANGLE_THRESHOLD) { motion = Vector3(); if (result.travel.length() < margin + CMP_EPSILON) { Transform3D gt = get_global_transform(); @@ -1548,7 +1548,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { motion = result.remainder.slide(wall_normal); } - if (motion.dot(motion_velocity) <= 0.0) { + if (motion.dot(velocity) <= 0.0) { motion = Vector3(); } } @@ -1723,12 +1723,12 @@ real_t CharacterBody3D::get_safe_margin() const { return margin; } -const Vector3 &CharacterBody3D::get_motion_velocity() const { - return motion_velocity; +const Vector3 &CharacterBody3D::get_velocity() const { + return velocity; } -void CharacterBody3D::set_motion_velocity(const Vector3 &p_velocity) { - motion_velocity = p_velocity; +void CharacterBody3D::set_velocity(const Vector3 &p_velocity) { + velocity = p_velocity; } bool CharacterBody3D::is_on_floor() const { @@ -1943,8 +1943,8 @@ void CharacterBody3D::_notification(int p_what) { void CharacterBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide); - ClassDB::bind_method(D_METHOD("set_motion_velocity", "motion_velocity"), &CharacterBody3D::set_motion_velocity); - ClassDB::bind_method(D_METHOD("get_motion_velocity"), &CharacterBody3D::get_motion_velocity); + ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody3D::set_velocity); + ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody3D::get_velocity); ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin); ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin); @@ -1997,7 +1997,7 @@ void CharacterBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_mode", PROPERTY_HINT_ENUM, "Grounded,Floating", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_motion_mode", "get_motion_mode"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_motion_velocity", "get_motion_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle"); ADD_GROUP("Floor", "floor_"); @@ -2159,6 +2159,37 @@ void PhysicalBone3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_po PhysicsServer3D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position); } +void PhysicalBone3D::set_linear_velocity(const Vector3 &p_velocity) { + linear_velocity = p_velocity; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity); +} + +Vector3 PhysicalBone3D::get_linear_velocity() const { + return linear_velocity; +} + +void PhysicalBone3D::set_angular_velocity(const Vector3 &p_velocity) { + angular_velocity = p_velocity; + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity); +} + +Vector3 PhysicalBone3D::get_angular_velocity() const { + return angular_velocity; +} + +void PhysicalBone3D::set_use_custom_integrator(bool p_enable) { + if (custom_integrator == p_enable) { + return; + } + + custom_integrator = p_enable; + PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable); +} + +bool PhysicalBone3D::is_using_custom_integrator() { + return custom_integrator; +} + void PhysicalBone3D::reset_physics_simulation_state() { if (simulate_physics) { _start_physics_simulation(); @@ -2867,6 +2898,11 @@ void PhysicalBone3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) { return; } + linear_velocity = p_state->get_linear_velocity(); + angular_velocity = p_state->get_angular_velocity(); + + GDVIRTUAL_CALL(_integrate_forces, p_state); + /// Update bone transform. Transform3D global_transform(p_state->get_transform()); @@ -2929,9 +2965,20 @@ void PhysicalBone3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &PhysicalBone3D::set_angular_damp); ClassDB::bind_method(D_METHOD("get_angular_damp"), &PhysicalBone3D::get_angular_damp); + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &PhysicalBone3D::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &PhysicalBone3D::get_linear_velocity); + + ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &PhysicalBone3D::set_angular_velocity); + ClassDB::bind_method(D_METHOD("get_angular_velocity"), &PhysicalBone3D::get_angular_velocity); + + ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &PhysicalBone3D::set_use_custom_integrator); + ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &PhysicalBone3D::is_using_custom_integrator); + ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep); + GDVIRTUAL_BIND(_integrate_forces, "state"); + ADD_GROUP("Joint", "joint_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset"), "set_joint_offset", "get_joint_offset"); @@ -2943,10 +2990,13 @@ void PhysicalBone3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); BIND_ENUM_CONSTANT(DAMP_MODE_COMBINE); diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 67dc7382c3..6ace681021 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -354,8 +354,8 @@ public: }; bool move_and_slide(); - const Vector3 &get_motion_velocity() const; - void set_motion_velocity(const Vector3 &p_velocity); + const Vector3 &get_velocity() const; + void set_velocity(const Vector3 &p_velocity); bool is_on_floor() const; bool is_on_floor_only() const; @@ -416,7 +416,7 @@ private: real_t floor_max_angle = Math::deg2rad((real_t)45.0); real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0); Vector3 up_direction = Vector3(0.0, 1.0, 0.0); - Vector3 motion_velocity; + Vector3 velocity; Vector3 floor_normal; Vector3 wall_normal; Vector3 ceiling_normal; @@ -662,9 +662,13 @@ private: real_t bounce = 0.0; real_t mass = 1.0; real_t friction = 1.0; + Vector3 linear_velocity; + Vector3 angular_velocity; real_t gravity_scale = 1.0; bool can_sleep = true; + bool custom_integrator = false; + DampMode linear_damp_mode = DAMP_MODE_COMBINE; DampMode angular_damp_mode = DAMP_MODE_COMBINE; @@ -676,6 +680,7 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; void _notification(int p_what); + GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *) static void _body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state); void _body_state_changed(PhysicsDirectBodyState3D *p_state); @@ -691,6 +696,15 @@ private: public: void _on_bone_parent_changed(); + void set_linear_velocity(const Vector3 &p_velocity); + Vector3 get_linear_velocity() const override; + + void set_angular_velocity(const Vector3 &p_velocity); + Vector3 get_angular_velocity() const override; + + void set_use_custom_integrator(bool p_enable); + bool is_using_custom_integrator(); + #ifdef TOOLS_ENABLED void _set_gizmo_move_joint(bool p_move_joint); virtual Transform3D get_global_gizmo_transform() const override; diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp index b251aa38ba..f5e08b92ca 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/ray_cast_3d.cpp @@ -171,8 +171,8 @@ void RayCast3D::_notification(int p_what) { exclude.erase(Object::cast_to<CollisionObject3D>(get_parent())->get_rid()); } } - } break; + case NOTIFICATION_EXIT_TREE: { if (enabled) { set_physics_process_internal(false); @@ -181,8 +181,8 @@ void RayCast3D::_notification(int p_what) { if (debug_shape) { _clear_debug_shape(); } - } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!enabled) { break; @@ -193,7 +193,6 @@ void RayCast3D::_notification(int p_what) { if (prev_collision_state != collided && get_tree()->is_debugging_collisions_hint()) { _update_debug_shape_material(true); } - } break; } } diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index be655e71db..1bebd8e335 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -178,10 +178,6 @@ AABB ReflectionProbe::get_aabb() const { return aabb; } -Vector<Face3> ReflectionProbe::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void ReflectionProbe::_validate_property(PropertyInfo &property) const { if (property.name == "interior/ambient_color" || property.name == "interior/ambient_color_energy") { if (ambient_mode != AMBIENT_COLOR) { diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h index d0643496a4..424976d895 100644 --- a/scene/3d/reflection_probe.h +++ b/scene/3d/reflection_probe.h @@ -113,7 +113,6 @@ public: UpdateMode get_update_mode() const; virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; ReflectionProbe(); ~ReflectionProbe(); diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp index 2770b6f40c..8b714850d6 100644 --- a/scene/3d/remote_transform_3d.cpp +++ b/scene/3d/remote_transform_3d.cpp @@ -111,8 +111,8 @@ void RemoteTransform3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { _update_cache(); - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_inside_tree()) { break; @@ -121,7 +121,6 @@ void RemoteTransform3D::_notification(int p_what) { if (cache.is_valid()) { _update_remote(); } - } break; } } diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index b6b5920f69..598897456d 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -318,11 +318,9 @@ void Skeleton3D::_notification(int p_what) { rs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i)); } } - #ifdef TOOLS_ENABLED emit_signal(SceneStringNames::get_singleton()->pose_updated); #endif // TOOLS_ENABLED - } break; #ifndef _3D_DISABLED @@ -344,19 +342,14 @@ void Skeleton3D::_notification(int p_what) { if (modification_stack.is_valid()) { execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process); } - } break; -#endif // _3D_DISABLED -#ifndef _3D_DISABLED case NOTIFICATION_INTERNAL_PROCESS: { if (modification_stack.is_valid()) { execute_modifications(get_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_process); } } break; -#endif // _3D_DISABLED -#ifndef _3D_DISABLED case NOTIFICATION_READY: { set_physics_process_internal(true); set_process_internal(true); diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index c645009c72..f29b060069 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -407,14 +407,14 @@ void SkeletonIK3D::_notification(int p_what) { set_process_priority(1); reload_chain(); } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (target_node_override) { reload_goal(); } - _solve_chain(); - } break; + case NOTIFICATION_EXIT_TREE: { reload_chain(); } break; diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp index 8a8964f69a..230801bd52 100644 --- a/scene/3d/spring_arm_3d.cpp +++ b/scene/3d/spring_arm_3d.cpp @@ -29,23 +29,26 @@ /*************************************************************************/ #include "spring_arm_3d.h" + #include "scene/3d/camera_3d.h" void SpringArm3D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_ENTER_TREE: { if (!Engine::get_singleton()->is_editor_hint()) { set_physics_process_internal(true); } - break; - case NOTIFICATION_EXIT_TREE: + } break; + + case NOTIFICATION_EXIT_TREE: { if (!Engine::get_singleton()->is_editor_hint()) { set_physics_process_internal(false); } - break; - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: + } break; + + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { process_spring(); - break; + } break; } } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 331d58927b..514bd4aba0 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -66,23 +66,25 @@ void SpriteBase3D::_propagate_color_changed() { } void SpriteBase3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (!pending_update) { - _im_update(); - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (!pending_update) { + _im_update(); + } - parent_sprite = Object::cast_to<SpriteBase3D>(get_parent()); - if (parent_sprite) { - pI = parent_sprite->children.push_back(this); - } - } + parent_sprite = Object::cast_to<SpriteBase3D>(get_parent()); + if (parent_sprite) { + pI = parent_sprite->children.push_back(this); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - if (parent_sprite) { - parent_sprite->children.erase(pI); - pI = nullptr; - parent_sprite = nullptr; - } + case NOTIFICATION_EXIT_TREE: { + if (parent_sprite) { + parent_sprite->children.erase(pI); + pI = nullptr; + parent_sprite = nullptr; + } + } break; } } @@ -175,10 +177,6 @@ AABB SpriteBase3D::get_aabb() const { return aabb; } -Vector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) { return triangle_mesh; @@ -694,10 +692,6 @@ Rect2 Sprite3D::get_item_rect() const { if (texture.is_null()) { return Rect2(0, 0, 1, 1); } - /* - if (texture.is_null()) - return CanvasItem::get_item_rect(); - */ Size2 s; @@ -1021,14 +1015,14 @@ void AnimatedSprite3D::_notification(int p_what) { return; } - float speed = frames->get_animation_speed(animation); - if (speed == 0) { - return; //do nothing - } - double remaining = get_process_delta_time(); while (remaining) { + double speed = frames->get_animation_speed(animation); + if (speed == 0) { + return; // Do nothing. + } + if (timeout <= 0) { timeout = 1.0 / speed; diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 985103e190..92dbef0855 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -137,7 +137,7 @@ public: virtual Rect2 get_item_rect() const = 0; virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; + Ref<TriangleMesh> generate_triangle_mesh() const; SpriteBase3D(); diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index a5fd3a7dd0..8d02d26fc4 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -116,9 +116,7 @@ TypedArray<String> VehicleWheel3D::get_configuration_warnings() const { } void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) { - if (m_raycastInfo.m_isInContact) - - { + if (m_raycastInfo.m_isInContact) { real_t project = m_raycastInfo.m_contactNormalWS.dot(m_raycastInfo.m_wheelDirectionWS); Vector3 chassis_velocity_at_contactPoint; Vector3 relpos = m_raycastInfo.m_contactPointWS - s->get_transform().origin; @@ -135,11 +133,7 @@ void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) { m_suspensionRelativeVelocity = projVel * inv; m_clippedInvContactDotSuspension = inv; } - - } - - else // Not in contact : position wheel in a nice (rest length) position - { + } else { // Not in contact : position wheel in a nice (rest length) position m_raycastInfo.m_suspensionLength = m_suspensionRestLength; m_suspensionRelativeVelocity = real_t(0.0); m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS; diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp index 44d2a3e03f..41cd604a4f 100644 --- a/scene/3d/visible_on_screen_notifier_3d.cpp +++ b/scene/3d/visible_on_screen_notifier_3d.cpp @@ -71,8 +71,11 @@ bool VisibleOnScreenNotifier3D::is_on_screen() const { } void VisibleOnScreenNotifier3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_EXIT_TREE) { - on_screen = false; + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_EXIT_TREE: { + on_screen = false; + } break; } } @@ -86,10 +89,6 @@ void VisibleOnScreenNotifier3D::_bind_methods() { ADD_SIGNAL(MethodInfo("screen_exited")); } -Vector<Face3> VisibleOnScreenNotifier3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - VisibleOnScreenNotifier3D::VisibleOnScreenNotifier3D() { RID notifier = RS::get_singleton()->visibility_notifier_create(); RS::get_singleton()->visibility_notifier_set_aabb(notifier, aabb); @@ -161,21 +160,23 @@ void VisibleOnScreenEnabler3D::_update_enable_mode(bool p_enable) { } } void VisibleOnScreenEnabler3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } - node_id = ObjectID(); - Node *node = get_node(enable_node_path); - if (node) { - node_id = node->get_instance_id(); - node->set_process_mode(PROCESS_MODE_DISABLED); - } - } + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - node_id = ObjectID(); + case NOTIFICATION_EXIT_TREE: { + node_id = ObjectID(); + } break; } } diff --git a/scene/3d/visible_on_screen_notifier_3d.h b/scene/3d/visible_on_screen_notifier_3d.h index 852c7e2ed3..fe17f1e444 100644 --- a/scene/3d/visible_on_screen_notifier_3d.h +++ b/scene/3d/visible_on_screen_notifier_3d.h @@ -57,8 +57,6 @@ public: virtual AABB get_aabb() const override; bool is_on_screen() const; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; - VisibleOnScreenNotifier3D(); ~VisibleOnScreenNotifier3D(); }; diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 005bb5a737..b8a68cdca9 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -32,6 +32,14 @@ #include "scene/scene_string_names.h" +AABB VisualInstance3D::get_aabb() const { + AABB ret; + if (GDVIRTUAL_CALL(_get_aabb, ret)) { + return ret; + } + return AABB(); +} + AABB VisualInstance3D::get_transformed_aabb() const { return get_global_transform().xform(get_aabb()); } @@ -47,27 +55,21 @@ void VisualInstance3D::_update_visibility() { void VisualInstance3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_WORLD: { - // CHECK SKELETON => moving skeleton attaching logic to MeshInstance - /* - Skeleton *skeleton=Object::cast_to<Skeleton>(get_parent()); - if (skeleton) - RenderingServer::get_singleton()->instance_attach_skeleton( instance, skeleton->get_skeleton() ); - */ ERR_FAIL_COND(get_world_3d().is_null()); RenderingServer::get_singleton()->instance_set_scenario(instance, get_world_3d()->get_scenario()); _update_visibility(); - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { Transform3D gt = get_global_transform(); RenderingServer::get_singleton()->instance_set_transform(instance, gt); } break; + case NOTIFICATION_EXIT_WORLD: { RenderingServer::get_singleton()->instance_set_scenario(instance, RID()); RenderingServer::get_singleton()->instance_attach_skeleton(instance, RID()); - //RS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() ); - } break; + case NOTIFICATION_VISIBILITY_CHANGED: { _update_visibility(); } break; @@ -121,6 +123,7 @@ void VisualInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb); + GDVIRTUAL_BIND(_get_aabb); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask"); } @@ -220,9 +223,6 @@ GeometryInstance3D::VisibilityRangeFadeMode GeometryInstance3D::get_visibility_r return visibility_range_fade_mode; } -void GeometryInstance3D::_notification(int p_what) { -} - const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringName p_name) const { StringName *r = instance_uniform_property_remap.getptr(p_name); if (!r) { diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index be964e5080..1c044ba681 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -49,6 +49,7 @@ protected: void _notification(int p_what); static void _bind_methods(); + GDVIRTUAL0RC(AABB, _get_aabb) public: enum GetFacesFlags { FACES_SOLID = 1, // solid geometry @@ -58,8 +59,7 @@ public: }; RID get_instance() const; - virtual AABB get_aabb() const = 0; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const = 0; + virtual AABB get_aabb() const; virtual AABB get_transformed_aabb() const; // helper @@ -137,7 +137,6 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index bfe3c80a4f..6840d15f78 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -450,10 +450,6 @@ AABB VoxelGI::get_aabb() const { return AABB(-extents, extents * 2); } -Vector<Face3> VoxelGI::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - TypedArray<String> VoxelGI::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h index 3678bd4f3b..e1a38dd7a0 100644 --- a/scene/3d/voxel_gi.h +++ b/scene/3d/voxel_gi.h @@ -149,7 +149,6 @@ public: void bake(Node *p_from_node = nullptr, bool p_create_visual_debug = false); virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index 98f28a8cff..300e761f39 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -34,27 +34,32 @@ #include "scene/main/window.h" void WorldEnvironment::_notification(int p_what) { - if (p_what == Node3D::NOTIFICATION_ENTER_WORLD || p_what == Node3D::NOTIFICATION_ENTER_TREE) { - if (environment.is_valid()) { - add_to_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - _update_current_environment(); - } - - if (camera_effects.is_valid()) { - add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - _update_current_camera_effects(); - } - - } else if (p_what == Node3D::NOTIFICATION_EXIT_WORLD || p_what == Node3D::NOTIFICATION_EXIT_TREE) { - if (environment.is_valid()) { - remove_from_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - _update_current_environment(); - } - - if (camera_effects.is_valid()) { - remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - _update_current_camera_effects(); - } + switch (p_what) { + case Node3D::NOTIFICATION_ENTER_WORLD: + case Node3D::NOTIFICATION_ENTER_TREE: { + if (environment.is_valid()) { + add_to_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_environment(); + } + + if (camera_effects.is_valid()) { + add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_effects(); + } + } break; + + case Node3D::NOTIFICATION_EXIT_WORLD: + case Node3D::NOTIFICATION_EXIT_TREE: { + if (environment.is_valid()) { + remove_from_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_environment(); + } + + if (camera_effects.is_valid()) { + remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_effects(); + } + } break; } } diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 211c39c949..efae81e048 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -44,16 +44,17 @@ void XRCamera3D::_notification(int p_what) { if (origin != nullptr) { origin->set_tracked_camera(this); } - }; break; + } break; + case NOTIFICATION_EXIT_TREE: { // need to find our XROrigin3D parent and let it know we're no longer its camera! XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); if (origin != nullptr && origin->get_tracked_camera() == this) { origin->set_tracked_camera(nullptr); } - }; break; - }; -}; + } break; + } +} void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) { if (p_tracker_name == tracker_name) { @@ -447,11 +448,6 @@ void XRController3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand); - ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble); - ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble"); - ADD_PROPERTY_DEFAULT("rumble", 0.0); - ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value"))); @@ -557,20 +553,6 @@ Vector2 XRController3D::get_axis(const StringName &p_name) const { } } -real_t XRController3D::get_rumble() const { - if (!tracker.is_valid()) { - return 0.0; - } - - return tracker->get_rumble(); -} - -void XRController3D::set_rumble(real_t p_rumble) { - if (tracker.is_valid()) { - tracker->set_rumble(p_rumble); - } -} - XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const { // get our XRServer if (!tracker.is_valid()) { @@ -611,7 +593,7 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const { } } - bool xr_enabled = GLOBAL_GET("rendering/xr/enabled"); + bool xr_enabled = GLOBAL_GET("xr/shaders/enabled"); if (!xr_enabled) { warnings.push_back(TTR("XR is not enabled in rendering project settings. Stereoscopic output is not supported unless this is enabled.")); } @@ -657,10 +639,12 @@ void XROrigin3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { set_process_internal(true); - }; break; + } break; + case NOTIFICATION_EXIT_TREE: { set_process_internal(false); - }; break; + } break; + case NOTIFICATION_INTERNAL_PROCESS: { // set our world origin to our node transform xr_server->set_world_origin(get_global_transform()); @@ -673,11 +657,9 @@ void XROrigin3D::_notification(int p_what) { // now apply this to our camera tracked_camera->set_transform(t); - }; - }; break; - default: - break; - }; + } + } break; + } // send our notification to all active XE interfaces, they may need to react to it also for (int i = 0; i < xr_server->get_interface_count(); i++) { diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 5675cbd944..3079e20dc7 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -139,9 +139,6 @@ public: float get_value(const StringName &p_name) const; Vector2 get_axis(const StringName &p_name) const; - real_t get_rumble() const; - void set_rumble(real_t p_rumble); - XRPositionalTracker::TrackerHand get_tracker_hand() const; XRController3D() {} diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index a68f7e037d..5ea7f4b7d9 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -807,9 +807,6 @@ String AnimationNodeStateMachine::get_caption() const { return "StateMachine"; } -void AnimationNodeStateMachine::_notification(int p_what) { -} - Ref<AnimationNode> AnimationNodeStateMachine::get_child_by_name(const StringName &p_name) { return get_node(p_name); } diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index b980556875..3bae0fcffa 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -164,7 +164,6 @@ private: void _tree_changed(); protected: - void _notification(int p_what); static void _bind_methods(); bool _set(const StringName &p_name, const Variant &p_value); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 4a3fd72080..402418e5a9 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -202,15 +202,16 @@ void AnimationPlayer::_notification(int p_what) { set_physics_process_internal(false); set_process_internal(false); } - //_set_process(false); clear_caches(); } break; + case NOTIFICATION_READY: { if (!Engine::get_singleton()->is_editor_hint() && animation_set.has(autoplay)) { play(autoplay); _animation_process(0); } } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (process_callback == ANIMATION_PROCESS_PHYSICS) { break; @@ -220,6 +221,7 @@ void AnimationPlayer::_notification(int p_what) { _animation_process(get_process_delta_time()); } } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (process_callback == ANIMATION_PROCESS_IDLE) { break; @@ -229,6 +231,7 @@ void AnimationPlayer::_notification(int p_what) { _animation_process(get_physics_process_delta_time()); } } break; + case NOTIFICATION_EXIT_TREE: { clear_caches(); } break; @@ -398,6 +401,22 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov } } +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()); + const Variant *args = p_params.ptr(); + uint32_t argcount = p_params.size(); + for (uint32_t i = 0; i < argcount; i++) { + argptrs[i] = &args[i]; + } + if (p_deferred) { + MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount); + } else { + Callable::CallError ce; + p_object->callp(p_method, argptrs, argcount, ce); + } +} + void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double p_time, double p_delta, float p_interp, bool p_is_current, bool p_seeked, bool p_started, int p_pingponged) { _ensure_node_caches(p_anim); ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count()); @@ -592,18 +611,12 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } if (update_mode == Animation::UPDATE_CONTINUOUS || update_mode == Animation::UPDATE_CAPTURE || (p_delta == 0 && update_mode == Animation::UPDATE_DISCRETE)) { //delta == 0 means seek - Variant value = a->value_track_interpolate(i, p_time); if (value == Variant()) { continue; } - //thanks to trigger mode, this should be solved now.. - /* - if (p_delta==0 && value.get_type()==Variant::STRING) - continue; // doing this with strings is messy, should find another way - */ if (pa->accum_pass != accum_pass) { ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX); cache_update_prop[cache_update_prop_size++] = pa; @@ -680,41 +693,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double StringName method = a->method_track_get_name(i, E); Vector<Variant> params = a->method_track_get_params(i, E); - int s = params.size(); - - ERR_CONTINUE(s > VARIANT_ARG_MAX); #ifdef DEBUG_ENABLED if (!nc->node->has_method(method)) { ERR_PRINT("Invalid method call '" + method + "'. '" + a->get_name() + "' at node '" + get_path() + "'."); } #endif - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); if (can_call) { - if (method_call_mode == ANIMATION_METHOD_CALL_DEFERRED) { - MessageQueue::get_singleton()->push_call( - nc->node, - method, - s >= 1 ? params[0] : Variant(), - s >= 2 ? params[1] : Variant(), - s >= 3 ? params[2] : Variant(), - s >= 4 ? params[3] : Variant(), - s >= 5 ? params[4] : Variant(), - s >= 6 ? params[5] : Variant(), - s >= 7 ? params[6] : Variant(), - s >= 8 ? params[7] : Variant()); - } else { - nc->node->call( - method, - s >= 1 ? params[0] : Variant(), - s >= 2 ? params[1] : Variant(), - s >= 3 ? params[2] : Variant(), - s >= 4 ? params[3] : Variant(), - s >= 5 ? params[4] : Variant(), - s >= 6 ? params[5] : Variant(), - s >= 7 ? params[6] : Variant(), - s >= 8 ? params[7] : Variant()); - } + _call_object(nc->node, method, params, method_call_mode == ANIMATION_METHOD_CALL_DEFERRED); } } @@ -757,7 +743,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx); if (!stream.is_valid()) { - nc->node->call("stop"); + nc->node->call(SNAME("stop")); nc->audio_playing = false; playing_caches.erase(nc); } else { @@ -767,14 +753,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double float len = stream->get_length(); if (start_ofs > len - end_ofs) { - nc->node->call("stop"); + nc->node->call(SNAME("stop")); nc->audio_playing = false; playing_caches.erase(nc); continue; } - nc->node->call("set_stream", stream); - nc->node->call("play", start_ofs); + nc->node->call(SNAME("set_stream"), stream); + nc->node->call(SNAME("play"), start_ofs); nc->audio_playing = true; playing_caches.insert(nc); @@ -796,7 +782,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx); if (!stream.is_valid()) { - nc->node->call("stop"); + nc->node->call(SNAME("stop")); nc->audio_playing = false; playing_caches.erase(nc); } else { @@ -804,8 +790,8 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double float end_ofs = a->audio_track_get_key_end_offset(i, idx); float len = stream->get_length(); - nc->node->call("set_stream", stream); - nc->node->call("play", start_ofs); + nc->node->call(SNAME("set_stream"), stream); + nc->node->call(SNAME("play"), start_ofs); nc->audio_playing = true; playing_caches.insert(nc); @@ -836,7 +822,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double if (stop) { //time to stop - nc->node->call("stop"); + nc->node->call(SNAME("stop")); nc->audio_playing = false; playing_caches.erase(nc); } @@ -1547,7 +1533,7 @@ void AnimationPlayer::_animation_changed() { void AnimationPlayer::_stop_playing_caches() { for (Set<TrackNodeCache *>::Element *E = playing_caches.front(); E; E = E->next()) { if (E->get()->node && E->get()->audio_playing) { - E->get()->node->call("stop"); + E->get()->node->call(SNAME("stop")); } if (E->get()->node && E->get()->animation_playing) { AnimationPlayer *player = Object::cast_to<AnimationPlayer>(E->get()->node); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index f2f69fc439..e0e94d8632 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -490,7 +490,7 @@ void AnimationTree::set_active(bool p_active) { if (!active && is_inside_tree()) { for (Set<TrackCache *>::Element *E = playing_caches.front(); E; E = E->next()) { if (ObjectDB::get_instance(E->get()->object_id)) { - E->get()->object->call("stop"); + E->get()->object->call(SNAME("stop")); } } @@ -796,6 +796,21 @@ void AnimationTree::_clear_caches() { cache_valid = false; } +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()); + const Variant *args = p_params.ptr(); + uint32_t argcount = p_params.size(); + for (uint32_t i = 0; i < argcount; i++) { + argptrs[i] = &args[i]; + } + if (p_deferred) { + MessageQueue::get_singleton()->push_callp(p_object, p_method, argptrs, argcount); + } else { + Callable::CallError ce; + p_object->callp(p_method, argptrs, argcount, ce); + } +} void AnimationTree::_process_graph(double p_delta) { _update_properties(); //if properties need updating, update them @@ -1286,25 +1301,10 @@ void AnimationTree::_process_graph(double p_delta) { for (int &F : indices) { StringName method = a->method_track_get_name(i, F); Vector<Variant> params = a->method_track_get_params(i, F); - - int s = params.size(); - - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); - ERR_CONTINUE(s > VARIANT_ARG_MAX); if (can_call) { - t->object->call_deferred( - method, - s >= 1 ? params[0] : Variant(), - s >= 2 ? params[1] : Variant(), - s >= 3 ? params[2] : Variant(), - s >= 4 ? params[3] : Variant(), - s >= 5 ? params[4] : Variant(), - s >= 6 ? params[5] : Variant(), - s >= 7 ? params[6] : Variant(), - s >= 8 ? params[7] : Variant()); + _call_object(t->object, method, params, true); } } - } break; case Animation::TYPE_BEZIER: { TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); @@ -1331,7 +1331,7 @@ void AnimationTree::_process_graph(double p_delta) { Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx); if (!stream.is_valid()) { - t->object->call("stop"); + t->object->call(SNAME("stop")); t->playing = false; playing_caches.erase(t); } else { @@ -1341,14 +1341,14 @@ void AnimationTree::_process_graph(double p_delta) { double len = stream->get_length(); if (start_ofs > len - end_ofs) { - t->object->call("stop"); + t->object->call(SNAME("stop")); t->playing = false; playing_caches.erase(t); continue; } - t->object->call("set_stream", stream); - t->object->call("play", start_ofs); + t->object->call(SNAME("set_stream"), stream); + t->object->call(SNAME("play"), start_ofs); t->playing = true; playing_caches.insert(t); @@ -1370,7 +1370,7 @@ void AnimationTree::_process_graph(double p_delta) { Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx); if (!stream.is_valid()) { - t->object->call("stop"); + t->object->call(SNAME("stop")); t->playing = false; playing_caches.erase(t); } else { @@ -1378,8 +1378,8 @@ void AnimationTree::_process_graph(double p_delta) { double end_ofs = a->audio_track_get_key_end_offset(i, idx); double len = stream->get_length(); - t->object->call("set_stream", stream); - t->object->call("play", start_ofs); + t->object->call(SNAME("set_stream"), stream); + t->object->call(SNAME("play"), start_ofs); t->playing = true; playing_caches.insert(t); @@ -1416,7 +1416,7 @@ void AnimationTree::_process_graph(double p_delta) { if (stop) { //time to stop - t->object->call("stop"); + t->object->call(SNAME("stop")); t->playing = false; playing_caches.erase(t); } @@ -1424,10 +1424,10 @@ void AnimationTree::_process_graph(double p_delta) { } real_t db = Math::linear2db(MAX(blend, 0.00001)); - if (t->object->has_method("set_unit_db")) { - t->object->call("set_unit_db", db); + if (t->object->has_method(SNAME("set_unit_db"))) { + t->object->call(SNAME("set_unit_db"), db); } else { - t->object->call("set_volume_db", db); + t->object->call(SNAME("set_volume_db"), db); } } break; case Animation::TYPE_ANIMATION: { @@ -1586,29 +1586,37 @@ void AnimationTree::advance(real_t p_time) { } void AnimationTree::_notification(int p_what) { - if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_callback == ANIMATION_PROCESS_PHYSICS) { - _process_graph(get_physics_process_delta_time()); - } - - if (active && p_what == NOTIFICATION_INTERNAL_PROCESS && process_callback == ANIMATION_PROCESS_IDLE) { - _process_graph(get_process_delta_time()); - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (last_animation_player.is_valid()) { + Object *player = ObjectDB::get_instance(last_animation_player); + if (player) { + player->connect("caches_cleared", callable_mp(this, &AnimationTree::_clear_caches)); + } + } + } break; + + case NOTIFICATION_EXIT_TREE: { + _clear_caches(); + if (last_animation_player.is_valid()) { + Object *player = ObjectDB::get_instance(last_animation_player); + if (player) { + player->disconnect("caches_cleared", callable_mp(this, &AnimationTree::_clear_caches)); + } + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - _clear_caches(); - if (last_animation_player.is_valid()) { - Object *player = ObjectDB::get_instance(last_animation_player); - if (player) { - player->disconnect("caches_cleared", callable_mp(this, &AnimationTree::_clear_caches)); + case NOTIFICATION_INTERNAL_PROCESS: { + if (active && process_callback == ANIMATION_PROCESS_IDLE) { + _process_graph(get_process_delta_time()); } - } - } else if (p_what == NOTIFICATION_ENTER_TREE) { - if (last_animation_player.is_valid()) { - Object *player = ObjectDB::get_instance(last_animation_player); - if (player) { - player->connect("caches_cleared", callable_mp(this, &AnimationTree::_clear_caches)); + } break; + + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (active && process_callback == ANIMATION_PROCESS_PHYSICS) { + _process_graph(get_physics_process_delta_time()); } - } + } break; } } diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp index 0d44687588..42adc1ea02 100644 --- a/scene/animation/root_motion_view.cpp +++ b/scene/animation/root_motion_view.cpp @@ -29,8 +29,10 @@ /*************************************************************************/ #include "root_motion_view.h" + #include "scene/animation/animation_tree.h" #include "scene/resources/material.h" + void RootMotionView::set_animation_path(const NodePath &p_path) { path = p_path; first = true; @@ -76,84 +78,87 @@ bool RootMotionView::get_zero_y() const { } void RootMotionView::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - immediate_material = StandardMaterial3D::get_material_for_2d(false, true, false, false, false); - first = true; - } - - if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - Transform3D transform; - - if (has_node(path)) { - Node *node = get_node(path); - - AnimationTree *tree = Object::cast_to<AnimationTree>(node); - if (tree && tree->is_active() && tree->get_root_motion_track() != NodePath()) { - if (is_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_PHYSICS) { - set_process_internal(false); - set_physics_process_internal(true); - } - - if (is_physics_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_IDLE) { - set_process_internal(true); - set_physics_process_internal(false); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + immediate_material = StandardMaterial3D::get_material_for_2d(false, true, false, false, false); + first = true; + } break; + + case NOTIFICATION_INTERNAL_PROCESS: + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + Transform3D transform; + + if (has_node(path)) { + Node *node = get_node(path); + + AnimationTree *tree = Object::cast_to<AnimationTree>(node); + if (tree && tree->is_active() && tree->get_root_motion_track() != NodePath()) { + if (is_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_PHYSICS) { + set_process_internal(false); + set_physics_process_internal(true); + } + + if (is_physics_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } + + transform = tree->get_root_motion_transform(); } - - transform = tree->get_root_motion_transform(); } - } - if (!first && transform == Transform3D()) { - return; - } + if (!first && transform == Transform3D()) { + return; + } - first = false; + first = false; - transform.orthonormalize(); //don't want scale, too imprecise - transform.affine_invert(); + transform.orthonormalize(); //don't want scale, too imprecise + transform.affine_invert(); - accumulated = transform * accumulated; - accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size); - if (zero_y) { - accumulated.origin.y = 0; - } - accumulated.origin.z = Math::fposmod(accumulated.origin.z, cell_size); + accumulated = transform * accumulated; + accumulated.origin.x = Math::fposmod(accumulated.origin.x, cell_size); + if (zero_y) { + accumulated.origin.y = 0; + } + accumulated.origin.z = Math::fposmod(accumulated.origin.z, cell_size); - immediate->clear_surfaces(); + immediate->clear_surfaces(); - int cells_in_radius = int((radius / cell_size) + 1.0); + int cells_in_radius = int((radius / cell_size) + 1.0); - immediate->surface_begin(Mesh::PRIMITIVE_LINES, immediate_material); + immediate->surface_begin(Mesh::PRIMITIVE_LINES, immediate_material); - for (int i = -cells_in_radius; i < cells_in_radius; i++) { - for (int j = -cells_in_radius; j < cells_in_radius; j++) { - Vector3 from(i * cell_size, 0, j * cell_size); - Vector3 from_i((i + 1) * cell_size, 0, j * cell_size); - Vector3 from_j(i * cell_size, 0, (j + 1) * cell_size); - from = accumulated.xform(from); - from_i = accumulated.xform(from_i); - from_j = accumulated.xform(from_j); + for (int i = -cells_in_radius; i < cells_in_radius; i++) { + for (int j = -cells_in_radius; j < cells_in_radius; j++) { + Vector3 from(i * cell_size, 0, j * cell_size); + Vector3 from_i((i + 1) * cell_size, 0, j * cell_size); + Vector3 from_j(i * cell_size, 0, (j + 1) * cell_size); + from = accumulated.xform(from); + from_i = accumulated.xform(from_i); + from_j = accumulated.xform(from_j); - Color c = color, c_i = color, c_j = color; - c.a *= MAX(0, 1.0 - from.length() / radius); - c_i.a *= MAX(0, 1.0 - from_i.length() / radius); - c_j.a *= MAX(0, 1.0 - from_j.length() / radius); + Color c = color, c_i = color, c_j = color; + c.a *= MAX(0, 1.0 - from.length() / radius); + c_i.a *= MAX(0, 1.0 - from_i.length() / radius); + c_j.a *= MAX(0, 1.0 - from_j.length() / radius); - immediate->surface_set_color(c); - immediate->surface_add_vertex(from); + immediate->surface_set_color(c); + immediate->surface_add_vertex(from); - immediate->surface_set_color(c_i); - immediate->surface_add_vertex(from_i); + immediate->surface_set_color(c_i); + immediate->surface_add_vertex(from_i); - immediate->surface_set_color(c); - immediate->surface_add_vertex(from); + immediate->surface_set_color(c); + immediate->surface_add_vertex(from); - immediate->surface_set_color(c_j); - immediate->surface_add_vertex(from_j); + immediate->surface_set_color(c_j); + immediate->surface_add_vertex(from_j); + } } - } - immediate->surface_end(); + immediate->surface_end(); + } break; } } @@ -161,10 +166,6 @@ AABB RootMotionView::get_aabb() const { return AABB(Vector3(-radius, 0, -radius), Vector3(radius * 2, 0.001, radius * 2)); } -Vector<Face3> RootMotionView::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - void RootMotionView::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation_path", "path"), &RootMotionView::set_animation_path); ClassDB::bind_method(D_METHOD("get_animation_path"), &RootMotionView::get_animation_path); diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h index e8b141c1fd..8cb8ea8a9a 100644 --- a/scene/animation/root_motion_view.h +++ b/scene/animation/root_motion_view.h @@ -71,7 +71,6 @@ public: bool get_zero_y() const; virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; RootMotionView(); ~RootMotionView(); diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 5f9d8a0d47..c8e8ff1cd1 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -35,49 +35,51 @@ #include "servers/audio_server.h" void AudioStreamPlayer::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (autoplay && !Engine::get_singleton()->is_editor_hint()) { - play(); - } - } - - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; - for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { - if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { - playbacks_to_remove.push_back(playback); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (autoplay && !Engine::get_singleton()->is_editor_hint()) { + play(); } - } - // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. - for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { - stream_playbacks.erase(playback); - } - if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { - // This node is no longer actively playing audio. - active.clear(); - set_process_internal(false); - } - if (!playbacks_to_remove.is_empty()) { - emit_signal(SNAME("finished")); - } - } + } break; + + case NOTIFICATION_INTERNAL_PROCESS: { + Vector<Ref<AudioStreamPlayback>> playbacks_to_remove; + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + if (playback.is_valid() && !AudioServer::get_singleton()->is_playback_active(playback) && !AudioServer::get_singleton()->is_playback_paused(playback)) { + playbacks_to_remove.push_back(playback); + } + } + // Now go through and remove playbacks that have finished. Removing elements from a Vector in a range based for is asking for trouble. + for (Ref<AudioStreamPlayback> &playback : playbacks_to_remove) { + stream_playbacks.erase(playback); + } + if (!playbacks_to_remove.is_empty() && stream_playbacks.is_empty()) { + // This node is no longer actively playing audio. + active.clear(); + set_process_internal(false); + } + if (!playbacks_to_remove.is_empty()) { + emit_signal(SNAME("finished")); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { - AudioServer::get_singleton()->stop_playback_stream(playback); - } - stream_playbacks.clear(); - } + case NOTIFICATION_EXIT_TREE: { + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + AudioServer::get_singleton()->stop_playback_stream(playback); + } + stream_playbacks.clear(); + } break; - if (p_what == NOTIFICATION_PAUSED) { - if (!can_process()) { - // Node can't process so we start fading out to silence - set_stream_paused(true); - } - } + case NOTIFICATION_PAUSED: { + if (!can_process()) { + // Node can't process so we start fading out to silence + set_stream_paused(true); + } + } break; - if (p_what == NOTIFICATION_UNPAUSED) { - set_stream_paused(false); + case NOTIFICATION_UNPAUSED: { + set_stream_paused(false); + } break; } } diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index e5b81f9d8d..ac0d017a23 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -34,6 +34,7 @@ #include "core/debugger/engine_profiler.h" #include "core/io/marshalls.h" #include "core/object/script_language.h" +#include "core/templates/local_vector.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" @@ -236,12 +237,28 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra live_editor->_res_set_func(p_args[0], p_args[1], p_args[2]); } else if (p_msg == "live_node_call") { - ERR_FAIL_COND_V(p_args.size() < 10, ERR_INVALID_DATA); - live_editor->_node_call_func(p_args[0], p_args[1], p_args[2], p_args[3], p_args[4], p_args[5], p_args[6], p_args[7], p_args[8], p_args[9]); + LocalVector<Variant> args; + LocalVector<Variant *> argptrs; + args.resize(p_args.size() - 2); + argptrs.resize(args.size()); + for (uint32_t i = 0; i < args.size(); i++) { + args[i] = p_args[i + 2]; + argptrs[i] = &args[i]; + } + live_editor->_node_call_func(p_args[0], p_args[1], (const Variant **)argptrs.ptr(), argptrs.size()); } else if (p_msg == "live_res_call") { ERR_FAIL_COND_V(p_args.size() < 10, ERR_INVALID_DATA); - live_editor->_res_call_func(p_args[0], p_args[1], p_args[2], p_args[3], p_args[4], p_args[5], p_args[6], p_args[7], p_args[8], p_args[9]); + + LocalVector<Variant> args; + LocalVector<Variant *> argptrs; + args.resize(p_args.size() - 2); + argptrs.resize(args.size()); + for (uint32_t i = 0; i < args.size(); i++) { + args[i] = p_args[i + 2]; + argptrs[i] = &args[i]; + } + live_editor->_res_call_func(p_args[0], p_args[1], (const Variant **)argptrs.ptr(), argptrs.size()); } else if (p_msg == "live_create_node") { ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA); @@ -636,7 +653,7 @@ void LiveEditor::_node_set_res_func(int p_id, const StringName &p_prop, const St _node_set_func(p_id, p_prop, r); } -void LiveEditor::_node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { +void LiveEditor::_node_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount) { SceneTree *scene_tree = SceneTree::get_singleton(); if (!scene_tree) { return; @@ -668,7 +685,8 @@ void LiveEditor::_node_call_func(int p_id, const StringName &p_method, VARIANT_A } Node *n2 = n->get_node(np); - n2->call(p_method, VARIANT_ARG_PASS); + Callable::CallError ce; + n2->callp(p_method, p_args, p_argcount, ce); } } @@ -699,7 +717,7 @@ void LiveEditor::_res_set_res_func(int p_id, const StringName &p_prop, const Str _res_set_func(p_id, p_prop, r); } -void LiveEditor::_res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { +void LiveEditor::_res_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount) { if (!live_edit_resource_cache.has(p_id)) { return; } @@ -715,7 +733,8 @@ void LiveEditor::_res_call_func(int p_id, const StringName &p_method, VARIANT_AR return; } - r->call(p_method, VARIANT_ARG_PASS); + Callable::CallError ce; + r->callp(p_method, p_args, p_argcount, ce); } void LiveEditor::_root_func(const NodePath &p_scene_path, const String &p_scene_from) { diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h index dd0a17c2dc..29d7da7d11 100644 --- a/scene/debugger/scene_debugger.h +++ b/scene/debugger/scene_debugger.h @@ -148,10 +148,10 @@ private: void _node_set_func(int p_id, const StringName &p_prop, const Variant &p_value); void _node_set_res_func(int p_id, const StringName &p_prop, const String &p_value); - void _node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); + void _node_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount); void _res_set_func(int p_id, const StringName &p_prop, const Variant &p_value); void _res_set_res_func(int p_id, const StringName &p_prop, const String &p_value); - void _res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); + void _res_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount); void _root_func(const NodePath &p_scene_path, const String &p_scene_from); void _create_node_func(const NodePath &p_parent, const String &p_type, const String &p_name); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index da2ef6c5ec..ab86face7e 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -81,42 +81,50 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) { } void BaseButton::_notification(int p_what) { - if (p_what == NOTIFICATION_MOUSE_ENTER) { - status.hovering = true; - update(); - } + switch (p_what) { + case NOTIFICATION_MOUSE_ENTER: { + status.hovering = true; + update(); + } break; - if (p_what == NOTIFICATION_MOUSE_EXIT) { - status.hovering = false; - update(); - } - if (p_what == NOTIFICATION_DRAG_BEGIN || p_what == NOTIFICATION_SCROLL_BEGIN) { - if (status.press_attempt) { - status.press_attempt = false; + case NOTIFICATION_MOUSE_EXIT: { + status.hovering = false; update(); - } - } + } break; - if (p_what == NOTIFICATION_FOCUS_ENTER) { - update(); - } + case NOTIFICATION_DRAG_BEGIN: + case NOTIFICATION_SCROLL_BEGIN: { + if (status.press_attempt) { + status.press_attempt = false; + update(); + } + } break; - if (p_what == NOTIFICATION_FOCUS_EXIT) { - if (status.press_attempt) { - status.press_attempt = false; - update(); - } else if (status.hovering) { + case NOTIFICATION_FOCUS_ENTER: { update(); - } - } + } break; - if (p_what == NOTIFICATION_EXIT_TREE || (p_what == NOTIFICATION_VISIBILITY_CHANGED && !is_visible_in_tree())) { - if (!toggle_mode) { - status.pressed = false; - } - status.hovering = false; - status.press_attempt = false; - status.pressing_inside = false; + case NOTIFICATION_FOCUS_EXIT: { + if (status.press_attempt) { + status.press_attempt = false; + update(); + } else if (status.hovering) { + update(); + } + } break; + + case NOTIFICATION_VISIBILITY_CHANGED: + case NOTIFICATION_EXIT_TREE: { + if (p_what == NOTIFICATION_VISIBILITY_CHANGED && is_visible_in_tree()) { + break; + } + if (!toggle_mode) { + status.pressed = false; + } + status.hovering = false; + status.press_attempt = false; + status.pressing_inside = false; + } break; } } @@ -341,7 +349,7 @@ Ref<Shortcut> BaseButton::get_shortcut() const { void BaseButton::unhandled_key_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shorcut_context()) { + if (!_is_focus_owner_in_shortcut_context()) { return; } @@ -396,7 +404,7 @@ Node *BaseButton::get_shortcut_context() const { return ctx_node; } -bool BaseButton::_is_focus_owner_in_shorcut_context() const { +bool BaseButton::_is_focus_owner_in_shortcut_context() const { if (shortcut_context == ObjectID()) { // No context, therefore global - always "in" context. return true; diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 6bfffe7575..a2b6ee0845 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -80,7 +80,7 @@ protected: virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); - bool _is_focus_owner_in_shorcut_context() const; + bool _is_focus_owner_in_shortcut_context() const; GDVIRTUAL0(_pressed) GDVIRTUAL1(_toggled, bool) diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index ed54410636..251648da69 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "box_container.h" + #include "label.h" #include "margin_container.h" @@ -294,9 +295,11 @@ void BoxContainer::_notification(int p_what) { case NOTIFICATION_SORT_CHILDREN: { _resort(); } break; + case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); } break; + case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { queue_sort(); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 3ed1b873af..724714b93b 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -78,6 +78,7 @@ void Button::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { update(); } break; + case NOTIFICATION_TRANSLATION_CHANGED: { xl_text = atr(text); _shape(); @@ -85,12 +86,14 @@ void Button::_notification(int p_what) { update_minimum_size(); update(); } break; + case NOTIFICATION_THEME_CHANGED: { _shape(); update_minimum_size(); update(); } break; + case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); Size2 size = get_size(); @@ -580,8 +583,8 @@ void Button::_bind_methods() { Button::Button(const String &p_text) { text_buf.instantiate(); text_buf->set_flags(TextServer::BREAK_MANDATORY); - set_mouse_filter(MOUSE_FILTER_STOP); + set_text(p_text); } diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp index f6cd74583b..33ec4006ae 100644 --- a/scene/gui/center_container.cpp +++ b/scene/gui/center_container.cpp @@ -78,21 +78,23 @@ Vector<int> CenterContainer::get_allowed_size_flags_vertical() const { } void CenterContainer::_notification(int p_what) { - if (p_what == NOTIFICATION_SORT_CHILDREN) { - Size2 size = get_size(); - for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to<Control>(get_child(i)); - if (!c) { - continue; - } - if (c->is_set_as_top_level()) { - continue; - } + switch (p_what) { + case NOTIFICATION_SORT_CHILDREN: { + Size2 size = get_size(); + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) { + continue; + } + if (c->is_set_as_top_level()) { + continue; + } - Size2 minsize = c->get_combined_minimum_size(); - Point2 ofs = use_top_left ? (-minsize * 0.5).floor() : ((size - minsize) / 2.0).floor(); - fit_child_in_rect(c, Rect2(ofs, minsize)); - } + Size2 minsize = c->get_combined_minimum_size(); + Point2 ofs = use_top_left ? (-minsize * 0.5).floor() : ((size - minsize) / 2.0).floor(); + fit_child_in_rect(c, Rect2(ofs, minsize)); + } + } break; } } diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index da2d4369d1..063a154bb2 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -84,34 +84,40 @@ Size2 CheckBox::get_minimum_size() const { } void CheckBox::_notification(int p_what) { - if ((p_what == NOTIFICATION_THEME_CHANGED) || (p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || (p_what == NOTIFICATION_TRANSLATION_CHANGED))) { - if (is_layout_rtl()) { - _set_internal_margin(SIDE_LEFT, 0.f); - _set_internal_margin(SIDE_RIGHT, get_icon_size().width); - } else { - _set_internal_margin(SIDE_LEFT, get_icon_size().width); - _set_internal_margin(SIDE_RIGHT, 0.f); - } - } else if (p_what == NOTIFICATION_DRAW) { - RID ci = get_canvas_item(); - - Ref<Texture2D> on = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_checked" : "checked", is_disabled() ? "_disabled" : "")); - Ref<Texture2D> off = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_unchecked" : "unchecked", is_disabled() ? "_disabled" : "")); - Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); - - Vector2 ofs; - if (is_layout_rtl()) { - ofs.x = get_size().x - sb->get_margin(SIDE_RIGHT) - get_icon_size().width; - } else { - ofs.x = sb->get_margin(SIDE_LEFT); - } - ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant(SNAME("check_vadjust")); - - if (is_pressed()) { - on->draw(ci, ofs); - } else { - off->draw(ci, ofs); - } + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: + case NOTIFICATION_TRANSLATION_CHANGED: { + if (is_layout_rtl()) { + _set_internal_margin(SIDE_LEFT, 0.f); + _set_internal_margin(SIDE_RIGHT, get_icon_size().width); + } else { + _set_internal_margin(SIDE_LEFT, get_icon_size().width); + _set_internal_margin(SIDE_RIGHT, 0.f); + } + } break; + + case NOTIFICATION_DRAW: { + RID ci = get_canvas_item(); + + Ref<Texture2D> on = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_checked" : "checked", is_disabled() ? "_disabled" : "")); + Ref<Texture2D> off = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_unchecked" : "unchecked", is_disabled() ? "_disabled" : "")); + Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); + + Vector2 ofs; + if (is_layout_rtl()) { + ofs.x = get_size().x - sb->get_margin(SIDE_RIGHT) - get_icon_size().width; + } else { + ofs.x = sb->get_margin(SIDE_LEFT); + } + ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant(SNAME("check_vadjust")); + + if (is_pressed()) { + on->draw(ci, ofs); + } else { + off->draw(ci, ofs); + } + } break; } } diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index afb23a540b..527b0061ac 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -61,53 +61,62 @@ Size2 CheckButton::get_minimum_size() const { } void CheckButton::_notification(int p_what) { - if ((p_what == NOTIFICATION_THEME_CHANGED) || (p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED) || (p_what == NOTIFICATION_TRANSLATION_CHANGED)) { - if (is_layout_rtl()) { - _set_internal_margin(SIDE_LEFT, get_icon_size().width); - _set_internal_margin(SIDE_RIGHT, 0.f); - } else { - _set_internal_margin(SIDE_LEFT, 0.f); - _set_internal_margin(SIDE_RIGHT, get_icon_size().width); - } - } else if (p_what == NOTIFICATION_DRAW) { - RID ci = get_canvas_item(); - bool rtl = is_layout_rtl(); - - Ref<Texture2D> on; - if (rtl) { - on = Control::get_theme_icon(is_disabled() ? "on_disabled_mirrored" : "on_mirrored"); - } else { - on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on"); - } - Ref<Texture2D> off; - if (rtl) { - off = Control::get_theme_icon(is_disabled() ? "off_disabled_mirrored" : "off_mirrored"); - } else { - off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off"); - } - - Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); - Vector2 ofs; - Size2 tex_size = get_icon_size(); - - if (rtl) { - ofs.x = sb->get_margin(SIDE_LEFT); - } else { - ofs.x = get_size().width - (tex_size.width + sb->get_margin(SIDE_RIGHT)); - } - ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant(SNAME("check_vadjust")); - - if (is_pressed()) { - on->draw(ci, ofs); - } else { - off->draw(ci, ofs); - } + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: + case NOTIFICATION_TRANSLATION_CHANGED: { + if (is_layout_rtl()) { + _set_internal_margin(SIDE_LEFT, get_icon_size().width); + _set_internal_margin(SIDE_RIGHT, 0.f); + } else { + _set_internal_margin(SIDE_LEFT, 0.f); + _set_internal_margin(SIDE_RIGHT, get_icon_size().width); + } + } break; + + case NOTIFICATION_DRAW: { + RID ci = get_canvas_item(); + bool rtl = is_layout_rtl(); + + Ref<Texture2D> on; + if (rtl) { + on = Control::get_theme_icon(is_disabled() ? "on_disabled_mirrored" : "on_mirrored"); + } else { + on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on"); + } + Ref<Texture2D> off; + if (rtl) { + off = Control::get_theme_icon(is_disabled() ? "off_disabled_mirrored" : "off_mirrored"); + } else { + off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off"); + } + + Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); + Vector2 ofs; + Size2 tex_size = get_icon_size(); + + if (rtl) { + ofs.x = sb->get_margin(SIDE_LEFT); + } else { + ofs.x = get_size().width - (tex_size.width + sb->get_margin(SIDE_RIGHT)); + } + ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant(SNAME("check_vadjust")); + + if (is_pressed()) { + on->draw(ci, ofs); + } else { + off->draw(ci, ofs); + } + } break; } } -CheckButton::CheckButton() { +CheckButton::CheckButton(const String &p_text) : + Button(p_text) { set_toggle_mode(true); + set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); + if (is_layout_rtl()) { _set_internal_margin(SIDE_LEFT, get_icon_size().width); } else { diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h index 9a72d04db2..7d4bb8bdfc 100644 --- a/scene/gui/check_button.h +++ b/scene/gui/check_button.h @@ -42,7 +42,7 @@ protected: void _notification(int p_what); public: - CheckButton(); + CheckButton(const String &p_text = String()); ~CheckButton(); }; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 8cb8a78e8d..3fa0cec302 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -74,6 +74,7 @@ void CodeEdit::_notification(int p_what) { line_length_guideline_color = get_theme_color(SNAME("line_length_guideline_color")); } break; + case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); const Size2 size = get_size(); @@ -84,7 +85,7 @@ void CodeEdit::_notification(int p_what) { if (line_length_guideline_columns.size() > 0) { const int xmargin_beg = style_normal->get_margin(SIDE_LEFT) + get_total_gutter_width(); const int xmargin_end = size.width - style_normal->get_margin(SIDE_RIGHT) - (is_drawing_minimap() ? get_minimap_width() : 0); - const int char_size = Math::round(font->get_char_size('0', 0, font_size).width); + const float char_size = font->get_char_size('0', 0, font_size).width; for (int i = 0; i < line_length_guideline_columns.size(); i++) { const int xoffset = xmargin_beg + char_size * (int)line_length_guideline_columns[i] - get_h_scroll(); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 36ea843d1e..9f32ac223c 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -33,11 +33,11 @@ #include "core/input/input.h" #include "core/os/keyboard.h" #include "core/os/os.h" +#include "scene/main/window.h" #ifdef TOOLS_ENABLED #include "editor/editor_settings.h" #endif -#include "scene/main/window.h" List<Color> ColorPicker::preset_cache; @@ -45,7 +45,6 @@ void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { _update_color(); - #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { if (preset_cache.is_empty()) { @@ -1305,7 +1304,7 @@ void ColorPickerButton::pressed() { Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale(); - popup->set_as_minsize(); + popup->reset_size(); picker->_update_presets(); Rect2i usable_rect = popup->get_usable_parent_rect(); @@ -1347,17 +1346,18 @@ void ColorPickerButton::_notification(int p_what) { draw_texture(Control::get_theme_icon(SNAME("overbright_indicator"), SNAME("ColorPicker")), normal->get_offset()); } } break; + case NOTIFICATION_WM_CLOSE_REQUEST: { if (popup) { popup->hide(); } } break; - } - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (popup && !is_visible_in_tree()) { - popup->hide(); - } + case NOTIFICATION_VISIBILITY_CHANGED: { + if (popup && !is_visible_in_tree()) { + popup->hide(); + } + } break; } } @@ -1429,7 +1429,8 @@ void ColorPickerButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); } -ColorPickerButton::ColorPickerButton() { +ColorPickerButton::ColorPickerButton(const String &p_text) : + Button(p_text) { set_toggle_mode(true); } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index d6067b1cf4..6f3e16009c 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -231,7 +231,7 @@ public: ColorPicker *get_picker(); PopupPanel *get_popup(); - ColorPickerButton(); + ColorPickerButton(const String &p_text = String()); }; VARIANT_ENUM_CAST(ColorPicker::PickerShapeType); diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp index dbac1fc78a..2955f74a0c 100644 --- a/scene/gui/color_rect.cpp +++ b/scene/gui/color_rect.cpp @@ -40,8 +40,10 @@ Color ColorRect::get_color() const { } void ColorRect::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - draw_rect(Rect2(Point2(), get_size()), color); + switch (p_what) { + case NOTIFICATION_DRAW: { + draw_rect(Rect2(Point2(), get_size()), color); + } break; } } diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index b8a5a06147..1dd88371ea 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "container.h" + #include "core/object/message_queue.h" #include "scene/scene_string_names.h" @@ -177,12 +178,12 @@ void Container::_notification(int p_what) { pending_sort = false; queue_sort(); } break; - case NOTIFICATION_RESIZED: { - queue_sort(); - } break; + + case NOTIFICATION_RESIZED: case NOTIFICATION_THEME_CHANGED: { queue_sort(); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible_in_tree()) { queue_sort(); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index aa59df6337..d8659b1f18 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -190,10 +190,10 @@ String Control::properties_managed_by_container[] = { "anchor_top", "anchor_right", "anchor_bottom", - "rect_position", - "rect_rotation", - "rect_scale", - "rect_size" + "position", + "rotation", + "scale", + "size" }; void Control::accept_event() { @@ -250,42 +250,41 @@ Transform2D Control::_get_internal_transform() const { bool Control::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; - // Prefixes "custom_*" are supported for compatibility with 3.x. - if (!name.begins_with("theme_override") && !name.begins_with("custom")) { + if (!name.begins_with("theme_override")) { return false; } if (p_value.get_type() == Variant::NIL || (p_value.get_type() == Variant::OBJECT && (Object *)p_value == nullptr)) { - if (name.begins_with("theme_override_icons/") || name.begins_with("custom_icons/")) { + if (name.begins_with("theme_override_icons/")) { String dname = name.get_slicec('/', 1); if (data.icon_override.has(dname)) { data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed)); } data.icon_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - } else if (name.begins_with("theme_override_styles/") || name.begins_with("custom_styles/")) { + } else if (name.begins_with("theme_override_styles/")) { String dname = name.get_slicec('/', 1); if (data.style_override.has(dname)) { data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed)); } data.style_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - } else if (name.begins_with("theme_override_fonts/") || name.begins_with("custom_fonts/")) { + } else if (name.begins_with("theme_override_fonts/")) { String dname = name.get_slicec('/', 1); if (data.font_override.has(dname)) { data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_override_changed)); } data.font_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - } else if (name.begins_with("theme_override_font_sizes/") || name.begins_with("custom_font_sizes/")) { + } else if (name.begins_with("theme_override_font_sizes/")) { String dname = name.get_slicec('/', 1); data.font_size_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - } else if (name.begins_with("theme_override_colors/") || name.begins_with("custom_colors/")) { + } else if (name.begins_with("theme_override_colors/")) { String dname = name.get_slicec('/', 1); data.color_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); - } else if (name.begins_with("theme_override_constants/") || name.begins_with("custom_constants/")) { + } else if (name.begins_with("theme_override_constants/")) { String dname = name.get_slicec('/', 1); data.constant_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); @@ -294,22 +293,22 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { } } else { - if (name.begins_with("theme_override_icons/") || name.begins_with("custom_icons/")) { + if (name.begins_with("theme_override_icons/")) { String dname = name.get_slicec('/', 1); add_theme_icon_override(dname, p_value); - } else if (name.begins_with("theme_override_styles/") || name.begins_with("custom_styles/")) { + } else if (name.begins_with("theme_override_styles/")) { String dname = name.get_slicec('/', 1); add_theme_style_override(dname, p_value); - } else if (name.begins_with("theme_override_fonts/") || name.begins_with("custom_fonts/")) { + } else if (name.begins_with("theme_override_fonts/")) { String dname = name.get_slicec('/', 1); add_theme_font_override(dname, p_value); - } else if (name.begins_with("theme_override_font_sizes/") || name.begins_with("custom_font_sizes/")) { + } else if (name.begins_with("theme_override_font_sizes/")) { String dname = name.get_slicec('/', 1); add_theme_font_size_override(dname, p_value); - } else if (name.begins_with("theme_override_colors/") || name.begins_with("custom_colors/")) { + } else if (name.begins_with("theme_override_colors/")) { String dname = name.get_slicec('/', 1); add_theme_color_override(dname, p_value); - } else if (name.begins_with("theme_override_constants/") || name.begins_with("custom_constants/")) { + } else if (name.begins_with("theme_override_constants/")) { String dname = name.get_slicec('/', 1); add_theme_constant_override(dname, p_value); } else { @@ -491,7 +490,7 @@ void Control::_validate_property(PropertyInfo &property) const { } else if (Object::cast_to<Container>(parent_node)) { // If the parent is a container, display only container-related properties. if (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_") || property.name == "anchors_preset" || - (property.name.begins_with("rect_") && property.name != "rect_min_size" && property.name != "rect_clip_content" && property.name != "rect_global_position")) { + property.name == "position" || property.name == "rotation" || property.name == "scale" || property.name == "size" || property.name == "pivot_offset") { property.usage ^= PROPERTY_USAGE_EDITOR; } else if (property.name == "layout_mode") { @@ -691,17 +690,17 @@ void Control::_update_canvas_item_transform() { void Control::_notification(int p_notification) { switch (p_notification) { - case NOTIFICATION_ENTER_TREE: { - } break; case NOTIFICATION_POST_ENTER_TREE: { data.minimum_size_valid = false; data.is_rtl_dirty = true; _size_changed(); } break; + case NOTIFICATION_EXIT_TREE: { release_focus(); get_viewport()->_gui_remove_control(this); } break; + case NOTIFICATION_READY: { #ifdef DEBUG_ENABLED connect("ready", callable_mp(this, &Control::_clear_size_warning), varray(), CONNECT_DEFERRED | CONNECT_ONESHOT); @@ -764,6 +763,7 @@ void Control::_notification(int p_notification) { viewport->connect("size_changed", callable_mp(this, &Control::_size_changed)); } } break; + case NOTIFICATION_EXIT_CANVAS: { if (data.parent_canvas_item) { data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed)); @@ -784,8 +784,8 @@ void Control::_notification(int p_notification) { data.parent_canvas_item = nullptr; data.parent_window = nullptr; data.is_rtl_dirty = true; - } break; + case NOTIFICATION_MOVED_IN_PARENT: { // some parents need to know the order of the children to draw (like TabContainer) // update if necessary @@ -797,50 +797,52 @@ void Control::_notification(int p_notification) { if (data.RI) { get_viewport()->_gui_set_root_order_dirty(); } - } break; + case NOTIFICATION_RESIZED: { emit_signal(SceneStringNames::get_singleton()->resized); } break; + case NOTIFICATION_DRAW: { _update_canvas_item_transform(); RenderingServer::get_singleton()->canvas_item_set_custom_rect(get_canvas_item(), !data.disable_visibility_clip, Rect2(Point2(), get_size())); RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), data.clip_contents); - //emit_signal(SceneStringNames::get_singleton()->draw); - } break; + case NOTIFICATION_MOUSE_ENTER: { emit_signal(SceneStringNames::get_singleton()->mouse_entered); } break; + case NOTIFICATION_MOUSE_EXIT: { emit_signal(SceneStringNames::get_singleton()->mouse_exited); } break; + case NOTIFICATION_FOCUS_ENTER: { emit_signal(SceneStringNames::get_singleton()->focus_entered); update(); } break; + case NOTIFICATION_FOCUS_EXIT: { emit_signal(SceneStringNames::get_singleton()->focus_exited); update(); } break; + case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); update(); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible_in_tree()) { if (get_viewport() != nullptr) { get_viewport()->_gui_hide_control(this); } - - //remove key focus - } else { data.minimum_size_valid = false; _size_changed(); } - } break; + case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { if (is_inside_tree()) { @@ -1585,14 +1587,25 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, } void Control::_set_anchors_layout_preset(int p_preset) { - set_meta("_edit_layout_mode", (int)LayoutMode::LAYOUT_MODE_ANCHORS); + bool list_changed = false; + + if (has_meta("_edit_layout_mode") && (int)get_meta("_edit_layout_mode") != (int)LayoutMode::LAYOUT_MODE_ANCHORS) { + list_changed = true; + set_meta("_edit_layout_mode", (int)LayoutMode::LAYOUT_MODE_ANCHORS); + } if (p_preset == -1) { - set_meta("_edit_use_custom_anchors", true); - notify_property_list_changed(); + if (!has_meta("_edit_use_custom_anchors") || !(bool)get_meta("_edit_use_custom_anchors")) { + set_meta("_edit_use_custom_anchors", true); + notify_property_list_changed(); + } return; // Keep settings as is. } - set_meta("_edit_use_custom_anchors", false); + + if (!has_meta("_edit_use_custom_anchors") || (bool)get_meta("_edit_use_custom_anchors")) { + list_changed = true; + set_meta("_edit_use_custom_anchors", false); + } LayoutPreset preset = (LayoutPreset)p_preset; // Set correct anchors. @@ -1625,7 +1638,9 @@ void Control::_set_anchors_layout_preset(int p_preset) { // Select correct grow directions. set_grow_direction_preset(preset); - notify_property_list_changed(); + if (list_changed) { + notify_property_list_changed(); + } } int Control::_get_anchors_layout_preset() const { @@ -3327,8 +3342,8 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("is_auto_translating"), &Control::is_auto_translating); ADD_GROUP("Layout", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimum_size"), "set_custom_minimum_size", "get_custom_minimum_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode"); ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION); @@ -3357,15 +3372,13 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Left,Right,Both"), "set_h_grow_direction", "get_h_grow_direction"); ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Top,Bottom,Both"), "set_v_grow_direction", "get_v_grow_direction"); - ADD_SUBGROUP("Rectangle", "rect_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size"); - - ADD_SUBGROUP("Transform", "rect_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset"); + ADD_SUBGROUP("Transform", ""); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset"), "set_pivot_offset", "get_pivot_offset"); ADD_SUBGROUP("Container Sizing", "size_flags_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_horizontal", PROPERTY_HINT_FLAGS, "Fill:1,Expand:2,Shrink Center:4,Shrink End:8"), "set_h_size_flags", "get_h_size_flags"); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 1cbe3adb3c..e3744eedca 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -33,12 +33,7 @@ #include "core/os/keyboard.h" #include "core/string/print_string.h" #include "core/string/translation.h" -#include "line_edit.h" - -#ifdef TOOLS_ENABLED -#include "editor/editor_node.h" -#include "scene/main/window.h" // Only used to check for more modals when dimming the editor. -#endif +#include "scene/gui/line_edit.h" // AcceptDialog @@ -72,21 +67,25 @@ void AcceptDialog::_notification(int p_what) { } } } break; + case NOTIFICATION_THEME_CHANGED: { bg->add_theme_style_override("panel", bg->get_theme_stylebox(SNAME("panel"), SNAME("AcceptDialog"))); } break; + case NOTIFICATION_EXIT_TREE: { if (parent_visible) { parent_visible->disconnect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); parent_visible = nullptr; } } break; + case NOTIFICATION_READY: case NOTIFICATION_WM_SIZE_CHANGED: { if (is_visible()) { _update_child_rects(); } } break; + case NOTIFICATION_WM_CLOSE_REQUEST: { _cancel_pressed(); } break; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index dad84461f4..e71ab64535 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -92,26 +92,30 @@ void FileDialog::_theme_changed() { } void FileDialog::_notification(int p_what) { - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (!is_visible()) { - set_process_unhandled_input(false); - } - } - if (p_what == NOTIFICATION_ENTER_TREE) { - dir_up->set_icon(vbox->get_theme_icon(SNAME("parent_folder"), SNAME("FileDialog"))); - if (vbox->is_layout_rtl()) { - dir_prev->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog"))); - dir_next->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog"))); - } else { - dir_prev->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog"))); - dir_next->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog"))); - } - refresh->set_icon(vbox->get_theme_icon(SNAME("reload"), SNAME("FileDialog"))); - show_hidden->set_icon(vbox->get_theme_icon(SNAME("toggle_hidden"), SNAME("FileDialog"))); - _theme_changed(); - } - if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { - update_filters(); + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible()) { + set_process_unhandled_input(false); + } + } break; + + case NOTIFICATION_ENTER_TREE: { + dir_up->set_icon(vbox->get_theme_icon(SNAME("parent_folder"), SNAME("FileDialog"))); + if (vbox->is_layout_rtl()) { + dir_prev->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog"))); + dir_next->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog"))); + } else { + dir_prev->set_icon(vbox->get_theme_icon(SNAME("back_folder"), SNAME("FileDialog"))); + dir_next->set_icon(vbox->get_theme_icon(SNAME("forward_folder"), SNAME("FileDialog"))); + } + refresh->set_icon(vbox->get_theme_icon(SNAME("reload"), SNAME("FileDialog"))); + show_hidden->set_icon(vbox->get_theme_icon(SNAME("toggle_hidden"), SNAME("FileDialog"))); + _theme_changed(); + } break; + + case NOTIFICATION_TRANSLATION_CHANGED: { + update_filters(); + } break; } } @@ -172,7 +176,7 @@ void FileDialog::update_dir() { if (dir_access->get_current_dir().is_network_share_path()) { _update_drives(false); drives->add_item(RTR("Network")); - drives->set_item_disabled(drives->get_item_count() - 1, true); + drives->set_item_disabled(-1, true); drives->select(drives->get_item_count() - 1); } else { drives->select(dir_access->get_current_drive()); @@ -258,7 +262,8 @@ void FileDialog::_action_pressed() { return; } - String f = dir_access->get_current_dir().plus_file(file->get_text()); + String file_text = file->get_text(); + String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text); if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) { emit_signal(SNAME("file_selected"), f); @@ -914,9 +919,9 @@ void FileDialog::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir"), "set_current_dir", "get_current_dir"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file"), "set_current_file", "get_current_file"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path"), "set_current_path", "get_current_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*", PROPERTY_USAGE_NONE), "set_current_file", "get_current_file"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_path", "get_current_path"); ADD_SIGNAL(MethodInfo("file_selected", PropertyInfo(Variant::STRING, "path"))); ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::PACKED_STRING_ARRAY, "paths"))); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 36a6b262b0..7a50efe40f 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -70,7 +70,6 @@ private: Button *makedir; Access access = ACCESS_RESOURCES; - //Button *action; VBoxContainer *vbox; FileMode mode; LineEdit *dir; diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp index e806a4a8a6..3bd21f96b2 100644 --- a/scene/gui/flow_container.cpp +++ b/scene/gui/flow_container.cpp @@ -251,9 +251,11 @@ void FlowContainer::_notification(int p_what) { _resort(); update_minimum_size(); } break; + case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); } break; + case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { queue_sort(); diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index bec3d58384..0690acbe16 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -287,84 +287,85 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) { } void GradientEdit::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (!picker->is_connected("color_changed", callable_mp(this, &GradientEdit::_color_changed))) { - picker->connect("color_changed", callable_mp(this, &GradientEdit::_color_changed)); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (!picker->is_connected("color_changed", callable_mp(this, &GradientEdit::_color_changed))) { + picker->connect("color_changed", callable_mp(this, &GradientEdit::_color_changed)); + } + [[fallthrough]]; } - } + case NOTIFICATION_THEME_CHANGED: { + draw_spacing = BASE_SPACING * get_theme_default_base_scale(); + draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale(); + } break; - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - draw_spacing = BASE_SPACING * get_theme_default_base_scale(); - draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale(); - } + case NOTIFICATION_DRAW: { + int w = get_size().x; + int h = get_size().y; - if (p_what == NOTIFICATION_DRAW) { - int w = get_size().x; - int h = get_size().y; + if (w == 0 || h == 0) { + return; // Safety check. We have division by 'h'. And in any case there is nothing to draw with such size. + } - if (w == 0 || h == 0) { - return; // Safety check. We have division by 'h'. And in any case there is nothing to draw with such size. - } + int total_w = get_size().width - get_size().height - draw_spacing; - int total_w = get_size().width - get_size().height - draw_spacing; + // Draw checker pattern for ramp. + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true); - // Draw checker pattern for ramp. - draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true); + // Draw color ramp. + gradient_cache->set_points(points); + gradient_cache->set_interpolation_mode(interpolation_mode); + preview_texture->set_gradient(gradient_cache); + draw_texture_rect(preview_texture, Rect2(0, 0, total_w, h)); - // Draw color ramp. + // Draw point markers. + for (int i = 0; i < points.size(); i++) { + Color col = points[i].color.inverted(); + col.a = 0.9; - gradient_cache->set_points(points); - gradient_cache->set_interpolation_mode(interpolation_mode); - preview_texture->set_gradient(gradient_cache); - draw_texture_rect(preview_texture, Rect2(0, 0, total_w, h)); + draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col); + Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2); + draw_rect(rect, points[i].color, true); + draw_rect(rect, col, false); + if (grabbed == i) { + rect = rect.grow(-1); + if (has_focus()) { + draw_rect(rect, Color(1, 0, 0, 0.9), false); + } else { + draw_rect(rect, Color(0.6, 0, 0, 0.9), false); + } - // Draw point markers. - for (int i = 0; i < points.size(); i++) { - Color col = points[i].color.inverted(); - col.a = 0.9; - - draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col); - Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2); - draw_rect(rect, points[i].color, true); - draw_rect(rect, col, false); - if (grabbed == i) { - rect = rect.grow(-1); - if (has_focus()) { - draw_rect(rect, Color(1, 0, 0, 0.9), false); - } else { - draw_rect(rect, Color(0.6, 0, 0, 0.9), false); + rect = rect.grow(-1); + draw_rect(rect, col, false); } - - rect = rect.grow(-1); - draw_rect(rect, col, false); } - } - //Draw "button" for color selector - draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true); - if (grabbed != -1) { - //Draw with selection color - draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color); - } else { - //if no color selected draw grey color with 'X' on top. - draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1)); - draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6)); - } + // Draw "button" for color selector. + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true); + if (grabbed != -1) { + // Draw with selection color. + draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color); + } else { + // If no color selected draw grey color with 'X' on top. + draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1)); + draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6)); + draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6)); + } - // Draw borders around color ramp if in focus. - if (has_focus()) { - draw_line(Vector2(-1, -1), Vector2(total_w + 1, -1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + 1, -1), Vector2(total_w + 1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); - } - } + // Draw borders around color ramp if in focus. + if (has_focus()) { + draw_line(Vector2(-1, -1), Vector2(total_w + 1, -1), Color(1, 1, 1, 0.6)); + draw_line(Vector2(total_w + 1, -1), Vector2(total_w + 1, h + 1), Color(1, 1, 1, 0.6)); + draw_line(Vector2(total_w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); + draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); + } + } break; - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (!is_visible()) { - grabbing = false; - } + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible()) { + grabbing = false; + } + } break; } } diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 95575a8226..1394b4192f 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -423,82 +423,86 @@ void GraphEdit::remove_child_notify(Node *p_child) { } void GraphEdit::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { - port_grab_distance_horizontal = get_theme_constant(SNAME("port_grab_distance_horizontal")); - port_grab_distance_vertical = get_theme_constant(SNAME("port_grab_distance_vertical")); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + port_grab_distance_horizontal = get_theme_constant(SNAME("port_grab_distance_horizontal")); + port_grab_distance_vertical = get_theme_constant(SNAME("port_grab_distance_vertical")); + + zoom_minus->set_icon(get_theme_icon(SNAME("minus"))); + zoom_reset->set_icon(get_theme_icon(SNAME("reset"))); + zoom_plus->set_icon(get_theme_icon(SNAME("more"))); + snap_button->set_icon(get_theme_icon(SNAME("snap"))); + minimap_button->set_icon(get_theme_icon(SNAME("minimap"))); + layout_button->set_icon(get_theme_icon(SNAME("layout"))); + + zoom_label->set_custom_minimum_size(Size2(48, 0) * get_theme_default_base_scale()); + } break; - zoom_minus->set_icon(get_theme_icon(SNAME("minus"))); - zoom_reset->set_icon(get_theme_icon(SNAME("reset"))); - zoom_plus->set_icon(get_theme_icon(SNAME("more"))); - snap_button->set_icon(get_theme_icon(SNAME("snap"))); - minimap_button->set_icon(get_theme_icon(SNAME("minimap"))); - layout_button->set_icon(get_theme_icon(SNAME("layout"))); + case NOTIFICATION_READY: { + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); - zoom_label->set_custom_minimum_size(Size2(48, 0) * get_theme_default_base_scale()); - } - if (p_what == NOTIFICATION_READY) { - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); + h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height); + h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); - h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0); - h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); - h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height); - h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); + v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width); + v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); + } break; - v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width); - v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); - v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); - v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); - } - if (p_what == NOTIFICATION_DRAW) { - draw_style_box(get_theme_stylebox(SNAME("bg")), Rect2(Point2(), get_size())); + case NOTIFICATION_DRAW: { + draw_style_box(get_theme_stylebox(SNAME("bg")), Rect2(Point2(), get_size())); - if (is_using_snap()) { - //draw grid + if (is_using_snap()) { + // Draw grid. + int snap = get_snap(); - int snap = get_snap(); + Vector2 offset = get_scroll_ofs() / zoom; + Size2 size = get_size() / zoom; - Vector2 offset = get_scroll_ofs() / zoom; - Size2 size = get_size() / zoom; + Point2i from = (offset / float(snap)).floor(); + Point2i len = (size / float(snap)).floor() + Vector2(1, 1); - Point2i from = (offset / float(snap)).floor(); - Point2i len = (size / float(snap)).floor() + Vector2(1, 1); + Color grid_minor = get_theme_color(SNAME("grid_minor")); + Color grid_major = get_theme_color(SNAME("grid_major")); - Color grid_minor = get_theme_color(SNAME("grid_minor")); - Color grid_major = get_theme_color(SNAME("grid_major")); + for (int i = from.x; i < from.x + len.x; i++) { + Color color; - for (int i = from.x; i < from.x + len.x; i++) { - Color color; + if (ABS(i) % 10 == 0) { + color = grid_major; + } else { + color = grid_minor; + } - if (ABS(i) % 10 == 0) { - color = grid_major; - } else { - color = grid_minor; + float base_ofs = i * snap * zoom - offset.x * zoom; + draw_line(Vector2(base_ofs, 0), Vector2(base_ofs, get_size().height), color); } - float base_ofs = i * snap * zoom - offset.x * zoom; - draw_line(Vector2(base_ofs, 0), Vector2(base_ofs, get_size().height), color); - } + for (int i = from.y; i < from.y + len.y; i++) { + Color color; - for (int i = from.y; i < from.y + len.y; i++) { - Color color; + if (ABS(i) % 10 == 0) { + color = grid_major; + } else { + color = grid_minor; + } - if (ABS(i) % 10 == 0) { - color = grid_major; - } else { - color = grid_minor; + float base_ofs = i * snap * zoom - offset.y * zoom; + draw_line(Vector2(0, base_ofs), Vector2(get_size().width, base_ofs), color); } - - float base_ofs = i * snap * zoom - offset.y * zoom; - draw_line(Vector2(0, base_ofs), Vector2(get_size().width, base_ofs), color); } - } - } + } break; - if (p_what == NOTIFICATION_RESIZED) { - _update_scroll(); - top_layer->update(); - minimap->update(); + case NOTIFICATION_RESIZED: { + _update_scroll(); + top_layer->update(); + minimap->update(); + } break; } } @@ -1166,7 +1170,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { if (connecting) { force_connection_drag_end(); } else { - emit_signal(SNAME("popup_request"), get_screen_position() + b->get_position()); + emit_signal(SNAME("popup_request"), b->get_position()); } } } diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index e0c59dd1bf..ef0ac75cb4 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -31,6 +31,7 @@ #include "graph_node.h" #include "core/string/translation.h" + #ifdef TOOLS_ENABLED #include "graph_edit.h" #endif diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index 465c9dac78..3c1f4bb93b 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -179,11 +179,12 @@ void GridContainer::_notification(int p_what) { col_ofs += s.width + hsep; } } - } break; + case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); } break; + case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { queue_sort(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 0cb3249c1d..8c0f696a9f 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -83,6 +83,9 @@ int ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) { } void ItemList::set_item_text(int p_idx, const String &p_text) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].text = p_text; @@ -97,6 +100,9 @@ String ItemList::get_item_text(int p_idx) const { } void ItemList::set_item_text_direction(int p_idx, Control::TextDirection p_text_direction) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); if (items[p_idx].text_direction != p_text_direction) { @@ -119,6 +125,9 @@ void ItemList::clear_item_opentype_features(int p_idx) { } void ItemList::set_item_opentype_feature(int p_idx, const String &p_name, int p_value) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); int32_t tag = TS->name_to_tag(p_name); if (!items[p_idx].opentype_features.has(tag) || (int)items[p_idx].opentype_features[tag] != p_value) { @@ -138,6 +147,9 @@ int ItemList::get_item_opentype_feature(int p_idx, const String &p_name) const { } void ItemList::set_item_language(int p_idx, const String &p_language) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); if (items[p_idx].language != p_language) { items.write[p_idx].language = p_language; @@ -152,6 +164,9 @@ String ItemList::get_item_language(int p_idx) const { } void ItemList::set_item_tooltip_enabled(int p_idx, const bool p_enabled) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].tooltip_enabled = p_enabled; } @@ -162,6 +177,9 @@ bool ItemList::is_item_tooltip_enabled(int p_idx) const { } void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].tooltip = p_tooltip; @@ -175,6 +193,9 @@ String ItemList::get_item_tooltip(int p_idx) const { } void ItemList::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].icon = p_icon; @@ -189,6 +210,9 @@ Ref<Texture2D> ItemList::get_item_icon(int p_idx) const { } void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].icon_transposed = p_transposed; @@ -203,6 +227,9 @@ bool ItemList::is_item_icon_transposed(int p_idx) const { } void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].icon_region = p_region; @@ -217,6 +244,9 @@ Rect2 ItemList::get_item_icon_region(int p_idx) const { } void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].icon_modulate = p_modulate; @@ -230,6 +260,9 @@ Color ItemList::get_item_icon_modulate(int p_idx) const { } void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_color) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].custom_bg = p_custom_bg_color; @@ -243,6 +276,9 @@ Color ItemList::get_item_custom_bg_color(int p_idx) const { } void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_color) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].custom_fg = p_custom_fg_color; @@ -256,6 +292,9 @@ Color ItemList::get_item_custom_fg_color(int p_idx) const { } void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].tag_icon = p_tag_icon; @@ -270,6 +309,9 @@ Ref<Texture2D> ItemList::get_item_tag_icon(int p_idx) const { } void ItemList::set_item_selectable(int p_idx, bool p_selectable) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].selectable = p_selectable; @@ -281,6 +323,9 @@ bool ItemList::is_item_selectable(int p_idx) const { } void ItemList::set_item_disabled(int p_idx, bool p_disabled) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].disabled = p_disabled; @@ -293,6 +338,9 @@ bool ItemList::is_item_disabled(int p_idx) const { } void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].metadata = p_metadata; @@ -855,445 +903,451 @@ static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) { } void ItemList::_notification(int p_what) { - if (p_what == NOTIFICATION_RESIZED) { - shape_changed = true; - update(); - } + switch (p_what) { + case NOTIFICATION_RESIZED: { + shape_changed = true; + update(); + } break; + + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: + case NOTIFICATION_TRANSLATION_CHANGED: + case NOTIFICATION_THEME_CHANGED: { + for (int i = 0; i < items.size(); i++) { + _shape(i); + } + shape_changed = true; + update(); + } break; - if ((p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED) || (p_what == NOTIFICATION_TRANSLATION_CHANGED) || (p_what == NOTIFICATION_THEME_CHANGED)) { - for (int i = 0; i < items.size(); i++) { - _shape(i); - } - shape_changed = true; - update(); - } + case NOTIFICATION_DRAW: { + Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg")); - if (p_what == NOTIFICATION_DRAW) { - Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg")); + int mw = scroll_bar->get_minimum_size().x; + scroll_bar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -mw); + scroll_bar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, bg->get_margin(SIDE_TOP)); + scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM)); - int mw = scroll_bar->get_minimum_size().x; - scroll_bar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -mw); - scroll_bar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); - scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, bg->get_margin(SIDE_TOP)); - scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM)); + Size2 size = get_size(); - Size2 size = get_size(); + int width = size.width - bg->get_minimum_size().width; + if (scroll_bar->is_visible()) { + width -= mw; + } - int width = size.width - bg->get_minimum_size().width; - if (scroll_bar->is_visible()) { - width -= mw; - } + draw_style_box(bg, Rect2(Point2(), size)); - draw_style_box(bg, Rect2(Point2(), size)); + int hseparation = get_theme_constant(SNAME("hseparation")); + int vseparation = get_theme_constant(SNAME("vseparation")); + int icon_margin = get_theme_constant(SNAME("icon_margin")); + int line_separation = get_theme_constant(SNAME("line_separation")); + Color font_outline_color = get_theme_color(SNAME("font_outline_color")); + int outline_size = get_theme_constant(SNAME("outline_size")); - int hseparation = get_theme_constant(SNAME("hseparation")); - int vseparation = get_theme_constant(SNAME("vseparation")); - int icon_margin = get_theme_constant(SNAME("icon_margin")); - int line_separation = get_theme_constant(SNAME("line_separation")); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); + Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox(SNAME("selected_focus")) : get_theme_stylebox(SNAME("selected")); + Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox(SNAME("cursor")) : get_theme_stylebox(SNAME("cursor_unfocused")); + bool rtl = is_layout_rtl(); - Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox(SNAME("selected_focus")) : get_theme_stylebox(SNAME("selected")); - Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox(SNAME("cursor")) : get_theme_stylebox(SNAME("cursor_unfocused")); - bool rtl = is_layout_rtl(); + Color guide_color = get_theme_color(SNAME("guide_color")); + Color font_color = get_theme_color(SNAME("font_color")); + Color font_selected_color = get_theme_color(SNAME("font_selected_color")); - Color guide_color = get_theme_color(SNAME("guide_color")); - Color font_color = get_theme_color(SNAME("font_color")); - Color font_selected_color = get_theme_color(SNAME("font_selected_color")); + if (has_focus()) { + RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true); + draw_style_box(get_theme_stylebox(SNAME("bg_focus")), Rect2(Point2(), size)); + RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false); + } - if (has_focus()) { - RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true); - draw_style_box(get_theme_stylebox(SNAME("bg_focus")), Rect2(Point2(), size)); - RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false); - } + if (shape_changed) { + float max_column_width = 0.0; - if (shape_changed) { - float max_column_width = 0.0; + //1- compute item minimum sizes + for (int i = 0; i < items.size(); i++) { + Size2 minsize; + if (items[i].icon.is_valid()) { + if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { + minsize = fixed_icon_size * icon_scale; + } else { + minsize = items[i].get_icon_size() * icon_scale; + } - //1- compute item minimum sizes - for (int i = 0; i < items.size(); i++) { - Size2 minsize; - if (items[i].icon.is_valid()) { - if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { - minsize = fixed_icon_size * icon_scale; - } else { - minsize = items[i].get_icon_size() * icon_scale; + if (!items[i].text.is_empty()) { + if (icon_mode == ICON_MODE_TOP) { + minsize.y += icon_margin; + } else { + minsize.x += icon_margin; + } + } } if (!items[i].text.is_empty()) { - if (icon_mode == ICON_MODE_TOP) { - minsize.y += icon_margin; - } else { - minsize.x += icon_margin; + int max_width = -1; + if (fixed_column_width) { + max_width = fixed_column_width; + } else if (same_column_width) { + max_width = items[i].rect_cache.size.x; } - } - } + items.write[i].text_buf->set_width(max_width); + Size2 s = items[i].text_buf->get_size(); - if (!items[i].text.is_empty()) { - int max_width = -1; - if (fixed_column_width) { - max_width = fixed_column_width; - } else if (same_column_width) { - max_width = items[i].rect_cache.size.x; - } - items.write[i].text_buf->set_width(max_width); - Size2 s = items[i].text_buf->get_size(); + if (icon_mode == ICON_MODE_TOP) { + minsize.x = MAX(minsize.x, s.width); + if (max_text_lines > 0) { + minsize.y += s.height + line_separation * max_text_lines; + } else { + minsize.y += s.height; + } - if (icon_mode == ICON_MODE_TOP) { - minsize.x = MAX(minsize.x, s.width); - if (max_text_lines > 0) { - minsize.y += s.height + line_separation * max_text_lines; } else { - minsize.y += s.height; + minsize.y = MAX(minsize.y, s.height); + minsize.x += s.width; } + } - } else { - minsize.y = MAX(minsize.y, s.height); - minsize.x += s.width; + if (fixed_column_width > 0) { + minsize.x = fixed_column_width; } + max_column_width = MAX(max_column_width, minsize.x); + + // elements need to adapt to the selected size + minsize.y += vseparation; + minsize.x += hseparation; + items.write[i].rect_cache.size = minsize; + items.write[i].min_rect_cache.size = minsize; } - if (fixed_column_width > 0) { - minsize.x = fixed_column_width; + int fit_size = size.x - bg->get_minimum_size().width - mw; + + //2-attempt best fit + current_columns = 0x7FFFFFFF; + if (max_columns > 0) { + current_columns = max_columns; } - max_column_width = MAX(max_column_width, minsize.x); - // elements need to adapt to the selected size - minsize.y += vseparation; - minsize.x += hseparation; - items.write[i].rect_cache.size = minsize; - items.write[i].min_rect_cache.size = minsize; - } + while (true) { + //repeat until all fits + bool all_fit = true; + Vector2 ofs; + int col = 0; + int max_h = 0; + separators.clear(); + for (int i = 0; i < items.size(); i++) { + if (current_columns > 1 && items[i].rect_cache.size.width + ofs.x > fit_size) { + //went past + current_columns = MAX(col, 1); + all_fit = false; + break; + } - int fit_size = size.x - bg->get_minimum_size().width - mw; + if (same_column_width) { + items.write[i].rect_cache.size.x = max_column_width; + } + items.write[i].rect_cache.position = ofs; + max_h = MAX(max_h, items[i].rect_cache.size.y); + ofs.x += items[i].rect_cache.size.x + hseparation; + col++; + if (col == current_columns) { + if (i < items.size() - 1) { + separators.push_back(ofs.y + max_h + vseparation / 2); + } - //2-attempt best fit - current_columns = 0x7FFFFFFF; - if (max_columns > 0) { - current_columns = max_columns; - } + for (int j = i; j >= 0 && col > 0; j--, col--) { + items.write[j].rect_cache.size.y = max_h; + } - while (true) { - //repeat until all fits - bool all_fit = true; - Vector2 ofs; - int col = 0; - int max_h = 0; - separators.clear(); - for (int i = 0; i < items.size(); i++) { - if (current_columns > 1 && items[i].rect_cache.size.width + ofs.x > fit_size) { - //went past - current_columns = MAX(col, 1); - all_fit = false; - break; + ofs.x = 0; + ofs.y += max_h + vseparation; + col = 0; + max_h = 0; + } } - if (same_column_width) { - items.write[i].rect_cache.size.x = max_column_width; + for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) { + items.write[j].rect_cache.size.y = max_h; } - items.write[i].rect_cache.position = ofs; - max_h = MAX(max_h, items[i].rect_cache.size.y); - ofs.x += items[i].rect_cache.size.x + hseparation; - col++; - if (col == current_columns) { - if (i < items.size() - 1) { - separators.push_back(ofs.y + max_h + vseparation / 2); - } - for (int j = i; j >= 0 && col > 0; j--, col--) { - items.write[j].rect_cache.size.y = max_h; + if (all_fit) { + float page = MAX(0, size.height - bg->get_minimum_size().height); + float max = MAX(page, ofs.y + max_h); + if (auto_height) { + auto_height_value = ofs.y + max_h + bg->get_minimum_size().height; } + scroll_bar->set_max(max); + scroll_bar->set_page(page); + if (max <= page) { + scroll_bar->set_value(0); + scroll_bar->hide(); + } else { + scroll_bar->show(); - ofs.x = 0; - ofs.y += max_h + vseparation; - col = 0; - max_h = 0; + if (do_autoscroll_to_bottom) { + scroll_bar->set_value(max); + } + } + break; } } - for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) { - items.write[j].rect_cache.size.y = max_h; - } + update_minimum_size(); + shape_changed = false; + } - if (all_fit) { - float page = MAX(0, size.height - bg->get_minimum_size().height); - float max = MAX(page, ofs.y + max_h); - if (auto_height) { - auto_height_value = ofs.y + max_h + bg->get_minimum_size().height; - } - scroll_bar->set_max(max); - scroll_bar->set_page(page); - if (max <= page) { - scroll_bar->set_value(0); - scroll_bar->hide(); - } else { - scroll_bar->show(); + //ensure_selected_visible needs to be checked before we draw the list. + if (ensure_selected_visible && current >= 0 && current < items.size()) { + Rect2 r = items[current].rect_cache; + int from = scroll_bar->get_value(); + int to = from + scroll_bar->get_page(); - if (do_autoscroll_to_bottom) { - scroll_bar->set_value(max); - } - } - break; + if (r.position.y < from) { + scroll_bar->set_value(r.position.y); + } else if (r.position.y + r.size.y > to) { + scroll_bar->set_value(r.position.y + r.size.y - (to - from)); } } - update_minimum_size(); - shape_changed = false; - } + ensure_selected_visible = false; - //ensure_selected_visible needs to be checked before we draw the list. - if (ensure_selected_visible && current >= 0 && current < items.size()) { - Rect2 r = items[current].rect_cache; - int from = scroll_bar->get_value(); - int to = from + scroll_bar->get_page(); - - if (r.position.y < from) { - scroll_bar->set_value(r.position.y); - } else if (r.position.y + r.size.y > to) { - scroll_bar->set_value(r.position.y + r.size.y - (to - from)); - } - } + Vector2 base_ofs = bg->get_offset(); + base_ofs.y -= int(scroll_bar->get_value()); - ensure_selected_visible = false; + const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there - Vector2 base_ofs = bg->get_offset(); - base_ofs.y -= int(scroll_bar->get_value()); - - const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there - - int first_item_visible; - { - // do a binary search to find the first item whose rect reaches below clip.position.y - int lo = 0; - int hi = items.size(); - while (lo < hi) { - const int mid = (lo + hi) / 2; - const Rect2 &rcache = items[mid].rect_cache; - if (rcache.position.y + rcache.size.y < clip.position.y) { - lo = mid + 1; - } else { - hi = mid; + int first_item_visible; + { + // do a binary search to find the first item whose rect reaches below clip.position.y + int lo = 0; + int hi = items.size(); + while (lo < hi) { + const int mid = (lo + hi) / 2; + const Rect2 &rcache = items[mid].rect_cache; + if (rcache.position.y + rcache.size.y < clip.position.y) { + lo = mid + 1; + } else { + hi = mid; + } } + // we might have ended up with column 2, or 3, ..., so let's find the first column + while (lo > 0 && items[lo - 1].rect_cache.position.y == items[lo].rect_cache.position.y) { + lo -= 1; + } + first_item_visible = lo; } - // we might have ended up with column 2, or 3, ..., so let's find the first column - while (lo > 0 && items[lo - 1].rect_cache.position.y == items[lo].rect_cache.position.y) { - lo -= 1; - } - first_item_visible = lo; - } - for (int i = first_item_visible; i < items.size(); i++) { - Rect2 rcache = items[i].rect_cache; + for (int i = first_item_visible; i < items.size(); i++) { + Rect2 rcache = items[i].rect_cache; - if (rcache.position.y > clip.position.y + clip.size.y) { - break; // done - } - - if (!clip.intersects(rcache)) { - continue; - } - - if (current_columns == 1) { - rcache.size.width = width - rcache.position.x; - } + if (rcache.position.y > clip.position.y + clip.size.y) { + break; // done + } - if (items[i].selected) { - Rect2 r = rcache; - r.position += base_ofs; - r.position.y -= vseparation / 2; - r.size.y += vseparation; - r.position.x -= hseparation / 2; - r.size.x += hseparation; - - if (rtl) { - r.position.x = size.width - r.position.x - r.size.x; + if (!clip.intersects(rcache)) { + continue; } - draw_style_box(sbsel, r); - } - if (items[i].custom_bg.a > 0.001) { - Rect2 r = rcache; - r.position += base_ofs; - - // Size rect to make the align the temperature colors - r.position.y -= vseparation / 2; - r.size.y += vseparation; - r.position.x -= hseparation / 2; - r.size.x += hseparation; - - if (rtl) { - r.position.x = size.width - r.position.x - r.size.x; + if (current_columns == 1) { + rcache.size.width = width - rcache.position.x; } - draw_rect(r, items[i].custom_bg); - } + if (items[i].selected) { + Rect2 r = rcache; + r.position += base_ofs; + r.position.y -= vseparation / 2; + r.size.y += vseparation; + r.position.x -= hseparation / 2; + r.size.x += hseparation; - Vector2 text_ofs; - if (items[i].icon.is_valid()) { - Size2 icon_size; - //= _adjust_to_max_size(items[i].get_icon_size(),fixed_icon_size) * icon_scale; + if (rtl) { + r.position.x = size.width - r.position.x - r.size.x; + } - if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { - icon_size = fixed_icon_size * icon_scale; - } else { - icon_size = items[i].get_icon_size() * icon_scale; + draw_style_box(sbsel, r); } + if (items[i].custom_bg.a > 0.001) { + Rect2 r = rcache; + r.position += base_ofs; - Vector2 icon_ofs; + // Size rect to make the align the temperature colors + r.position.y -= vseparation / 2; + r.size.y += vseparation; + r.position.x -= hseparation / 2; + r.size.x += hseparation; - Point2 pos = items[i].rect_cache.position + icon_ofs + base_ofs; + if (rtl) { + r.position.x = size.width - r.position.x - r.size.x; + } - if (icon_mode == ICON_MODE_TOP) { - pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2); - pos.y += icon_margin; - text_ofs.y = icon_size.height + icon_margin * 2; - } else { - pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2); - text_ofs.x = icon_size.width + icon_margin; + draw_rect(r, items[i].custom_bg); } - Rect2 draw_rect = Rect2(pos, icon_size); + Vector2 text_ofs; + if (items[i].icon.is_valid()) { + Size2 icon_size; + //= _adjust_to_max_size(items[i].get_icon_size(),fixed_icon_size) * icon_scale; - if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { - Rect2 adj = _adjust_to_max_size(items[i].get_icon_size() * icon_scale, icon_size); - draw_rect.position += adj.position; - draw_rect.size = adj.size; - } + if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { + icon_size = fixed_icon_size * icon_scale; + } else { + icon_size = items[i].get_icon_size() * icon_scale; + } - Color modulate = items[i].icon_modulate; - if (items[i].disabled) { - modulate.a *= 0.5; - } + Vector2 icon_ofs; - // If the icon is transposed, we have to switch the size so that it is drawn correctly - if (items[i].icon_transposed) { - Size2 size_tmp = draw_rect.size; - draw_rect.size.x = size_tmp.y; - draw_rect.size.y = size_tmp.x; - } + Point2 pos = items[i].rect_cache.position + icon_ofs + base_ofs; - Rect2 region = (items[i].icon_region.size.x == 0 || items[i].icon_region.size.y == 0) ? Rect2(Vector2(), items[i].icon->get_size()) : Rect2(items[i].icon_region); + if (icon_mode == ICON_MODE_TOP) { + pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2); + pos.y += icon_margin; + text_ofs.y = icon_size.height + icon_margin * 2; + } else { + pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2); + text_ofs.x = icon_size.width + icon_margin; + } - if (rtl) { - draw_rect.position.x = size.width - draw_rect.position.x - draw_rect.size.x; - } - draw_texture_rect_region(items[i].icon, draw_rect, region, modulate, items[i].icon_transposed); - } + Rect2 draw_rect = Rect2(pos, icon_size); - if (items[i].tag_icon.is_valid()) { - Point2 draw_pos = items[i].rect_cache.position; - if (rtl) { - draw_pos.x = size.width - draw_pos.x - items[i].tag_icon->get_width(); - } - draw_texture(items[i].tag_icon, draw_pos + base_ofs); - } + if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) { + Rect2 adj = _adjust_to_max_size(items[i].get_icon_size() * icon_scale, icon_size); + draw_rect.position += adj.position; + draw_rect.size = adj.size; + } - if (!items[i].text.is_empty()) { - int max_len = -1; + Color modulate = items[i].icon_modulate; + if (items[i].disabled) { + modulate.a *= 0.5; + } - Vector2 size2 = items[i].text_buf->get_size(); - if (fixed_column_width) { - max_len = fixed_column_width; - } else if (same_column_width) { - max_len = items[i].rect_cache.size.x; - } else { - max_len = size2.x; - } + // If the icon is transposed, we have to switch the size so that it is drawn correctly + if (items[i].icon_transposed) { + Size2 size_tmp = draw_rect.size; + draw_rect.size.x = size_tmp.y; + draw_rect.size.y = size_tmp.x; + } - Color modulate = items[i].selected ? font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color); - if (items[i].disabled) { - modulate.a *= 0.5; - } + Rect2 region = (items[i].icon_region.size.x == 0 || items[i].icon_region.size.y == 0) ? Rect2(Vector2(), items[i].icon->get_size()) : Rect2(items[i].icon_region); - if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { - text_ofs += base_ofs; - text_ofs += items[i].rect_cache.position; + if (rtl) { + draw_rect.position.x = size.width - draw_rect.position.x - draw_rect.size.x; + } + draw_texture_rect_region(items[i].icon, draw_rect, region, modulate, items[i].icon_transposed); + } + if (items[i].tag_icon.is_valid()) { + Point2 draw_pos = items[i].rect_cache.position; if (rtl) { - text_ofs.x = size.width - text_ofs.x - max_len; + draw_pos.x = size.width - draw_pos.x - items[i].tag_icon->get_width(); } + draw_texture(items[i].tag_icon, draw_pos + base_ofs); + } - items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_CENTER); + if (!items[i].text.is_empty()) { + int max_len = -1; - if (outline_size > 0 && font_outline_color.a > 0) { - items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color); + Vector2 size2 = items[i].text_buf->get_size(); + if (fixed_column_width) { + max_len = fixed_column_width; + } else if (same_column_width) { + max_len = items[i].rect_cache.size.x; + } else { + max_len = size2.x; } - items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate); - } else { - if (fixed_column_width > 0) { - size2.x = MIN(size2.x, fixed_column_width); + Color modulate = items[i].selected ? font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color); + if (items[i].disabled) { + modulate.a *= 0.5; } - if (icon_mode == ICON_MODE_TOP) { - text_ofs.x += (items[i].rect_cache.size.width - size2.x) / 2; - } else { - text_ofs.y += (items[i].rect_cache.size.height - size2.y) / 2; - } + if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { + text_ofs += base_ofs; + text_ofs += items[i].rect_cache.position; - text_ofs += base_ofs; - text_ofs += items[i].rect_cache.position; + if (rtl) { + text_ofs.x = size.width - text_ofs.x - max_len; + } - if (rtl) { - text_ofs.x = size.width - text_ofs.x - max_len; - } + items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_CENTER); - items.write[i].text_buf->set_width(max_len); + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color); + } - if (rtl) { - items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate); } else { - items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_LEFT); + if (fixed_column_width > 0) { + size2.x = MIN(size2.x, fixed_column_width); + } + + if (icon_mode == ICON_MODE_TOP) { + text_ofs.x += (items[i].rect_cache.size.width - size2.x) / 2; + } else { + text_ofs.y += (items[i].rect_cache.size.height - size2.y) / 2; + } + + text_ofs += base_ofs; + text_ofs += items[i].rect_cache.position; + + if (rtl) { + text_ofs.x = size.width - text_ofs.x - max_len; + } + + items.write[i].text_buf->set_width(width - text_ofs.x); + + if (rtl) { + items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_RIGHT); + } else { + items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_LEFT); + } + + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color); + } + + if (width - text_ofs.x > 0) { + items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate); + } } + } - if (outline_size > 0 && font_outline_color.a > 0) { - items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color); + if (select_mode == SELECT_MULTI && i == current) { + Rect2 r = rcache; + r.position += base_ofs; + r.position.y -= vseparation / 2; + r.size.y += vseparation; + r.position.x -= hseparation / 2; + r.size.x += hseparation; + + if (rtl) { + r.position.x = size.width - r.position.x - r.size.x; } - items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate); + draw_style_box(cursor, r); } } - if (select_mode == SELECT_MULTI && i == current) { - Rect2 r = rcache; - r.position += base_ofs; - r.position.y -= vseparation / 2; - r.size.y += vseparation; - r.position.x -= hseparation / 2; - r.size.x += hseparation; - - if (rtl) { - r.position.x = size.width - r.position.x - r.size.x; + int first_visible_separator = 0; + { + // do a binary search to find the first separator that is below clip_position.y + int lo = 0; + int hi = separators.size(); + while (lo < hi) { + const int mid = (lo + hi) / 2; + if (separators[mid] < clip.position.y) { + lo = mid + 1; + } else { + hi = mid; + } } - - draw_style_box(cursor, r); + first_visible_separator = lo; } - } - int first_visible_separator = 0; - { - // do a binary search to find the first separator that is below clip_position.y - int lo = 0; - int hi = separators.size(); - while (lo < hi) { - const int mid = (lo + hi) / 2; - if (separators[mid] < clip.position.y) { - lo = mid + 1; - } else { - hi = mid; + for (int i = first_visible_separator; i < separators.size(); i++) { + if (separators[i] > clip.position.y + clip.size.y) { + break; // done } - } - first_visible_separator = lo; - } - for (int i = first_visible_separator; i < separators.size(); i++) { - if (separators[i] > clip.position.y + clip.size.y) { - break; // done + const int y = base_ofs.y + separators[i]; + draw_line(Vector2(bg->get_margin(SIDE_LEFT), y), Vector2(width, y), guide_color); } - - const int y = base_ofs.y + separators[i]; - draw_line(Vector2(bg->get_margin(SIDE_LEFT), y), Vector2(width, y), guide_color); - } + } break; } } diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 77e910870f..96735678c1 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -99,7 +99,7 @@ private: SelectMode select_mode = SELECT_SINGLE; IconMode icon_mode = ICON_MODE_LEFT; VScrollBar *scroll_bar; - TextParagraph::OverrunBehavior text_overrun_behavior = TextParagraph::OVERRUN_NO_TRIMMING; + TextParagraph::OverrunBehavior text_overrun_behavior = TextParagraph::OVERRUN_TRIM_ELLIPSIS; uint64_t search_time_msec = 0; String search_string; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 7a24c76ff8..419901d5ea 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -263,168 +263,227 @@ inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Col } void Label::_notification(int p_what) { - if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { - String new_text = atr(text); - if (new_text == xl_text) { - return; // Nothing new. - } - xl_text = new_text; - if (percent_visible < 1) { - visible_chars = get_total_character_count() * percent_visible; - } - dirty = true; + switch (p_what) { + case NOTIFICATION_TRANSLATION_CHANGED: { + String new_text = atr(text); + if (new_text == xl_text) { + return; // Nothing new. + } + xl_text = new_text; + if (percent_visible < 1) { + visible_chars = get_total_character_count() * percent_visible; + } + dirty = true; - update(); - } + update(); + } break; - if (p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED) { - update(); - } + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { + update(); + } break; - if (p_what == NOTIFICATION_DRAW) { - if (clip) { - RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); - } + case NOTIFICATION_DRAW: { + if (clip) { + RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); + } - if (dirty || font_dirty || lines_dirty) { - _shape(); - } + if (dirty || font_dirty || lines_dirty) { + _shape(); + } - RID ci = get_canvas_item(); - - Size2 string_size; - Size2 size = get_size(); - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - Ref<Font> font = get_theme_font(SNAME("font")); - Color font_color = get_theme_color(SNAME("font_color")); - Color font_shadow_color = get_theme_color(SNAME("font_shadow_color")); - Point2 shadow_ofs(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y"))); - int line_spacing = get_theme_constant(SNAME("line_spacing")); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); - int shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size")); - bool rtl = (TS->shaped_text_get_inferred_direction(text_rid) == TextServer::DIRECTION_RTL); - bool rtl_layout = is_layout_rtl(); - - style->draw(ci, Rect2(Point2(0, 0), get_size())); - - float total_h = 0.0; - int lines_visible = 0; - - // Get number of lines to fit to the height. - for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; - if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) { - break; + RID ci = get_canvas_item(); + + Size2 string_size; + Size2 size = get_size(); + Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<Font> font = get_theme_font(SNAME("font")); + Color font_color = get_theme_color(SNAME("font_color")); + Color font_shadow_color = get_theme_color(SNAME("font_shadow_color")); + Point2 shadow_ofs(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y"))); + int line_spacing = get_theme_constant(SNAME("line_spacing")); + Color font_outline_color = get_theme_color(SNAME("font_outline_color")); + int outline_size = get_theme_constant(SNAME("outline_size")); + int shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size")); + bool rtl = (TS->shaped_text_get_inferred_direction(text_rid) == TextServer::DIRECTION_RTL); + bool rtl_layout = is_layout_rtl(); + + style->draw(ci, Rect2(Point2(0, 0), get_size())); + + float total_h = 0.0; + int lines_visible = 0; + + // Get number of lines to fit to the height. + for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; + if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) { + break; + } + lines_visible++; } - lines_visible++; - } - if (max_lines_visible >= 0 && lines_visible > max_lines_visible) { - lines_visible = max_lines_visible; - } + if (max_lines_visible >= 0 && lines_visible > max_lines_visible) { + lines_visible = max_lines_visible; + } - int last_line = MIN(lines_rid.size(), lines_visible + lines_skipped); - bool trim_chars = (visible_chars >= 0) && (visible_chars_behavior == VC_CHARS_AFTER_SHAPING); - bool trim_glyphs_ltr = (visible_chars >= 0) && ((visible_chars_behavior == VC_GLYPHS_LTR) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && !rtl_layout)); - bool trim_glyphs_rtl = (visible_chars >= 0) && ((visible_chars_behavior == VC_GLYPHS_RTL) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && rtl_layout)); - - // Get real total height. - int total_glyphs = 0; - total_h = 0; - for (int64_t i = lines_skipped; i < last_line; i++) { - total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; - total_glyphs += TS->shaped_text_get_glyph_count(lines_rid[i]) + TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]); - } - int visible_glyphs = total_glyphs * percent_visible; - int processed_glyphs = 0; - total_h += style->get_margin(SIDE_TOP) + style->get_margin(SIDE_BOTTOM); - - int vbegin = 0, vsep = 0; - if (lines_visible > 0) { - switch (vertical_alignment) { - case VERTICAL_ALIGNMENT_TOP: { - // Nothing. - } break; - case VERTICAL_ALIGNMENT_CENTER: { - vbegin = (size.y - (total_h - line_spacing)) / 2; - vsep = 0; - - } break; - case VERTICAL_ALIGNMENT_BOTTOM: { - vbegin = size.y - (total_h - line_spacing); - vsep = 0; - - } break; - case VERTICAL_ALIGNMENT_FILL: { - vbegin = 0; - if (lines_visible > 1) { - vsep = (size.y - (total_h - line_spacing)) / (lines_visible - 1); - } else { + int last_line = MIN(lines_rid.size(), lines_visible + lines_skipped); + bool trim_chars = (visible_chars >= 0) && (visible_chars_behavior == VC_CHARS_AFTER_SHAPING); + bool trim_glyphs_ltr = (visible_chars >= 0) && ((visible_chars_behavior == VC_GLYPHS_LTR) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && !rtl_layout)); + bool trim_glyphs_rtl = (visible_chars >= 0) && ((visible_chars_behavior == VC_GLYPHS_RTL) || ((visible_chars_behavior == VC_GLYPHS_AUTO) && rtl_layout)); + + // Get real total height. + int total_glyphs = 0; + total_h = 0; + for (int64_t i = lines_skipped; i < last_line; i++) { + total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM) + line_spacing; + total_glyphs += TS->shaped_text_get_glyph_count(lines_rid[i]) + TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]); + } + int visible_glyphs = total_glyphs * percent_visible; + int processed_glyphs = 0; + total_h += style->get_margin(SIDE_TOP) + style->get_margin(SIDE_BOTTOM); + + int vbegin = 0, vsep = 0; + if (lines_visible > 0) { + switch (vertical_alignment) { + case VERTICAL_ALIGNMENT_TOP: { + // Nothing. + } break; + case VERTICAL_ALIGNMENT_CENTER: { + vbegin = (size.y - (total_h - line_spacing)) / 2; vsep = 0; - } - } break; + } break; + case VERTICAL_ALIGNMENT_BOTTOM: { + vbegin = size.y - (total_h - line_spacing); + vsep = 0; + + } break; + case VERTICAL_ALIGNMENT_FILL: { + vbegin = 0; + if (lines_visible > 1) { + vsep = (size.y - (total_h - line_spacing)) / (lines_visible - 1); + } else { + vsep = 0; + } + + } break; + } } - } - Vector2 ofs; - ofs.y = style->get_offset().y + vbegin; - for (int i = lines_skipped; i < last_line; i++) { - Size2 line_size = TS->shaped_text_get_size(lines_rid[i]); - ofs.x = 0; - ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(TextServer::SPACING_TOP); - switch (horizontal_alignment) { - case HORIZONTAL_ALIGNMENT_FILL: - if (rtl && autowrap_mode != AUTOWRAP_OFF) { - ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width); - } else { - ofs.x = style->get_offset().x; - } - break; - case HORIZONTAL_ALIGNMENT_LEFT: { - if (rtl_layout) { - ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width); - } else { - ofs.x = style->get_offset().x; - } - } break; - case HORIZONTAL_ALIGNMENT_CENTER: { - ofs.x = int(size.width - line_size.width) / 2; - } break; - case HORIZONTAL_ALIGNMENT_RIGHT: { - if (rtl_layout) { - ofs.x = style->get_offset().x; - } else { - ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width); + Vector2 ofs; + ofs.y = style->get_offset().y + vbegin; + for (int i = lines_skipped; i < last_line; i++) { + Size2 line_size = TS->shaped_text_get_size(lines_rid[i]); + ofs.x = 0; + ofs.y += TS->shaped_text_get_ascent(lines_rid[i]) + font->get_spacing(TextServer::SPACING_TOP); + switch (horizontal_alignment) { + case HORIZONTAL_ALIGNMENT_FILL: + if (rtl && autowrap_mode != AUTOWRAP_OFF) { + ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width); + } else { + ofs.x = style->get_offset().x; + } + break; + case HORIZONTAL_ALIGNMENT_LEFT: { + if (rtl_layout) { + ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width); + } else { + ofs.x = style->get_offset().x; + } + } break; + case HORIZONTAL_ALIGNMENT_CENTER: { + ofs.x = int(size.width - line_size.width) / 2; + } break; + case HORIZONTAL_ALIGNMENT_RIGHT: { + if (rtl_layout) { + ofs.x = style->get_offset().x; + } else { + ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - line_size.width); + } + } break; + } + + const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]); + int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]); + + int ellipsis_pos = TS->shaped_text_get_ellipsis_pos(lines_rid[i]); + int trim_pos = TS->shaped_text_get_trim_pos(lines_rid[i]); + + const Glyph *ellipsis_glyphs = TS->shaped_text_get_ellipsis_glyphs(lines_rid[i]); + int ellipsis_gl_size = TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]); + + // Draw outline. Note: Do not merge this into the single loop with the main text, to prevent overlaps. + int processed_glyphs_ol = processed_glyphs; + if ((outline_size > 0 && font_outline_color.a != 0) || (font_shadow_color.a != 0)) { + Vector2 offset = ofs; + // Draw RTL ellipsis string when necessary. + if (rtl && ellipsis_pos >= 0) { + for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) { + for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { + bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs)); + //Draw glyph outlines and shadow. + if (!skip) { + draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs); + } + processed_glyphs_ol++; + offset.x += ellipsis_glyphs[gl_idx].advance; + } + } } - } break; - } - const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]); - int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]); + // Draw main text. + for (int j = 0; j < gl_size; j++) { + // Trim when necessary. + if (trim_pos >= 0) { + if (rtl) { + if (j < trim_pos) { + continue; + } + } else { + if (j >= trim_pos) { + break; + } + } + } + for (int k = 0; k < glyphs[j].repeat; k++) { + bool skip = (trim_chars && glyphs[j].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs)); - int ellipsis_pos = TS->shaped_text_get_ellipsis_pos(lines_rid[i]); - int trim_pos = TS->shaped_text_get_trim_pos(lines_rid[i]); + // Draw glyph outlines and shadow. + if (!skip) { + draw_glyph_outline(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs); + } + processed_glyphs_ol++; + offset.x += glyphs[j].advance; + } + } + // Draw LTR ellipsis string when necessary. + if (!rtl && ellipsis_pos >= 0) { + for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) { + for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { + bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs)); + //Draw glyph outlines and shadow. + if (!skip) { + draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs); + } + processed_glyphs_ol++; + offset.x += ellipsis_glyphs[gl_idx].advance; + } + } + } + } - const Glyph *ellipsis_glyphs = TS->shaped_text_get_ellipsis_glyphs(lines_rid[i]); - int ellipsis_gl_size = TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]); + // Draw main text. Note: Do not merge this into the single loop with the outline, to prevent overlaps. - // Draw outline. Note: Do not merge this into the single loop with the main text, to prevent overlaps. - int processed_glyphs_ol = processed_glyphs; - if ((outline_size > 0 && font_outline_color.a != 0) || (font_shadow_color.a != 0)) { - Vector2 offset = ofs; // Draw RTL ellipsis string when necessary. if (rtl && ellipsis_pos >= 0) { for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) { for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { - bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs)); + bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs)); //Draw glyph outlines and shadow. if (!skip) { - draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs); + draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs); } - processed_glyphs_ol++; - offset.x += ellipsis_glyphs[gl_idx].advance; + processed_glyphs++; + ofs.x += ellipsis_glyphs[gl_idx].advance; } } } @@ -444,98 +503,42 @@ void Label::_notification(int p_what) { } } for (int k = 0; k < glyphs[j].repeat; k++) { - bool skip = (trim_chars && glyphs[j].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs)); + bool skip = (trim_chars && glyphs[j].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs)); // Draw glyph outlines and shadow. if (!skip) { - draw_glyph_outline(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs); + draw_glyph(glyphs[j], ci, font_color, ofs); } - processed_glyphs_ol++; - offset.x += glyphs[j].advance; + processed_glyphs++; + ofs.x += glyphs[j].advance; } } // Draw LTR ellipsis string when necessary. if (!rtl && ellipsis_pos >= 0) { for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) { for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { - bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs_ol >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs_ol < total_glyphs - visible_glyphs)); + bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs)); //Draw glyph outlines and shadow. if (!skip) { - draw_glyph_outline(ellipsis_glyphs[gl_idx], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs); + draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs); } - processed_glyphs_ol++; - offset.x += ellipsis_glyphs[gl_idx].advance; + processed_glyphs++; + ofs.x += ellipsis_glyphs[gl_idx].advance; } } } + ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing + font->get_spacing(TextServer::SPACING_BOTTOM); } + } break; - // Draw main text. Note: Do not merge this into the single loop with the outline, to prevent overlaps. - - // Draw RTL ellipsis string when necessary. - if (rtl && ellipsis_pos >= 0) { - for (int gl_idx = ellipsis_gl_size - 1; gl_idx >= 0; gl_idx--) { - for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { - bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs)); - //Draw glyph outlines and shadow. - if (!skip) { - draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs); - } - processed_glyphs++; - ofs.x += ellipsis_glyphs[gl_idx].advance; - } - } - } + case NOTIFICATION_THEME_CHANGED: { + font_dirty = true; + update(); + } break; - // Draw main text. - for (int j = 0; j < gl_size; j++) { - // Trim when necessary. - if (trim_pos >= 0) { - if (rtl) { - if (j < trim_pos) { - continue; - } - } else { - if (j >= trim_pos) { - break; - } - } - } - for (int k = 0; k < glyphs[j].repeat; k++) { - bool skip = (trim_chars && glyphs[j].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs)); - - // Draw glyph outlines and shadow. - if (!skip) { - draw_glyph(glyphs[j], ci, font_color, ofs); - } - processed_glyphs++; - ofs.x += glyphs[j].advance; - } - } - // Draw LTR ellipsis string when necessary. - if (!rtl && ellipsis_pos >= 0) { - for (int gl_idx = 0; gl_idx < ellipsis_gl_size; gl_idx++) { - for (int j = 0; j < ellipsis_glyphs[gl_idx].repeat; j++) { - bool skip = (trim_chars && ellipsis_glyphs[gl_idx].end > visible_chars) || (trim_glyphs_ltr && (processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (processed_glyphs < total_glyphs - visible_glyphs)); - //Draw glyph outlines and shadow. - if (!skip) { - draw_glyph(ellipsis_glyphs[gl_idx], ci, font_color, ofs); - } - processed_glyphs++; - ofs.x += ellipsis_glyphs[gl_idx].advance; - } - } - } - ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing + font->get_spacing(TextServer::SPACING_BOTTOM); - } - } - - if (p_what == NOTIFICATION_THEME_CHANGED) { - font_dirty = true; - update(); - } - if (p_what == NOTIFICATION_RESIZED) { - lines_dirty = true; + case NOTIFICATION_RESIZED: { + lines_dirty = true; + } break; } } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 3aae3377bc..da39a3d387 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -647,8 +647,8 @@ void LineEdit::_notification(int p_what) { #ifdef TOOLS_ENABLED case NOTIFICATION_ENTER_TREE: { if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) { - set_caret_blink_enabled(EDITOR_DEF("text_editor/appearance/caret/caret_blink", false)); - set_caret_blink_speed(EDITOR_DEF("text_editor/appearance/caret/caret_blink_speed", 0.65)); + set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink")); + set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed")); if (!EditorSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed))) { EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed)); @@ -656,31 +656,37 @@ void LineEdit::_notification(int p_what) { } } break; #endif + case NOTIFICATION_RESIZED: { _fit_to_width(); scroll_offset = 0; set_caret_column(get_caret_column()); } break; + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_THEME_CHANGED: { _shape(); update(); } break; + case NOTIFICATION_TRANSLATION_CHANGED: { placeholder_translated = atr(placeholder); _shape(); update(); } break; + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { window_has_focus = true; draw_caret = true; update(); } break; + case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { window_has_focus = false; draw_caret = false; update(); } break; + case NOTIFICATION_DRAW: { if ((!has_focus() && !(menu && menu->has_focus()) && !caret_force_displayed) || !window_has_focus) { draw_caret = false; @@ -841,7 +847,8 @@ void LineEdit::_notification(int p_what) { // Draw carets. ofs.x = x_ofs + scroll_offset; if (draw_caret || drag_caret_force_displayed) { - const int caret_width = get_theme_constant(SNAME("caret_width")) * get_theme_default_base_scale(); + // Prevent carets from disappearing at theme scales below 1.0 (if the caret width is 1). + const int caret_width = get_theme_constant(SNAME("caret_width")) * MAX(1, get_theme_default_base_scale()); if (ime_text.length() == 0) { // Normal caret. @@ -923,6 +930,7 @@ void LineEdit::_notification(int p_what) { } } } break; + case NOTIFICATION_FOCUS_ENTER: { if (!caret_force_displayed) { if (caret_blink_enabled) { @@ -942,6 +950,7 @@ void LineEdit::_notification(int p_what) { show_virtual_keyboard(); } break; + case NOTIFICATION_FOCUS_EXIT: { if (caret_blink_enabled && !caret_force_displayed) { caret_blink_timer->stop(); @@ -964,6 +973,7 @@ void LineEdit::_notification(int p_what) { deselect(); } } break; + case MainLoop::NOTIFICATION_OS_IME_UPDATE: { if (has_focus()) { ime_text = DisplayServer::get_singleton()->ime_get_text(); @@ -974,10 +984,12 @@ void LineEdit::_notification(int p_what) { update(); } } break; - case Control::NOTIFICATION_DRAG_BEGIN: { + + case NOTIFICATION_DRAG_BEGIN: { drag_action = true; } break; - case Control::NOTIFICATION_DRAG_END: { + + case NOTIFICATION_DRAG_END: { if (is_drag_successful()) { if (selection.drag_attempt) { selection.drag_attempt = false; @@ -1606,7 +1618,7 @@ Size2 LineEdit::get_minimum_size() const { Size2 min_size; // Minimum size of text. - int em_space_size = font->get_char_size('M', 0, font_size).x; + float em_space_size = font->get_char_size('M', 0, font_size).x; min_size.width = get_theme_constant(SNAME("minimum_character_width")) * em_space_size; if (expand_to_text_length) { @@ -1932,8 +1944,8 @@ PopupMenu *LineEdit::get_menu() const { void LineEdit::_editor_settings_changed() { #ifdef TOOLS_ENABLED - set_caret_blink_enabled(EDITOR_DEF("text_editor/appearance/caret/caret_blink", false)); - set_caret_blink_speed(EDITOR_DEF("text_editor/appearance/caret/caret_blink_speed", 0.65)); + set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink")); + set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed")); #endif } @@ -2425,7 +2437,7 @@ void LineEdit::_ensure_menu() { } } -LineEdit::LineEdit() { +LineEdit::LineEdit(const String &p_placeholder) { text_rid = TS->create_shaped_text(); _create_undo_state(); @@ -2440,6 +2452,8 @@ LineEdit::LineEdit() { caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret)); set_caret_blink_enabled(false); + set_placeholder(p_placeholder); + set_editable(true); // Initialise to opposite first, so we get past the early-out in set_editable. } diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index 1519c09d73..444c9a1c50 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -332,7 +332,7 @@ public: void show_virtual_keyboard(); - LineEdit(); + LineEdit(const String &p_placeholder = String()); ~LineEdit(); }; diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index 0ff05faf85..dc4f09d22d 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "link_button.h" + #include "core/string/translation.h" void LinkButton::_shape() { @@ -148,18 +149,20 @@ void LinkButton::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { xl_text = atr(text); _shape(); - update_minimum_size(); update(); } break; + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { update(); } break; + case NOTIFICATION_THEME_CHANGED: { _shape(); update_minimum_size(); update(); } break; + case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); Size2 size = get_size(); @@ -230,7 +233,6 @@ void LinkButton::_notification(int p_what) { draw_line(Vector2(0, y), Vector2(width, y), color, text_buf->get_line_underline_thickness()); } } - } break; } } @@ -315,8 +317,10 @@ void LinkButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options"); } -LinkButton::LinkButton() { +LinkButton::LinkButton(const String &p_text) { text_buf.instantiate(); set_focus_mode(FOCUS_NONE); set_default_cursor_shape(CURSOR_POINTING_HAND); + + set_text(p_text); } diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index a455e866b1..f996558f32 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -90,7 +90,7 @@ public: void set_underline_mode(UnderlineMode p_underline_mode); UnderlineMode get_underline_mode() const; - LinkButton(); + LinkButton(const String &p_text = String()); }; VARIANT_ENUM_CAST(LinkButton::UnderlineMode); diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index 89008a19c5..fac37a8634 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -107,6 +107,7 @@ void MarginContainer::_notification(int p_what) { fit_child_in_rect(c, Rect2(margin_left, margin_top, w, h)); } } break; + case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); } break; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 94fa5d81d8..7e724e4d71 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -36,7 +36,7 @@ void MenuButton::unhandled_key_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shorcut_context()) { + if (!_is_focus_owner_in_shortcut_context()) { return; } @@ -139,11 +139,13 @@ void MenuButton::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { popup->set_layout_direction((Window::LayoutDirection)get_layout_direction()); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible_in_tree()) { popup->hide(); } } break; + case NOTIFICATION_INTERNAL_PROCESS: { Vector2i mouse_pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted; MenuButton *menu_btn_other = Object::cast_to<MenuButton>(get_viewport()->gui_find_control(mouse_pos)); @@ -225,7 +227,8 @@ void MenuButton::set_disable_shortcuts(bool p_disabled) { disable_shortcuts = p_disabled; } -MenuButton::MenuButton() { +MenuButton::MenuButton(const String &p_text) : + Button(p_text) { set_flat(true); set_toggle_mode(true); set_disable_shortcuts(false); diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 3647a69d33..9cfb780255 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -67,7 +67,7 @@ public: void set_item_count(int p_count); int get_item_count() const; - MenuButton(); + MenuButton(const String &p_text = String()); ~MenuButton(); }; diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp index 779d1307f5..4f34ece86f 100644 --- a/scene/gui/nine_patch_rect.cpp +++ b/scene/gui/nine_patch_rect.cpp @@ -34,18 +34,20 @@ #include "servers/rendering_server.h" void NinePatchRect::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - if (texture.is_null()) { - return; - } + switch (p_what) { + case NOTIFICATION_DRAW: { + if (texture.is_null()) { + return; + } - Rect2 rect = Rect2(Point2(), get_size()); - Rect2 src_rect = region_rect; + Rect2 rect = Rect2(Point2(), get_size()); + Rect2 src_rect = region_rect; - texture->get_rect_region(rect, src_rect, rect, src_rect); + texture->get_rect_region(rect, src_rect, rect, src_rect); - RID ci = get_canvas_item(); - RS::get_singleton()->canvas_item_add_nine_patch(ci, rect, src_rect, texture->get_rid(), Vector2(margin[SIDE_LEFT], margin[SIDE_TOP]), Vector2(margin[SIDE_RIGHT], margin[SIDE_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center); + RID ci = get_canvas_item(); + RS::get_singleton()->canvas_item_add_nine_patch(ci, rect, src_rect, texture->get_rid(), Vector2(margin[SIDE_LEFT], margin[SIDE_TOP]), Vector2(margin[SIDE_RIGHT], margin[SIDE_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center); + } break; } } @@ -93,10 +95,6 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) { } texture = p_tex; update(); - /* - if (texture.is_valid()) - texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites - */ update_minimum_size(); emit_signal(SceneStringNames::get_singleton()->texture_changed); } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index ad2434cd8b..b3804e73d9 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -91,6 +91,7 @@ void OptionButton::_notification(int p_what) { } arrow->draw(ci, ofs, clr); } break; + case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { popup->set_layout_direction((Window::LayoutDirection)get_layout_direction()); @@ -107,6 +108,7 @@ void OptionButton::_notification(int p_what) { } } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible_in_tree()) { popup->hide(); @@ -410,7 +412,8 @@ void OptionButton::_bind_methods() { ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index"))); } -OptionButton::OptionButton() { +OptionButton::OptionButton(const String &p_text) : + Button(p_text) { set_toggle_mode(true); set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); if (is_layout_rtl()) { diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index adf2bb90ef..5352fe18a6 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -94,7 +94,7 @@ public: virtual void get_translatable_strings(List<String> *p_strings) const override; - OptionButton(); + OptionButton(const String &p_text = String()); ~OptionButton(); }; diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp index c88e4ae2f2..1ac6cf57ab 100644 --- a/scene/gui/panel.cpp +++ b/scene/gui/panel.cpp @@ -31,10 +31,12 @@ #include "panel.h" void Panel::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - RID ci = get_canvas_item(); - Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); - style->draw(ci, Rect2(Point2(), get_size())); + switch (p_what) { + case NOTIFICATION_DRAW: { + RID ci = get_canvas_item(); + Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); + style->draw(ci, Rect2(Point2(), get_size())); + } break; } } diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index 91a343084b..fe01712a89 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -79,46 +79,48 @@ Vector<int> PanelContainer::get_allowed_size_flags_vertical() const { } void PanelContainer::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - RID ci = get_canvas_item(); - Ref<StyleBox> style; - - if (has_theme_stylebox(SNAME("panel"))) { - style = get_theme_stylebox(SNAME("panel")); - } else { - style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer")); - } - - style->draw(ci, Rect2(Point2(), get_size())); - } + switch (p_what) { + case NOTIFICATION_DRAW: { + RID ci = get_canvas_item(); + Ref<StyleBox> style; + + if (has_theme_stylebox(SNAME("panel"))) { + style = get_theme_stylebox(SNAME("panel")); + } else { + style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer")); + } - if (p_what == NOTIFICATION_SORT_CHILDREN) { - Ref<StyleBox> style; + style->draw(ci, Rect2(Point2(), get_size())); + } break; - if (has_theme_stylebox(SNAME("panel"))) { - style = get_theme_stylebox(SNAME("panel")); - } else { - style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer")); - } + case NOTIFICATION_SORT_CHILDREN: { + Ref<StyleBox> style; - Size2 size = get_size(); - Point2 ofs; - if (style.is_valid()) { - size -= style->get_minimum_size(); - ofs += style->get_offset(); - } - - for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to<Control>(get_child(i)); - if (!c || !c->is_visible_in_tree()) { - continue; + if (has_theme_stylebox(SNAME("panel"))) { + style = get_theme_stylebox(SNAME("panel")); + } else { + style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer")); } - if (c->is_set_as_top_level()) { - continue; + + Size2 size = get_size(); + Point2 ofs; + if (style.is_valid()) { + size -= style->get_minimum_size(); + ofs += style->get_offset(); } - fit_child_in_rect(c, Rect2(ofs, size)); - } + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c || !c->is_visible_in_tree()) { + continue; + } + if (c->is_set_as_top_level()) { + continue; + } + + fit_child_in_rect(c, Rect2(ofs, size)); + } + } break; } } diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 7c03fcbb37..b9e3e7814e 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -42,26 +42,30 @@ void Popup::_input_from_window(const Ref<InputEvent> &p_event) { } void Popup::_initialize_visible_parents() { - visible_parents.clear(); - - Window *parent_window = this; - while (parent_window) { - parent_window = parent_window->get_parent_visible_window(); - if (parent_window) { - visible_parents.push_back(parent_window); - parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + if (is_embedded()) { + visible_parents.clear(); + + Window *parent_window = this; + while (parent_window) { + parent_window = parent_window->get_parent_visible_window(); + if (parent_window) { + visible_parents.push_back(parent_window); + parent_window->connect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + parent_window->connect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + } } } } void Popup::_deinitialize_visible_parents() { - for (uint32_t i = 0; i < visible_parents.size(); ++i) { - visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); - visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); - } + if (is_embedded()) { + for (uint32_t i = 0; i < visible_parents.size(); ++i) { + visible_parents[i]->disconnect("focus_entered", callable_mp(this, &Popup::_parent_focused)); + visible_parents[i]->disconnect("tree_exited", callable_mp(this, &Popup::_deinitialize_visible_parents)); + } - visible_parents.clear(); + visible_parents.clear(); + } } void Popup::_notification(int p_what) { @@ -74,19 +78,19 @@ void Popup::_notification(int p_what) { emit_signal(SNAME("popup_hide")); popped_up = false; } - } break; + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { if (has_focus()) { popped_up = true; } } break; + case NOTIFICATION_EXIT_TREE: { _deinitialize_visible_parents(); } break; - case NOTIFICATION_WM_CLOSE_REQUEST: { - _close_pressed(); - } break; + + case NOTIFICATION_WM_CLOSE_REQUEST: case NOTIFICATION_APPLICATION_FOCUS_OUT: { _close_pressed(); } break; @@ -94,7 +98,7 @@ void Popup::_notification(int p_what) { } void Popup::_parent_focused() { - if (popped_up && close_on_parent_focus) { + if (popped_up && get_flag(FLAG_POPUP)) { _close_pressed(); } } @@ -107,23 +111,7 @@ void Popup::_close_pressed() { call_deferred(SNAME("hide")); } -void Popup::set_as_minsize() { - set_size(get_contents_minimum_size()); -} - -void Popup::set_close_on_parent_focus(bool p_close) { - close_on_parent_focus = p_close; -} - -bool Popup::get_close_on_parent_focus() { - return close_on_parent_focus; -} - void Popup::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_close_on_parent_focus", "close"), &Popup::set_close_on_parent_focus); - ClassDB::bind_method(D_METHOD("get_close_on_parent_focus"), &Popup::get_close_on_parent_focus); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "close_on_parent_focus"), "set_close_on_parent_focus", "get_close_on_parent_focus"); - ADD_SIGNAL(MethodInfo("popup_hide")); } @@ -184,6 +172,7 @@ Popup::Popup() { set_transient(true); set_flag(FLAG_BORDERLESS, true); set_flag(FLAG_RESIZE_DISABLED, true); + set_flag(FLAG_POPUP, true); connect("window_input", callable_mp(this, &Popup::_input_from_window)); } @@ -241,13 +230,20 @@ void PopupPanel::_update_child_rects() { } void PopupPanel::_notification(int p_what) { - if (p_what == NOTIFICATION_THEME_CHANGED) { - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name())); - } else if (p_what == NOTIFICATION_READY || p_what == NOTIFICATION_ENTER_TREE) { - panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name())); - _update_child_rects(); - } else if (p_what == NOTIFICATION_WM_SIZE_CHANGED) { - _update_child_rects(); + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name())); + } break; + + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_READY: { + panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), get_class_name())); + _update_child_rects(); + } break; + + case NOTIFICATION_WM_SIZE_CHANGED: { + _update_child_rects(); + } break; } } diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 5678043b23..c45f4ddc24 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -42,7 +42,6 @@ class Popup : public Window { LocalVector<Window *> visible_parents; bool popped_up = false; - bool close_on_parent_focus = true; void _input_from_window(const Ref<InputEvent> &p_event); @@ -59,11 +58,6 @@ protected: static void _bind_methods(); public: - void set_as_minsize(); - - void set_close_on_parent_focus(bool p_close); - bool get_close_on_parent_focus(); - Popup(); ~Popup(); }; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 5c86e1850e..4220066b20 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -186,7 +186,7 @@ void PopupMenu::_activate_submenu(int p_over) { float scroll_offset = control->get_position().y; - submenu_popup->set_as_minsize(); // Shrink the popup size to its contents. + submenu_popup->reset_size(); // Shrink the popup size to its contents. Size2 submenu_size = submenu_popup->get_size(); Point2 submenu_pos; @@ -205,7 +205,6 @@ void PopupMenu::_activate_submenu(int p_over) { submenu_pos.x = this_pos.x - submenu_size.width; } - submenu_popup->set_close_on_parent_focus(false); submenu_popup->set_position(submenu_pos); PopupMenu *submenu_pum = Object::cast_to<PopupMenu>(submenu_popup); @@ -223,6 +222,11 @@ void PopupMenu::_activate_submenu(int p_over) { // Set autohide areas. + Rect2 safe_area = this_rect; + safe_area.position.y += items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2; + safe_area.size.y = items[p_over]._height_cache; + DisplayServer::get_singleton()->window_set_popup_safe_rect(submenu_popup->get_window_id(), safe_area); + // Make the position of the parent popup relative to submenu popup. this_rect.position = this_rect.position - submenu_pum->get_position(); @@ -736,6 +740,7 @@ void PopupMenu::_notification(int p_what) { set_submenu_popup_delay(pm_delay); } } break; + case NOTIFICATION_THEME_CHANGED: case Control::NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { @@ -748,23 +753,25 @@ void PopupMenu::_notification(int p_what) { child_controls_changed(); control->update(); } break; + case NOTIFICATION_WM_MOUSE_ENTER: { grab_focus(); } break; + case NOTIFICATION_WM_MOUSE_EXIT: { if (mouse_over >= 0 && (items[mouse_over].submenu.is_empty() || submenu_over != -1)) { mouse_over = -1; control->update(); } } break; + case NOTIFICATION_POST_POPUP: { initial_button_mask = Input::get_singleton()->get_mouse_button_mask(); during_grabbed_click = (bool)initial_button_mask; } break; - case NOTIFICATION_WM_SIZE_CHANGED: { - } break; + case NOTIFICATION_INTERNAL_PROCESS: { - //only used when using operating system windows + // Only used when using operating system windows. if (!is_embedded() && autohide_areas.size()) { Point2 mouse_pos = DisplayServer::get_singleton()->mouse_get_position(); mouse_pos -= get_position(); @@ -777,6 +784,7 @@ void PopupMenu::_notification(int p_what) { } } } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (!is_visible()) { if (mouse_over >= 0) { @@ -991,6 +999,9 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, /* Methods to modify existing items. */ void PopupMenu::set_item_text(int p_idx, const String &p_text) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].text = p_text; items.write[p_idx].xl_text = atr(p_text); @@ -1001,6 +1012,9 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) { } void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_text_direction) { + if (p_item < 0) { + p_item += get_item_count(); + } ERR_FAIL_INDEX(p_item, items.size()); ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); if (items[p_item].text_direction != p_text_direction) { @@ -1011,6 +1025,9 @@ void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_tex } void PopupMenu::clear_item_opentype_features(int p_item) { + if (p_item < 0) { + p_item += get_item_count(); + } ERR_FAIL_INDEX(p_item, items.size()); items.write[p_item].opentype_features.clear(); items.write[p_item].dirty = true; @@ -1018,6 +1035,9 @@ void PopupMenu::clear_item_opentype_features(int p_item) { } void PopupMenu::set_item_opentype_feature(int p_item, const String &p_name, int p_value) { + if (p_item < 0) { + p_item += get_item_count(); + } ERR_FAIL_INDEX(p_item, items.size()); int32_t tag = TS->name_to_tag(p_name); if (!items[p_item].opentype_features.has(tag) || (int)items[p_item].opentype_features[tag] != p_value) { @@ -1028,6 +1048,9 @@ void PopupMenu::set_item_opentype_feature(int p_item, const String &p_name, int } void PopupMenu::set_item_language(int p_item, const String &p_language) { + if (p_item < 0) { + p_item += get_item_count(); + } ERR_FAIL_INDEX(p_item, items.size()); if (items[p_item].language != p_language) { items.write[p_item].language = p_language; @@ -1037,6 +1060,9 @@ void PopupMenu::set_item_language(int p_item, const String &p_language) { } void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].icon = p_icon; @@ -1045,6 +1071,9 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { } void PopupMenu::set_item_checked(int p_idx, bool p_checked) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].checked = p_checked; @@ -1054,6 +1083,9 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { } void PopupMenu::set_item_id(int p_idx, int p_id) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].id = p_id; @@ -1062,6 +1094,9 @@ void PopupMenu::set_item_id(int p_idx, int p_id) { } void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].accel = p_accel; items.write[p_idx].dirty = true; @@ -1071,6 +1106,9 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) { } void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].metadata = p_meta; control->update(); @@ -1078,6 +1116,9 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { } void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].disabled = p_disabled; control->update(); @@ -1085,6 +1126,9 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { } void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].submenu = p_submenu; control->update(); @@ -1193,6 +1237,9 @@ int PopupMenu::get_item_state(int p_idx) const { } void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].separator = p_separator; control->update(); @@ -1204,24 +1251,36 @@ bool PopupMenu::is_item_separator(int p_idx) const { } void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; control->update(); } void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; control->update(); } void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].tooltip = p_tooltip; control->update(); } void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); if (items[p_idx].shortcut.is_valid()) { _unref_shortcut(items[p_idx].shortcut); @@ -1238,6 +1297,9 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo } void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].h_ofs = p_offset; control->update(); @@ -1245,12 +1307,18 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { } void PopupMenu::set_item_multistate(int p_idx, int p_state) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].state = p_state; control->update(); } void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) { + if (p_idx < 0) { + p_idx += get_item_count(); + } ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].shortcut_is_disabled = p_disabled; control->update(); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index c20fb0d7a8..20b3513375 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "progress_bar.h" + #include "scene/resources/text_line.h" Size2 ProgressBar::get_minimum_size() const { @@ -52,36 +53,38 @@ Size2 ProgressBar::get_minimum_size() const { } void ProgressBar::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg")); - Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg")); - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); - Color font_color = get_theme_color(SNAME("font_color")); + switch (p_what) { + case NOTIFICATION_DRAW: { + Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg")); + Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg")); + Ref<Font> font = get_theme_font(SNAME("font")); + int font_size = get_theme_font_size(SNAME("font_size")); + Color font_color = get_theme_color(SNAME("font_color")); - draw_style_box(bg, Rect2(Point2(), get_size())); - float r = get_as_ratio(); - int mp = fg->get_minimum_size().width; - int p = r * (get_size().width - mp); - if (p > 0) { - if (is_layout_rtl()) { - draw_style_box(fg, Rect2(Point2(p, 0), Size2(fg->get_minimum_size().width, get_size().height))); - } else { - draw_style_box(fg, Rect2(Point2(0, 0), Size2(p + fg->get_minimum_size().width, get_size().height))); + draw_style_box(bg, Rect2(Point2(), get_size())); + float r = get_as_ratio(); + int mp = fg->get_minimum_size().width; + int p = r * (get_size().width - mp); + if (p > 0) { + if (is_layout_rtl()) { + draw_style_box(fg, Rect2(Point2(p, 0), Size2(fg->get_minimum_size().width, get_size().height))); + } else { + draw_style_box(fg, Rect2(Point2(0, 0), Size2(p + fg->get_minimum_size().width, get_size().height))); + } } - } - if (percent_visible) { - String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign(); - TextLine tl = TextLine(txt, font, font_size); - Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round(); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); - if (outline_size > 0 && font_outline_color.a > 0) { - tl.draw_outline(get_canvas_item(), text_pos, outline_size, font_outline_color); + if (percent_visible) { + String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign(); + TextLine tl = TextLine(txt, font, font_size); + Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round(); + Color font_outline_color = get_theme_color(SNAME("font_outline_color")); + int outline_size = get_theme_constant(SNAME("outline_size")); + if (outline_size > 0 && font_outline_color.a > 0) { + tl.draw_outline(get_canvas_item(), text_pos, outline_size, font_outline_color); + } + tl.draw(get_canvas_item(), text_pos, font_color); } - tl.draw(get_canvas_item(), text_pos, font_color); - } + } break; } } diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 879f25c8d8..2fb6452a97 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -40,6 +40,9 @@ TypedArray<String> Range::get_configuration_warnings() const { return warnings; } +void Range::_value_changed(double p_value) { + GDVIRTUAL_CALL(_value_changed, p_value); +} void Range::_value_changed_notify() { _value_changed(shared->val); emit_signal(SNAME("value_changed"), shared->val); @@ -279,6 +282,8 @@ void Range::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_greater"), "set_allow_greater", "is_greater_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed"); + GDVIRTUAL_BIND(_value_changed); + ADD_LINKED_PROPERTY("min_value", "value"); ADD_LINKED_PROPERTY("min_value", "max_value"); ADD_LINKED_PROPERTY("min_value", "page"); diff --git a/scene/gui/range.h b/scene/gui/range.h index c27eeee13c..597c50ca26 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -62,12 +62,14 @@ class Range : public Control { void _validate_values(); protected: - virtual void _value_changed(double) {} + virtual void _value_changed(double p_value); static void _bind_methods(); bool _rounded_values = false; + GDVIRTUAL1(_value_changed, double) + public: void set_value(double p_val); void set_min(double p_min); diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp index e2a0d568a1..ed79da5c22 100644 --- a/scene/gui/reference_rect.cpp +++ b/scene/gui/reference_rect.cpp @@ -33,13 +33,15 @@ #include "core/config/engine.h" void ReferenceRect::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - if (!is_inside_tree()) { - return; - } - if (Engine::get_singleton()->is_editor_hint() || !editor_only) { - draw_rect(Rect2(Point2(), get_size()), border_color, false, border_width); - } + switch (p_what) { + case NOTIFICATION_DRAW: { + if (!is_inside_tree()) { + return; + } + if (Engine::get_singleton()->is_editor_hint() || !editor_only) { + draw_rect(Rect2(Point2(), get_size()), border_color, false, border_width); + } + } break; } } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 042aec7362..bad7be7d42 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1502,15 +1502,17 @@ void RichTextLabel::_notification(int p_what) { update(); } } break; + case NOTIFICATION_RESIZED: { main->first_resized_line = 0; //invalidate ALL update(); - } break; + case NOTIFICATION_THEME_CHANGED: { main->first_invalid_font_line = 0; //invalidate ALL update(); } break; + case NOTIFICATION_ENTER_TREE: { if (!text.is_empty()) { set_text(text); @@ -1519,11 +1521,13 @@ void RichTextLabel::_notification(int p_what) { main->first_invalid_line = 0; //invalidate ALL update(); } break; + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { main->first_invalid_line = 0; //invalidate ALL update(); } break; + case NOTIFICATION_DRAW: { _validate_line_caches(main); _update_scroll(); @@ -1578,6 +1582,7 @@ void RichTextLabel::_notification(int p_what) { from_line++; } } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (is_visible_in_tree()) { double dt = get_process_delta_time(); @@ -1585,12 +1590,14 @@ void RichTextLabel::_notification(int p_what) { update(); } } break; + case NOTIFICATION_FOCUS_EXIT: { if (deselect_on_focus_loss_enabled) { selection.active = false; update(); } } break; + case NOTIFICATION_DRAG_END: { selection.drag_attempt = false; } break; @@ -3243,6 +3250,10 @@ void RichTextLabel::append_text(const String &p_bbcode) { push_paragraph(HORIZONTAL_ALIGNMENT_FILL); pos = brk_end + 1; tag_stack.push_front(tag); + } else if (tag == "left") { + push_paragraph(HORIZONTAL_ALIGNMENT_LEFT); + pos = brk_end + 1; + tag_stack.push_front(tag); } else if (tag == "right") { push_paragraph(HORIZONTAL_ALIGNMENT_RIGHT); pos = brk_end + 1; @@ -3718,7 +3729,7 @@ void RichTextLabel::scroll_to_line(int p_line) { if ((line_count <= p_line) && (line_count + main->lines[i].text_buf->get_line_count() >= p_line)) { float line_offset = 0.f; for (int j = 0; j < p_line - line_count; j++) { - line_offset += main->lines[i].text_buf->get_line_size(j).y; + line_offset += main->lines[i].text_buf->get_line_size(j).y + get_theme_constant(SNAME("line_separation")); } vscroll->set_value(main->lines[i].offset.y + line_offset); return; @@ -3727,6 +3738,28 @@ void RichTextLabel::scroll_to_line(int p_line) { } } +float RichTextLabel::get_line_offset(int p_line) { + int line_count = 0; + for (int i = 0; i < main->lines.size(); i++) { + if ((line_count <= p_line) && (p_line <= line_count + main->lines[i].text_buf->get_line_count())) { + float line_offset = 0.f; + for (int j = 0; j < p_line - line_count; j++) { + line_offset += main->lines[i].text_buf->get_line_size(j).y + get_theme_constant(SNAME("line_separation")); + } + return main->lines[i].offset.y + line_offset; + } + line_count += main->lines[i].text_buf->get_line_count(); + } + return 0; +} + +float RichTextLabel::get_paragraph_offset(int p_paragraph) { + if (0 <= p_paragraph && p_paragraph < main->lines.size()) { + return main->lines[p_paragraph].offset.y; + } + return 0; +} + int RichTextLabel::get_line_count() const { int line_count = 0; for (int i = 0; i < main->lines.size(); i++) { @@ -4327,6 +4360,8 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_percent_visible", "percent_visible"), &RichTextLabel::set_percent_visible); ClassDB::bind_method(D_METHOD("get_percent_visible"), &RichTextLabel::get_percent_visible); + ClassDB::bind_method(D_METHOD("get_character_line", "character"), &RichTextLabel::get_character_line); + ClassDB::bind_method(D_METHOD("get_character_paragraph", "character"), &RichTextLabel::get_character_paragraph); ClassDB::bind_method(D_METHOD("get_total_character_count"), &RichTextLabel::get_total_character_count); ClassDB::bind_method(D_METHOD("set_use_bbcode", "enable"), &RichTextLabel::set_use_bbcode); @@ -4341,6 +4376,9 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_content_height"), &RichTextLabel::get_content_height); ClassDB::bind_method(D_METHOD("get_content_width"), &RichTextLabel::get_content_width); + ClassDB::bind_method(D_METHOD("get_line_offset", "line"), &RichTextLabel::get_line_offset); + ClassDB::bind_method(D_METHOD("get_paragraph_offset", "paragraph"), &RichTextLabel::get_paragraph_offset); + ClassDB::bind_method(D_METHOD("parse_expressions_for_values", "expressions"), &RichTextLabel::parse_expressions_for_values); ClassDB::bind_method(D_METHOD("set_effects", "effects"), &RichTextLabel::set_effects); @@ -4459,6 +4497,36 @@ int RichTextLabel::get_visible_characters() const { return visible_characters; } +int RichTextLabel::get_character_line(int p_char) { + int line_count = 0; + for (int i = 0; i < main->lines.size(); i++) { + if (main->lines[i].char_offset < p_char && p_char <= main->lines[i].char_offset + main->lines[i].char_count) { + for (int j = 0; j < main->lines[i].text_buf->get_line_count(); j++) { + Vector2i range = main->lines[i].text_buf->get_line_range(j); + if (main->lines[i].char_offset + range.x < p_char && p_char <= main->lines[i].char_offset + range.y) { + return line_count; + } + line_count++; + } + } else { + line_count += main->lines[i].text_buf->get_line_count(); + } + } + return -1; +} + +int RichTextLabel::get_character_paragraph(int p_char) { + int para_count = 0; + for (int i = 0; i < main->lines.size(); i++) { + if (main->lines[i].char_offset < p_char && p_char <= main->lines[i].char_offset + main->lines[i].char_count) { + return para_count; + } else { + para_count++; + } + } + return -1; +} + int RichTextLabel::get_total_character_count() const { // Note: Do not use line buffer "char_count", it includes only visible characters. int tc = 0; @@ -4648,7 +4716,7 @@ Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressi return d; } -RichTextLabel::RichTextLabel() { +RichTextLabel::RichTextLabel(const String &p_text) { main = memnew(ItemFrame); main->index = 0; current = main; @@ -4670,6 +4738,8 @@ RichTextLabel::RichTextLabel() { vscroll->set_step(1); vscroll->hide(); + set_text(p_text); + set_clip_contents(true); } diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 5ed1031798..076b68a0da 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -551,6 +551,9 @@ public: int get_paragraph_count() const; int get_visible_paragraph_count() const; + float get_line_offset(int p_line); + float get_paragraph_offset(int p_paragraph); + void scroll_to_line(int p_line); int get_line_count() const; int get_visible_line_count() const; @@ -598,6 +601,8 @@ public: void set_visible_characters(int p_visible); int get_visible_characters() const; + int get_character_line(int p_char); + int get_character_paragraph(int p_char); int get_total_character_count() const; int get_total_glyph_count() const; @@ -615,7 +620,7 @@ public: void set_fixed_size_to_width(int p_width); virtual Size2 get_minimum_size() const override; - RichTextLabel(); + RichTextLabel(const String &p_text = String()); ~RichTextLabel(); }; diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 343056957c..e1b0e8cca8 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -218,195 +218,198 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { } void ScrollBar::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - RID ci = get_canvas_item(); + switch (p_what) { + case NOTIFICATION_DRAW: { + RID ci = get_canvas_item(); - Ref<Texture2D> decr, incr; + Ref<Texture2D> decr, incr; - if (decr_active) { - decr = get_theme_icon(SNAME("decrement_pressed")); - } else if (highlight == HIGHLIGHT_DECR) { - decr = get_theme_icon(SNAME("decrement_highlight")); - } else { - decr = get_theme_icon(SNAME("decrement")); - } + if (decr_active) { + decr = get_theme_icon(SNAME("decrement_pressed")); + } else if (highlight == HIGHLIGHT_DECR) { + decr = get_theme_icon(SNAME("decrement_highlight")); + } else { + decr = get_theme_icon(SNAME("decrement")); + } - if (incr_active) { - incr = get_theme_icon(SNAME("increment_pressed")); - } else if (highlight == HIGHLIGHT_INCR) { - incr = get_theme_icon(SNAME("increment_highlight")); - } else { - incr = get_theme_icon(SNAME("increment")); - } + if (incr_active) { + incr = get_theme_icon(SNAME("increment_pressed")); + } else if (highlight == HIGHLIGHT_INCR) { + incr = get_theme_icon(SNAME("increment_highlight")); + } else { + incr = get_theme_icon(SNAME("increment")); + } - Ref<StyleBox> bg = has_focus() ? get_theme_stylebox(SNAME("scroll_focus")) : get_theme_stylebox(SNAME("scroll")); + Ref<StyleBox> bg = has_focus() ? get_theme_stylebox(SNAME("scroll_focus")) : get_theme_stylebox(SNAME("scroll")); - Ref<StyleBox> grabber; - if (drag.active) { - grabber = get_theme_stylebox(SNAME("grabber_pressed")); - } else if (highlight == HIGHLIGHT_RANGE) { - grabber = get_theme_stylebox(SNAME("grabber_highlight")); - } else { - grabber = get_theme_stylebox(SNAME("grabber")); - } + Ref<StyleBox> grabber; + if (drag.active) { + grabber = get_theme_stylebox(SNAME("grabber_pressed")); + } else if (highlight == HIGHLIGHT_RANGE) { + grabber = get_theme_stylebox(SNAME("grabber_highlight")); + } else { + grabber = get_theme_stylebox(SNAME("grabber")); + } - Point2 ofs; + Point2 ofs; - decr->draw(ci, Point2()); + decr->draw(ci, Point2()); - if (orientation == HORIZONTAL) { - ofs.x += decr->get_width(); - } else { - ofs.y += decr->get_height(); - } + if (orientation == HORIZONTAL) { + ofs.x += decr->get_width(); + } else { + ofs.y += decr->get_height(); + } - Size2 area = get_size(); + Size2 area = get_size(); - if (orientation == HORIZONTAL) { - area.width -= incr->get_width() + decr->get_width(); - } else { - area.height -= incr->get_height() + decr->get_height(); - } + if (orientation == HORIZONTAL) { + area.width -= incr->get_width() + decr->get_width(); + } else { + area.height -= incr->get_height() + decr->get_height(); + } - bg->draw(ci, Rect2(ofs, area)); + bg->draw(ci, Rect2(ofs, area)); - if (orientation == HORIZONTAL) { - ofs.width += area.width; - } else { - ofs.height += area.height; - } + if (orientation == HORIZONTAL) { + ofs.width += area.width; + } else { + ofs.height += area.height; + } - incr->draw(ci, ofs); - Rect2 grabber_rect; + incr->draw(ci, ofs); + Rect2 grabber_rect; - if (orientation == HORIZONTAL) { - grabber_rect.size.width = get_grabber_size(); - grabber_rect.size.height = get_size().height; - grabber_rect.position.y = 0; - grabber_rect.position.x = get_grabber_offset() + decr->get_width() + bg->get_margin(SIDE_LEFT); - } else { - grabber_rect.size.width = get_size().width; - grabber_rect.size.height = get_grabber_size(); - grabber_rect.position.y = get_grabber_offset() + decr->get_height() + bg->get_margin(SIDE_TOP); - grabber_rect.position.x = 0; - } + if (orientation == HORIZONTAL) { + grabber_rect.size.width = get_grabber_size(); + grabber_rect.size.height = get_size().height; + grabber_rect.position.y = 0; + grabber_rect.position.x = get_grabber_offset() + decr->get_width() + bg->get_margin(SIDE_LEFT); + } else { + grabber_rect.size.width = get_size().width; + grabber_rect.size.height = get_grabber_size(); + grabber_rect.position.y = get_grabber_offset() + decr->get_height() + bg->get_margin(SIDE_TOP); + grabber_rect.position.x = 0; + } - grabber->draw(ci, grabber_rect); - } + grabber->draw(ci, grabber_rect); + } break; - if (p_what == NOTIFICATION_ENTER_TREE) { - if (has_node(drag_node_path)) { - Node *n = get_node(drag_node_path); - drag_node = Object::cast_to<Control>(n); - } + case NOTIFICATION_ENTER_TREE: { + if (has_node(drag_node_path)) { + Node *n = get_node(drag_node_path); + drag_node = Object::cast_to<Control>(n); + } - if (drag_node) { - drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); - drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), varray(), CONNECT_ONESHOT); - } - } - if (p_what == NOTIFICATION_EXIT_TREE) { - if (drag_node) { - drag_node->disconnect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); - drag_node->disconnect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit)); - } + if (drag_node) { + drag_node->connect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); + drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), varray(), CONNECT_ONESHOT); + } + } break; - drag_node = nullptr; - } + case NOTIFICATION_EXIT_TREE: { + if (drag_node) { + drag_node->disconnect("gui_input", callable_mp(this, &ScrollBar::_drag_node_input)); + drag_node->disconnect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit)); + } - if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - if (scrolling) { - if (get_value() != target_scroll) { - double target = target_scroll - get_value(); - double dist = sqrt(target * target); - double vel = ((target / dist) * 500) * get_physics_process_delta_time(); + drag_node = nullptr; + } break; - if (Math::abs(vel) >= dist) { - set_value(target_scroll); + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (scrolling) { + if (get_value() != target_scroll) { + double target = target_scroll - get_value(); + double dist = sqrt(target * target); + double vel = ((target / dist) * 500) * get_physics_process_delta_time(); + + if (Math::abs(vel) >= dist) { + set_value(target_scroll); + scrolling = false; + set_physics_process_internal(false); + } else { + set_value(get_value() + vel); + } + } else { scrolling = false; set_physics_process_internal(false); - } else { - set_value(get_value() + vel); } - } else { - scrolling = false; - set_physics_process_internal(false); - } - } else if (drag_node_touching) { - if (drag_node_touching_deaccel) { - Vector2 pos = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0); - pos += drag_node_speed * get_physics_process_delta_time(); + } else if (drag_node_touching) { + if (drag_node_touching_deaccel) { + Vector2 pos = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0); + pos += drag_node_speed * get_physics_process_delta_time(); - bool turnoff = false; + bool turnoff = false; - if (orientation == HORIZONTAL) { - if (pos.x < 0) { - pos.x = 0; - turnoff = true; - } + if (orientation == HORIZONTAL) { + if (pos.x < 0) { + pos.x = 0; + turnoff = true; + } - if (pos.x > (get_max() - get_page())) { - pos.x = get_max() - get_page(); - turnoff = true; - } + if (pos.x > (get_max() - get_page())) { + pos.x = get_max() - get_page(); + turnoff = true; + } - set_value(pos.x); + set_value(pos.x); - float sgn_x = drag_node_speed.x < 0 ? -1 : 1; - float val_x = Math::abs(drag_node_speed.x); - val_x -= 1000 * get_physics_process_delta_time(); + float sgn_x = drag_node_speed.x < 0 ? -1 : 1; + float val_x = Math::abs(drag_node_speed.x); + val_x -= 1000 * get_physics_process_delta_time(); - if (val_x < 0) { - turnoff = true; - } + if (val_x < 0) { + turnoff = true; + } - drag_node_speed.x = sgn_x * val_x; + drag_node_speed.x = sgn_x * val_x; - } else { - if (pos.y < 0) { - pos.y = 0; - turnoff = true; - } + } else { + if (pos.y < 0) { + pos.y = 0; + turnoff = true; + } - if (pos.y > (get_max() - get_page())) { - pos.y = get_max() - get_page(); - turnoff = true; - } + if (pos.y > (get_max() - get_page())) { + pos.y = get_max() - get_page(); + turnoff = true; + } - set_value(pos.y); + set_value(pos.y); - float sgn_y = drag_node_speed.y < 0 ? -1 : 1; - float val_y = Math::abs(drag_node_speed.y); - val_y -= 1000 * get_physics_process_delta_time(); + float sgn_y = drag_node_speed.y < 0 ? -1 : 1; + float val_y = Math::abs(drag_node_speed.y); + val_y -= 1000 * get_physics_process_delta_time(); - if (val_y < 0) { - turnoff = true; + if (val_y < 0) { + turnoff = true; + } + drag_node_speed.y = sgn_y * val_y; } - drag_node_speed.y = sgn_y * val_y; - } - if (turnoff) { - set_physics_process_internal(false); - drag_node_touching = false; - drag_node_touching_deaccel = false; - } + if (turnoff) { + set_physics_process_internal(false); + drag_node_touching = false; + drag_node_touching_deaccel = false; + } - } else { - if (time_since_motion == 0 || time_since_motion > 0.1) { - Vector2 diff = drag_node_accum - last_drag_node_accum; - last_drag_node_accum = drag_node_accum; - drag_node_speed = diff / get_physics_process_delta_time(); - } + } else { + if (time_since_motion == 0 || time_since_motion > 0.1) { + Vector2 diff = drag_node_accum - last_drag_node_accum; + last_drag_node_accum = drag_node_accum; + drag_node_speed = diff / get_physics_process_delta_time(); + } - time_since_motion += get_physics_process_delta_time(); + time_since_motion += get_physics_process_delta_time(); + } } - } - } + } break; - if (p_what == NOTIFICATION_MOUSE_EXIT) { - highlight = HIGHLIGHT_NONE; - update(); + case NOTIFICATION_MOUSE_EXIT: { + highlight = HIGHLIGHT_NONE; + update(); + } break; } } @@ -423,11 +426,6 @@ double ScrollBar::get_grabber_size() const { } float page = (get_page() > 0) ? get_page() : 0; - /* - if (grabber_range < get_step()) - grabber_range=get_step(); - */ - double area_size = get_area_size(); double grabber_size = page / range * area_size; return grabber_size + get_grabber_min_size(); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 7e69fa09e7..b3cf2cbf7e 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -316,97 +316,102 @@ void ScrollContainer::_update_dimensions() { } void ScrollContainer::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || p_what == NOTIFICATION_TRANSLATION_CHANGED) { - _updating_scrollbars = true; - call_deferred(SNAME("_update_scrollbar_position")); - }; - - if (p_what == NOTIFICATION_READY) { - Viewport *viewport = get_viewport(); - ERR_FAIL_COND(!viewport); - viewport->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_gui_focus_changed)); - _update_dimensions(); - } - - if (p_what == NOTIFICATION_SORT_CHILDREN) { - _update_dimensions(); - }; - - if (p_what == NOTIFICATION_DRAW) { - Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); - draw_style_box(sb, Rect2(Vector2(), get_size())); - - update_scrollbars(); - } - - if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - if (drag_touching) { - if (drag_touching_deaccel) { - Vector2 pos = Vector2(h_scroll->get_value(), v_scroll->get_value()); - pos += drag_speed * get_physics_process_delta_time(); - - bool turnoff_h = false; - bool turnoff_v = false; - - if (pos.x < 0) { - pos.x = 0; - turnoff_h = true; - } - if (pos.x > (h_scroll->get_max() - h_scroll->get_page())) { - pos.x = h_scroll->get_max() - h_scroll->get_page(); - turnoff_h = true; - } - - if (pos.y < 0) { - pos.y = 0; - turnoff_v = true; - } - if (pos.y > (v_scroll->get_max() - v_scroll->get_page())) { - pos.y = v_scroll->get_max() - v_scroll->get_page(); - turnoff_v = true; - } - - if (horizontal_scroll_mode != SCROLL_MODE_DISABLED) { - h_scroll->set_value(pos.x); - } - if (vertical_scroll_mode != SCROLL_MODE_DISABLED) { - v_scroll->set_value(pos.y); - } - - float sgn_x = drag_speed.x < 0 ? -1 : 1; - float val_x = Math::abs(drag_speed.x); - val_x -= 1000 * get_physics_process_delta_time(); - - if (val_x < 0) { - turnoff_h = true; - } - - float sgn_y = drag_speed.y < 0 ? -1 : 1; - float val_y = Math::abs(drag_speed.y); - val_y -= 1000 * get_physics_process_delta_time(); - - if (val_y < 0) { - turnoff_v = true; - } - - drag_speed = Vector2(sgn_x * val_x, sgn_y * val_y); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: + case NOTIFICATION_TRANSLATION_CHANGED: { + _updating_scrollbars = true; + call_deferred(SNAME("_update_scrollbar_position")); + } break; + + case NOTIFICATION_READY: { + Viewport *viewport = get_viewport(); + ERR_FAIL_COND(!viewport); + viewport->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_gui_focus_changed)); + _update_dimensions(); + } break; + + case NOTIFICATION_SORT_CHILDREN: { + _update_dimensions(); + } break; + + case NOTIFICATION_DRAW: { + Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); + draw_style_box(sb, Rect2(Vector2(), get_size())); + + update_scrollbars(); + } break; + + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (drag_touching) { + if (drag_touching_deaccel) { + Vector2 pos = Vector2(h_scroll->get_value(), v_scroll->get_value()); + pos += drag_speed * get_physics_process_delta_time(); + + bool turnoff_h = false; + bool turnoff_v = false; + + if (pos.x < 0) { + pos.x = 0; + turnoff_h = true; + } + if (pos.x > (h_scroll->get_max() - h_scroll->get_page())) { + pos.x = h_scroll->get_max() - h_scroll->get_page(); + turnoff_h = true; + } + + if (pos.y < 0) { + pos.y = 0; + turnoff_v = true; + } + if (pos.y > (v_scroll->get_max() - v_scroll->get_page())) { + pos.y = v_scroll->get_max() - v_scroll->get_page(); + turnoff_v = true; + } + + if (horizontal_scroll_mode != SCROLL_MODE_DISABLED) { + h_scroll->set_value(pos.x); + } + if (vertical_scroll_mode != SCROLL_MODE_DISABLED) { + v_scroll->set_value(pos.y); + } + + float sgn_x = drag_speed.x < 0 ? -1 : 1; + float val_x = Math::abs(drag_speed.x); + val_x -= 1000 * get_physics_process_delta_time(); + + if (val_x < 0) { + turnoff_h = true; + } + + float sgn_y = drag_speed.y < 0 ? -1 : 1; + float val_y = Math::abs(drag_speed.y); + val_y -= 1000 * get_physics_process_delta_time(); + + if (val_y < 0) { + turnoff_v = true; + } + + drag_speed = Vector2(sgn_x * val_x, sgn_y * val_y); + + if (turnoff_h && turnoff_v) { + _cancel_drag(); + } - if (turnoff_h && turnoff_v) { - _cancel_drag(); - } + } else { + if (time_since_motion == 0 || time_since_motion > 0.1) { + Vector2 diff = drag_accum - last_drag_accum; + last_drag_accum = drag_accum; + drag_speed = diff / get_physics_process_delta_time(); + } - } else { - if (time_since_motion == 0 || time_since_motion > 0.1) { - Vector2 diff = drag_accum - last_drag_accum; - last_drag_accum = drag_accum; - drag_speed = diff / get_physics_process_delta_time(); + time_since_motion += get_physics_process_delta_time(); } - - time_since_motion += get_physics_process_delta_time(); } - } + } break; } -}; +} void ScrollContainer::update_scrollbars() { Size2 size = get_size(); diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp index 9c19eb54dc..e3400d9c8f 100644 --- a/scene/gui/separator.cpp +++ b/scene/gui/separator.cpp @@ -52,7 +52,6 @@ void Separator::_notification(int p_what) { } else { style->draw(get_canvas_item(), Rect2(0, (size.y - ssize.y) / 2, size.x, ssize.y)); } - } break; } } diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 1d459d589f..4b680f72cf 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "slider.h" + #include "core/os/keyboard.h" Size2 Slider::get_minimum_size() const { @@ -150,19 +151,23 @@ void Slider::_notification(int p_what) { update_minimum_size(); update(); } break; + case NOTIFICATION_MOUSE_ENTER: { mouse_inside = true; update(); } break; + case NOTIFICATION_MOUSE_EXIT: { mouse_inside = false; update(); } break; - case NOTIFICATION_VISIBILITY_CHANGED: // fallthrough + + case NOTIFICATION_VISIBILITY_CHANGED: case NOTIFICATION_EXIT_TREE: { mouse_inside = false; grab.active = false; } break; + case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); Size2i size = get_size(); @@ -209,7 +214,6 @@ void Slider::_notification(int p_what) { } grabber->draw(ci, Point2i(ratio * areasize, size.height / 2 - grabber->get_size().height / 2)); } - } break; } } diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 19d47ea492..e50d7e765c 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -39,7 +39,7 @@ Size2 SpinBox::get_minimum_size() const { return ms; } -void SpinBox::_value_changed(double) { +void SpinBox::_value_changed(double p_value) { String value = TS->format_number(String::num(get_value(), Math::range_step_decimals(get_step()))); if (!prefix.is_empty()) { value = prefix + " " + value; @@ -48,6 +48,7 @@ void SpinBox::_value_changed(double) { value += " " + suffix; } line_edit->set_text(value); + Range::_value_changed(p_value); } void SpinBox::_text_submitted(const String &p_string) { @@ -196,34 +197,44 @@ inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) { } void SpinBox::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - Ref<Texture2D> updown = get_theme_icon(SNAME("updown")); - - _adjust_width_for_icon(updown); - - RID ci = get_canvas_item(); - Size2i size = get_size(); - - if (is_layout_rtl()) { - updown->draw(ci, Point2i(0, (size.height - updown->get_height()) / 2)); - } else { - updown->draw(ci, Point2i(size.width - updown->get_width(), (size.height - updown->get_height()) / 2)); - } - - } else if (p_what == NOTIFICATION_FOCUS_EXIT) { - //_value_changed(0); - } else if (p_what == NOTIFICATION_ENTER_TREE) { - _adjust_width_for_icon(get_theme_icon(SNAME("updown"))); - _value_changed(0); - } else if (p_what == NOTIFICATION_EXIT_TREE) { - _release_mouse(); - } else if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { - _value_changed(0); - } else if (p_what == NOTIFICATION_THEME_CHANGED) { - call_deferred(SNAME("update_minimum_size")); - get_line_edit()->call_deferred(SNAME("update_minimum_size")); - } else if (p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || p_what == NOTIFICATION_TRANSLATION_CHANGED) { - update(); + switch (p_what) { + case NOTIFICATION_DRAW: { + Ref<Texture2D> updown = get_theme_icon(SNAME("updown")); + + _adjust_width_for_icon(updown); + + RID ci = get_canvas_item(); + Size2i size = get_size(); + + if (is_layout_rtl()) { + updown->draw(ci, Point2i(0, (size.height - updown->get_height()) / 2)); + } else { + updown->draw(ci, Point2i(size.width - updown->get_width(), (size.height - updown->get_height()) / 2)); + } + } break; + + case NOTIFICATION_ENTER_TREE: { + _adjust_width_for_icon(get_theme_icon(SNAME("updown"))); + _value_changed(0); + } break; + + case NOTIFICATION_EXIT_TREE: { + _release_mouse(); + } break; + + case NOTIFICATION_TRANSLATION_CHANGED: { + _value_changed(0); + update(); + } break; + + case NOTIFICATION_THEME_CHANGED: { + call_deferred(SNAME("update_minimum_size")); + get_line_edit()->call_deferred(SNAME("update_minimum_size")); + } break; + + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { + update(); + } break; } } diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 0691a4b48d..a15e3fe5f5 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -47,7 +47,7 @@ class SpinBox : public Range { void _release_mouse(); void _text_submitted(const String &p_string); - virtual void _value_changed(double) override; + virtual void _value_changed(double p_value) override; void _text_changed(const String &p_string); String prefix; diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index b56326088d..6845d46721 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -168,15 +168,18 @@ void SplitContainer::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { queue_sort(); } break; + case NOTIFICATION_SORT_CHILDREN: { _resort(); } break; + case NOTIFICATION_MOUSE_EXIT: { mouse_inside = false; if (get_theme_constant(SNAME("autohide"))) { update(); } } break; + case NOTIFICATION_DRAW: { if (!_getch(0) || !_getch(1)) { return; @@ -200,6 +203,7 @@ void SplitContainer::_notification(int p_what) { draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2)); } } break; + case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); } break; diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index b8baefc307..c66e145bc4 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -100,51 +100,72 @@ Vector<int> SubViewportContainer::get_allowed_size_flags_vertical() const { } void SubViewportContainer::_notification(int p_what) { - if (p_what == NOTIFICATION_RESIZED) { - if (!stretch) { - return; - } - - for (int i = 0; i < get_child_count(); i++) { - SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); - if (!c) { - continue; + switch (p_what) { + case NOTIFICATION_RESIZED: { + if (!stretch) { + return; } - c->set_size(get_size() / shrink); - } - } + for (int i = 0; i < get_child_count(); i++) { + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); + if (!c) { + continue; + } - if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_VISIBILITY_CHANGED) { - for (int i = 0; i < get_child_count(); i++) { - SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); - if (!c) { - continue; + c->set_size(get_size() / shrink); } - - if (is_visible_in_tree()) { - c->set_update_mode(SubViewport::UPDATE_ALWAYS); - } else { - c->set_update_mode(SubViewport::UPDATE_DISABLED); + } break; + + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_VISIBILITY_CHANGED: { + for (int i = 0; i < get_child_count(); i++) { + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); + if (!c) { + continue; + } + + if (is_visible_in_tree()) { + c->set_update_mode(SubViewport::UPDATE_ALWAYS); + } else { + c->set_update_mode(SubViewport::UPDATE_DISABLED); + } + + c->set_handle_input_locally(false); //do not handle input locally here + } + } break; + + case NOTIFICATION_DRAW: { + for (int i = 0; i < get_child_count(); i++) { + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); + if (!c) { + continue; + } + + if (stretch) { + draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size())); + } else { + draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size())); + } } + } break; - c->set_handle_input_locally(false); //do not handle input locally here - } - } + case NOTIFICATION_MOUSE_ENTER: { + _notify_viewports(NOTIFICATION_VP_MOUSE_ENTER); + } break; - if (p_what == NOTIFICATION_DRAW) { - for (int i = 0; i < get_child_count(); i++) { - SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); - if (!c) { - continue; - } + case NOTIFICATION_MOUSE_EXIT: { + _notify_viewports(NOTIFICATION_VP_MOUSE_EXIT); + } break; + } +} - if (stretch) { - draw_texture_rect(c->get_texture(), Rect2(Vector2(), get_size())); - } else { - draw_texture_rect(c->get_texture(), Rect2(Vector2(), c->get_size())); - } +void SubViewportContainer::_notify_viewports(int p_notification) { + for (int i = 0; i < get_child_count(); i++) { + SubViewport *c = Object::cast_to<SubViewport>(get_child(i)); + if (!c) { + continue; } + c->notification(p_notification); } } diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index 3138a6144c..f52f01e4e2 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -38,6 +38,7 @@ class SubViewportContainer : public Container { bool stretch = false; int shrink = 1; + void _notify_viewports(int p_notification); protected: void _notification(int p_what); diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index b1baacd887..af314b9545 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -32,7 +32,6 @@ #include "core/object/message_queue.h" #include "core/string/translation.h" - #include "scene/gui/box_container.h" #include "scene/gui/label.h" #include "scene/gui/texture_rect.h" @@ -72,7 +71,7 @@ Size2 TabBar::get_minimum_size() const { Ref<Texture2D> tex = tabs[i].icon; if (tex.is_valid()) { - ms.height = MAX(ms.height, tex->get_size().height); + ms.height = MAX(ms.height, tex->get_size().height + y_margin); ms.width += tex->get_size().width + hseparation; } @@ -92,13 +91,13 @@ Size2 TabBar::get_minimum_size() const { ms.width += button_highlight->get_margin(SIDE_LEFT) + rb->get_width() + hseparation; } - ms.height = MAX(rb->get_height() + style->get_minimum_size().height, ms.height); + ms.height = MAX(ms.height, rb->get_height() + y_margin); } if (close_visible) { ms.width += button_highlight->get_margin(SIDE_LEFT) + close->get_width() + hseparation; - ms.height = MAX(close->get_height() + style->get_minimum_size().height, ms.height); + ms.height = MAX(ms.height, close->get_height() + y_margin); } if (ms.width - ofs > style->get_minimum_size().width) { @@ -313,6 +312,7 @@ void TabBar::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { update(); } break; + case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { for (int i = 0; i < tabs.size(); ++i) { @@ -332,6 +332,7 @@ void TabBar::_notification(int p_what) { ensure_tab_visible(current); } } break; + case NOTIFICATION_DRAW: { if (tabs.is_empty()) { return; @@ -524,13 +525,14 @@ void TabBar::set_tab_count(int p_count) { offset = MIN(offset, p_count - 1); max_drawn_tab = MIN(max_drawn_tab, p_count - 1); current = MIN(current, p_count - 1); - } - _update_cache(); - _ensure_no_over_offset(); - if (scroll_to_selected) { - ensure_tab_visible(current); + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } } + update(); update_minimum_size(); notify_property_list_changed(); @@ -550,10 +552,6 @@ void TabBar::set_current_tab(int p_current) { emit_signal(SNAME("tab_selected"), current); return; } - // Triggered by dragging a tab from another TabBar to the selected index, to ensure that tab_changed is emitted. - if (previous == -1) { - previous = current; - } emit_signal(SNAME("tab_selected"), current); @@ -829,78 +827,52 @@ void TabBar::_update_cache() { int limit_minus_buttons = limit - incr->get_width() - decr->get_width(); int w = 0; - int mw = 0; - int size_fixed = 0; - int count_resize = 0; + + max_drawn_tab = tabs.size() - 1; for (int i = 0; i < tabs.size(); i++) { - tabs.write[i].size_text = Math::ceil(tabs[i].text_buf->get_size().x); tabs.write[i].text_buf->set_width(-1); - - tabs.write[i].ofs_cache = 0; + tabs.write[i].size_text = Math::ceil(tabs[i].text_buf->get_size().x); tabs.write[i].size_cache = get_tab_width(i); - if (!tabs[i].hidden) { - mw += tabs[i].size_cache; + if (max_width > 0 && tabs[i].size_cache > max_width) { + int size_textless = tabs[i].size_cache - tabs[i].size_text; + int mw = MAX(size_textless, max_width); - if (tabs[i].size_cache <= min_width || i == current) { - size_fixed += tabs[i].size_cache; - } else { - count_resize++; - } + tabs.write[i].size_text = MAX(mw - size_textless, 1); + tabs.write[i].text_buf->set_width(tabs[i].size_text); + tabs.write[i].size_cache = size_textless + tabs[i].size_text; } - } - - int m_width = min_width; - if (count_resize > 0) { - m_width = MAX((limit_minus_buttons - size_fixed) / count_resize, min_width); - } - - for (int i = offset; i < tabs.size(); i++) { - if (tabs[i].hidden) { - tabs.write[i].ofs_cache = w; - max_drawn_tab = i; + if (i < offset || i > max_drawn_tab) { + tabs.write[i].ofs_cache = 0; continue; } - int lsize = tabs[i].size_cache; - int slen = tabs[i].size_text; + tabs.write[i].ofs_cache = w; - // FIXME: This is completely broken. - if (min_width > 0 && (mw > limit || (offset > 0 && mw > limit_minus_buttons)) && i != current && lsize > m_width) { - slen = MAX(m_width - tabs[i].size_cache + tabs[i].size_text, 1); - lsize = m_width; + if (tabs[i].hidden) { + continue; } - tabs.write[i].ofs_cache = w; - tabs.write[i].size_cache = lsize; - tabs.write[i].size_text = slen; - tabs.write[i].text_buf->set_width(slen); - - w += lsize; - max_drawn_tab = i; + w += tabs[i].size_cache; // Check if all tabs would fit inside the area. if (clip_tabs && i > offset && (w > limit || (offset > 0 && w > limit_minus_buttons))) { tabs.write[i].ofs_cache = 0; - tabs.write[i].text_buf->set_width(-1); w -= tabs[i].size_cache; - max_drawn_tab--; + max_drawn_tab = i - 1; while (w > limit_minus_buttons && max_drawn_tab > offset) { tabs.write[max_drawn_tab].ofs_cache = 0; if (!tabs[max_drawn_tab].hidden) { - tabs.write[max_drawn_tab].text_buf->set_width(-1); w -= tabs[max_drawn_tab].size_cache; } max_drawn_tab--; } - - break; } } @@ -940,28 +912,34 @@ void TabBar::_on_mouse_exited() { void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { Tab t; t.text = p_str; - t.xl_text = atr(p_str); t.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); - t.text_buf->add_string(t.xl_text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); t.icon = p_icon; tabs.push_back(t); + _shape(tabs.size() - 1); _update_cache(); if (scroll_to_selected) { ensure_tab_visible(current); } update(); update_minimum_size(); + + if (tabs.size() == 1 && is_inside_tree()) { + emit_signal(SNAME("tab_changed"), 0); + } } void TabBar::clear_tabs() { + if (tabs.is_empty()) { + return; + } + tabs.clear(); offset = 0; max_drawn_tab = 0; current = 0; previous = 0; - _update_cache(); update(); update_minimum_size(); notify_property_list_changed(); @@ -970,35 +948,43 @@ void TabBar::clear_tabs() { void TabBar::remove_tab(int p_idx) { ERR_FAIL_INDEX(p_idx, tabs.size()); tabs.remove_at(p_idx); - if (current >= p_idx) { + + bool is_tab_changing = current == p_idx && !tabs.is_empty(); + + if (current >= p_idx && current > 0) { current--; } - if (current < 0) { - current = 0; + if (tabs.is_empty()) { + offset = 0; + max_drawn_tab = 0; previous = 0; - } - if (current >= tabs.size()) { - current = tabs.size() - 1; - } + } else { + offset = MIN(offset, tabs.size() - 1); + max_drawn_tab = MIN(max_drawn_tab, tabs.size() - 1); - _update_cache(); - _ensure_no_over_offset(); - if (scroll_to_selected && !tabs.is_empty()) { - ensure_tab_visible(current); + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } } + update(); update_minimum_size(); notify_property_list_changed(); + + if (is_tab_changing && is_inside_tree()) { + emit_signal(SNAME("tab_changed"), current); + } } Variant TabBar::get_drag_data(const Point2 &p_point) { if (!drag_to_rearrange_enabled) { - return Variant(); + return Control::get_drag_data(p_point); // Allow stuff like TabContainer to override it. } int tab_over = get_tab_idx_at_point(p_point); - if (tab_over < 0) { return Variant(); } @@ -1021,12 +1007,13 @@ Variant TabBar::get_drag_data(const Point2 &p_point) { drag_data["type"] = "tab_element"; drag_data["tab_element"] = tab_over; drag_data["from_path"] = get_path(); + return drag_data; } bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const { if (!drag_to_rearrange_enabled) { - return false; + return Control::can_drop_data(p_point, p_data); // Allow stuff like TabContainer to override it. } Dictionary d = p_data; @@ -1048,16 +1035,16 @@ bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const { } } } + return false; } void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { if (!drag_to_rearrange_enabled) { + Control::drop_data(p_point, p_data); // Allow stuff like TabContainer to override it. return; } - int hover_now = get_tab_idx_at_point(p_point); - Dictionary d = p_data; if (!d.has("type")) { return; @@ -1065,6 +1052,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { if (String(d["type"]) == "tab_element") { int tab_from_id = d["tab_element"]; + int hover_now = get_tab_idx_at_point(p_point); NodePath from_path = d["from_path"]; NodePath to_path = get_path(); @@ -1092,15 +1080,25 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { hover_now = get_tab_count(); } - // Workaround to ensure that tab_changed is emitted. - if (current == hover_now) { - current = -1; + from_tabs->remove_tab(tab_from_id); + tabs.insert(hover_now, moving_tab); + + if (tabs.size() > 1) { + if (current >= hover_now) { + current++; + } + if (previous >= hover_now) { + previous++; + } } - tabs.insert(hover_now, moving_tab); - from_tabs->remove_tab(tab_from_id); set_current_tab(hover_now); update_minimum_size(); + + if (tabs.size() == 1) { + emit_signal(SNAME("tab_selected"), 0); + emit_signal(SNAME("tab_changed"), 0); + } } } } @@ -1153,17 +1151,33 @@ bool TabBar::get_clip_tabs() const { return clip_tabs; } -void TabBar::move_tab(int from, int to) { - if (from == to) { +void TabBar::move_tab(int p_from, int p_to) { + if (p_from == p_to) { return; } - ERR_FAIL_INDEX(from, tabs.size()); - ERR_FAIL_INDEX(to, tabs.size()); + ERR_FAIL_INDEX(p_from, tabs.size()); + ERR_FAIL_INDEX(p_to, tabs.size()); + + Tab tab_from = tabs[p_from]; + tabs.remove_at(p_from); + tabs.insert(p_to, tab_from); - Tab tab_from = tabs[from]; - tabs.remove_at(from); - tabs.insert(to, tab_from); + if (current == p_from) { + current = p_to; + } else if (current > p_from && current <= p_to) { + current--; + } else if (current < p_from && current >= p_to) { + current++; + } + + if (previous == p_from) { + previous = p_to; + } else if (previous > p_from && previous >= p_to) { + previous--; + } else if (previous < p_from && previous <= p_to) { + previous++; + } _update_cache(); _ensure_no_over_offset(); @@ -1338,8 +1352,21 @@ TabBar::CloseButtonDisplayPolicy TabBar::get_tab_close_display_policy() const { return cb_displaypolicy; } -void TabBar::set_min_width(int p_width) { - min_width = p_width; +void TabBar::set_max_tab_width(int p_width) { + ERR_FAIL_COND(p_width < 0); + max_width = p_width; + + _update_cache(); + _ensure_no_over_offset(); + if (scroll_to_selected) { + ensure_tab_visible(current); + } + update(); + update_minimum_size(); +} + +int TabBar::get_max_tab_width() const { + return max_width; } void TabBar::set_scrolling_enabled(bool p_enabled) { @@ -1462,6 +1489,7 @@ void TabBar::_bind_methods() { ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabBar::is_tab_hidden); ClassDB::bind_method(D_METHOD("remove_tab", "tab_idx"), &TabBar::remove_tab); ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &TabBar::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>())); + ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabBar::get_tab_idx_at_point); ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabBar::set_tab_alignment); ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabBar::get_tab_alignment); ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabBar::set_clip_tabs); @@ -1473,6 +1501,8 @@ void TabBar::_bind_methods() { ClassDB::bind_method(D_METHOD("move_tab", "from", "to"), &TabBar::move_tab); ClassDB::bind_method(D_METHOD("set_tab_close_display_policy", "policy"), &TabBar::set_tab_close_display_policy); ClassDB::bind_method(D_METHOD("get_tab_close_display_policy"), &TabBar::get_tab_close_display_policy); + ClassDB::bind_method(D_METHOD("set_max_tab_width", "width"), &TabBar::set_max_tab_width); + ClassDB::bind_method(D_METHOD("get_max_tab_width"), &TabBar::get_max_tab_width); ClassDB::bind_method(D_METHOD("set_scrolling_enabled", "enabled"), &TabBar::set_scrolling_enabled); ClassDB::bind_method(D_METHOD("get_scrolling_enabled"), &TabBar::get_scrolling_enabled); ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabBar::set_drag_to_rearrange_enabled); @@ -1497,8 +1527,10 @@ void TabBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_tab_width", PROPERTY_HINT_RANGE, "0,99999,1"), "set_max_tab_width", "get_max_tab_width"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_rearrange_group"), "set_tabs_rearrange_group", "get_tabs_rearrange_group"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_to_selected"), "set_scroll_to_selected", "get_scroll_to_selected"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_with_rmb"), "set_select_with_rmb", "get_select_with_rmb"); diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index b428538570..0f2184aca7 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -98,7 +98,7 @@ private: CloseButtonDisplayPolicy cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER; int hover = -1; // Hovered tab. - int min_width = 0; + int max_width = 0; bool scrolling_enabled = true; bool drag_to_rearrange_enabled = false; bool scroll_to_selected = true; @@ -126,7 +126,6 @@ protected: Variant get_drag_data(const Point2 &p_point) override; bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override; void drop_data(const Point2 &p_point, const Variant &p_data) override; - int get_tab_idx_at_point(const Point2 &p_point) const; public: void add_tab(const String &p_str = "", const Ref<Texture2D> &p_icon = Ref<Texture2D>()); @@ -156,13 +155,15 @@ public: void set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon); Ref<Texture2D> get_tab_button_icon(int p_tab) const; + int get_tab_idx_at_point(const Point2 &p_point) const; + void set_tab_alignment(AlignmentMode p_alignment); AlignmentMode get_tab_alignment() const; void set_clip_tabs(bool p_clip_tabs); bool get_clip_tabs() const; - void move_tab(int from, int to); + void move_tab(int p_from, int p_to); void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy); CloseButtonDisplayPolicy get_tab_close_display_policy() const; @@ -197,7 +198,9 @@ public: bool get_select_with_rmb() const; void ensure_tab_visible(int p_idx); - void set_min_width(int p_width); + + void set_max_tab_width(int p_width); + int get_max_tab_width() const; Rect2 get_tab_rect(int p_tab) const; Size2 get_minimum_size() const override; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 4bd3686e7c..ee61c862b7 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -30,45 +30,17 @@ #include "tab_container.h" -#include "core/object/message_queue.h" -#include "core/string/translation.h" - #include "scene/gui/box_container.h" #include "scene/gui/label.h" #include "scene/gui/texture_rect.h" int TabContainer::_get_top_margin() const { - if (!tabs_visible) { - return 0; - } - - // Respect the minimum tab height. - Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected")); - Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected")); - Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled")); - - int tab_height = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height); - - // Font height or higher icon wins. - int content_height = 0; - - Vector<Control *> tabs = _get_tabs(); - for (int i = 0; i < tabs.size(); i++) { - content_height = MAX(content_height, text_buf[i]->get_size().y); - - Control *c = tabs[i]; - if (!c->has_meta("_tab_icon")) { - continue; - } - - Ref<Texture2D> tex = c->get_meta("_tab_icon"); - if (!tex.is_valid()) { - continue; - } - content_height = MAX(content_height, tex->get_size().height); + int height = 0; + if (tabs_visible && get_tab_count() > 0) { + height = tab_bar->get_minimum_size().height; } - return tab_height + content_height; + return height; } void TabContainer::gui_input(const Ref<InputEvent> &p_event) { @@ -114,77 +86,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { return; } } - - // Do not activate tabs when tabs is empty. - if (get_tab_count() == 0) { - return; - } - - Vector<Control *> tabs = _get_tabs(); - - // Handle navigation buttons. - if (buttons_visible_cache) { - int popup_ofs = 0; - if (popup) { - popup_ofs = menu->get_width(); - } - - Ref<Texture2D> increment = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement")); - if (is_layout_rtl()) { - if (pos.x < popup_ofs + decrement->get_width()) { - if (last_tab_cache < tabs.size() - 1) { - first_tab_cache += 1; - update(); - } - return; - } else if (pos.x < popup_ofs + increment->get_width() + decrement->get_width()) { - if (first_tab_cache > 0) { - first_tab_cache -= 1; - update(); - } - return; - } - } else { - if (pos.x > size.width - increment->get_width() - popup_ofs && pos.x) { - if (last_tab_cache < tabs.size() - 1) { - first_tab_cache += 1; - update(); - } - return; - } else if (pos.x > size.width - increment->get_width() - decrement->get_width() - popup_ofs) { - if (first_tab_cache > 0) { - first_tab_cache -= 1; - update(); - } - return; - } - } - } - - // Activate the clicked tab. - if (is_layout_rtl()) { - pos.x = size.width - pos.x; - } - - if (pos.x < tabs_ofs_cache) { - return; - } - - pos.x -= tabs_ofs_cache; - for (int i = first_tab_cache; i <= last_tab_cache; i++) { - if (get_tab_hidden(i)) { - continue; - } - int tab_width = _get_tab_width(i); - if (pos.x < tab_width) { - if (!get_tab_disabled(i)) { - set_current_tab(i); - } - break; - } - pos.x -= tab_width; - } } Ref<InputEventMouseMotion> mm = p_event; @@ -195,9 +96,8 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { // Mouse must be on tabs in the tab header area. if (pos.y > _get_top_margin()) { - if (menu_hovered || highlight_arrow > -1) { + if (menu_hovered) { menu_hovered = false; - highlight_arrow = -1; update(); } return; @@ -209,7 +109,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { if (pos.x <= menu->get_width()) { if (!menu_hovered) { menu_hovered = true; - highlight_arrow = -1; update(); return; } @@ -221,7 +120,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { if (pos.x >= size.width - menu->get_width()) { if (!menu_hovered) { menu_hovered = true; - highlight_arrow = -1; update(); return; } @@ -235,101 +133,26 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { return; } } - - // Do not activate tabs when tabs is empty. - if ((get_tab_count() == 0 || !buttons_visible_cache) && menu_hovered) { - highlight_arrow = -1; - update(); - return; - } - - int popup_ofs = 0; - if (popup) { - popup_ofs = menu->get_width(); - } - - Ref<Texture2D> increment = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement")); - - if (is_layout_rtl()) { - if (pos.x <= popup_ofs + decrement->get_width()) { - if (highlight_arrow != 1) { - highlight_arrow = 1; - update(); - } - } else if (pos.x <= popup_ofs + increment->get_width() + decrement->get_width()) { - if (highlight_arrow != 0) { - highlight_arrow = 0; - update(); - } - } else if (highlight_arrow > -1) { - highlight_arrow = -1; - update(); - } - } else { - if (pos.x >= size.width - increment->get_width() - popup_ofs) { - if (highlight_arrow != 1) { - highlight_arrow = 1; - update(); - } - } else if (pos.x >= size.width - increment->get_width() - decrement->get_width() - popup_ofs) { - if (highlight_arrow != 0) { - highlight_arrow = 0; - update(); - } - } else if (highlight_arrow > -1) { - highlight_arrow = -1; - update(); - } - } } } void TabContainer::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_RESIZED: { - Vector<Control *> tabs = _get_tabs(); - int side_margin = get_theme_constant(SNAME("side_margin")); - Ref<Texture2D> menu = get_theme_icon(SNAME("menu")); - Ref<Texture2D> increment = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement")); - int header_width = get_size().width - side_margin * 2; - - // Find the width of the header area. - Popup *popup = get_popup(); - if (popup) { - header_width -= menu->get_width(); - } - if (buttons_visible_cache) { - header_width -= increment->get_width() + decrement->get_width(); - } - if (popup || buttons_visible_cache) { - header_width += side_margin; + case NOTIFICATION_ENTER_TREE: { + // If some nodes happen to be renamed outside the tree, the tab names need to be updated manually. + if (get_tab_count() > 0) { + _refresh_tab_names(); } + } break; - // Find the width of all tabs after first_tab_cache. - int all_tabs_width = 0; - for (int i = first_tab_cache; i < tabs.size(); i++) { - int tab_width = _get_tab_width(i); - all_tabs_width += tab_width; - } - - // Check if tabs before first_tab_cache would fit into the header area. - for (int i = first_tab_cache - 1; i >= 0; i--) { - int tab_width = _get_tab_width(i); - - if (all_tabs_width + tab_width > header_width) { - break; - } - - all_tabs_width += tab_width; - first_tab_cache--; - } + case NOTIFICATION_READY: + case NOTIFICATION_RESIZED: { + _update_margins(); } break; + case NOTIFICATION_DRAW: { RID canvas = get_canvas_item(); Size2 size = get_size(); - bool rtl = is_layout_rtl(); // Draw only the tab area if the header is hidden. Ref<StyleBox> panel = get_theme_stylebox(SNAME("panel")); @@ -338,480 +161,171 @@ void TabContainer::_notification(int p_what) { return; } - Vector<Control *> tabs = _get_tabs(); - Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected")); - Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected")); - Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled")); - Ref<Texture2D> increment = get_theme_icon(SNAME("increment")); - Ref<Texture2D> increment_hl = get_theme_icon(SNAME("increment_highlight")); - Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement")); - Ref<Texture2D> decrement_hl = get_theme_icon(SNAME("decrement_highlight")); - Ref<Texture2D> menu = get_theme_icon(SNAME("menu")); - Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight")); - Color font_selected_color = get_theme_color(SNAME("font_selected_color")); - Color font_unselected_color = get_theme_color(SNAME("font_unselected_color")); - Color font_disabled_color = get_theme_color(SNAME("font_disabled_color")); - int side_margin = get_theme_constant(SNAME("side_margin")); - - // Find out start and width of the header area. - int header_x = side_margin; - int header_width = size.width - side_margin * 2; int header_height = _get_top_margin(); - Popup *popup = get_popup(); - if (popup) { - header_width -= menu->get_width(); - } - - // Check if all tabs would fit into the header area. - int all_tabs_width = 0; - for (int i = 0; i < tabs.size(); i++) { - if (get_tab_hidden(i)) { - continue; - } - int tab_width = _get_tab_width(i); - all_tabs_width += tab_width; - - if (all_tabs_width > header_width) { - // Not all tabs are visible at the same time - reserve space for navigation buttons. - buttons_visible_cache = true; - header_width -= decrement->get_width() + increment->get_width(); - break; - } else { - buttons_visible_cache = false; - } - } - // With buttons, a right side margin does not need to be respected. - if (popup || buttons_visible_cache) { - header_width += side_margin; - } - - if (!buttons_visible_cache) { - first_tab_cache = 0; - } - // Go through the visible tabs to find the width they occupy. - all_tabs_width = 0; - Vector<int> tab_widths; - for (int i = first_tab_cache; i < tabs.size(); i++) { - if (get_tab_hidden(i)) { - tab_widths.push_back(0); - continue; - } - int tab_width = _get_tab_width(i); - if (all_tabs_width + tab_width > header_width && tab_widths.size() > 0) { - break; - } - all_tabs_width += tab_width; - tab_widths.push_back(tab_width); - } + panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); - // Find the offset at which to draw tabs, according to the alignment. - switch (alignment) { - case ALIGNMENT_LEFT: - tabs_ofs_cache = header_x; - break; - case ALIGNMENT_CENTER: - tabs_ofs_cache = header_x + (header_width / 2) - (all_tabs_width / 2); - break; - case ALIGNMENT_RIGHT: - tabs_ofs_cache = header_x + header_width - all_tabs_width; - break; - } - - if (all_tabs_in_front) { - // Draw the tab area. - panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); - } - - // Draw unselected tabs in back - int x = 0; - int x_current = 0; - int index = 0; - for (int i = 0; i < tab_widths.size(); i++) { - index = i + first_tab_cache; - if (get_tab_hidden(index)) { - continue; - } - - int tab_width = tab_widths[i]; - if (index == current) { - x_current = x; - } else if (get_tab_disabled(index)) { - if (rtl) { - _draw_tab(tab_disabled, font_disabled_color, index, size.width - (tabs_ofs_cache + x) - tab_width); - } else { - _draw_tab(tab_disabled, font_disabled_color, index, tabs_ofs_cache + x); - } - } else { - if (rtl) { - _draw_tab(tab_unselected, font_unselected_color, index, size.width - (tabs_ofs_cache + x) - tab_width); - } else { - _draw_tab(tab_unselected, font_unselected_color, index, tabs_ofs_cache + x); - } - } + // Draw the popup menu. + if (get_popup()) { + Ref<Texture2D> menu = get_theme_icon(SNAME("menu")); + Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight")); - x += tab_width; - last_tab_cache = index; - } + int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width(); - if (!all_tabs_in_front) { - // Draw the tab area. - panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); - } - - // Draw selected tab in front. Only draw selected tab when it's in visible range. - if (tabs.size() > 0 && current - first_tab_cache < tab_widths.size() && current >= first_tab_cache) { - Ref<StyleBox> current_style_box = get_tab_disabled(current) ? tab_disabled : tab_selected; - if (rtl) { - _draw_tab(current_style_box, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]); - } else { - _draw_tab(current_style_box, font_selected_color, current, tabs_ofs_cache + x_current); - } - } - - // Draw the popup menu. - if (rtl) { - x = 0; - } else { - x = get_size().width; - } - if (popup) { - if (!rtl) { - x -= menu->get_width(); - } if (menu_hovered) { menu_hl->draw(get_canvas_item(), Size2(x, (header_height - menu_hl->get_height()) / 2)); } else { menu->draw(get_canvas_item(), Size2(x, (header_height - menu->get_height()) / 2)); } - if (rtl) { - x += menu->get_width(); - } - } - - // Draw the navigation buttons. - if (buttons_visible_cache) { - if (rtl) { - if (last_tab_cache < tabs.size() - 1) { - draw_texture(highlight_arrow == 1 ? decrement_hl : decrement, Point2(x, (header_height - increment->get_height()) / 2)); - } else { - draw_texture(decrement, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5)); - } - x += increment->get_width(); - - if (first_tab_cache > 0) { - draw_texture(highlight_arrow == 0 ? increment_hl : increment, Point2(x, (header_height - decrement->get_height()) / 2)); - } else { - draw_texture(increment, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5)); - } - x += decrement->get_width(); - } else { - x -= increment->get_width(); - if (last_tab_cache < tabs.size() - 1) { - draw_texture(highlight_arrow == 1 ? increment_hl : increment, Point2(x, (header_height - increment->get_height()) / 2)); - } else { - draw_texture(increment, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5)); - } - - x -= decrement->get_width(); - if (first_tab_cache > 0) { - draw_texture(highlight_arrow == 0 ? decrement_hl : decrement, Point2(x, (header_height - decrement->get_height()) / 2)); - } else { - draw_texture(decrement, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5)); - } - } } } break; + case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_THEME_CHANGED: { - Vector<Control *> tabs = _get_tabs(); - for (int i = 0; i < tabs.size(); i++) { - text_buf.write[i]->clear(); - } - _theme_changing = true; + theme_changing = true; call_deferred(SNAME("_on_theme_changed")); // Wait until all changed theme. } break; } } -void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) { - Control *control = get_tab_control(p_index); - RID canvas = get_canvas_item(); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); - int icon_text_distance = get_theme_constant(SNAME("icon_separation")); - int tab_width = _get_tab_width(p_index); - int header_height = _get_top_margin(); - - // Draw the tab background. - Rect2 tab_rect(p_x, 0, tab_width, header_height); - p_tab_style->draw(canvas, tab_rect); - - // Draw the tab contents. - String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name())); - - int x_content = tab_rect.position.x + p_tab_style->get_margin(SIDE_LEFT); - int top_margin = p_tab_style->get_margin(SIDE_TOP); - int y_center = top_margin + (tab_rect.size.y - p_tab_style->get_minimum_size().y) / 2; - - // Draw the tab icon. - if (control->has_meta("_tab_icon")) { - Ref<Texture2D> icon = control->get_meta("_tab_icon"); - if (icon.is_valid()) { - int y = y_center - (icon->get_height() / 2); - icon->draw(canvas, Point2i(x_content, y)); - if (!text.is_empty()) { - x_content += icon->get_width() + icon_text_distance; - } - } - } - - // Draw the tab text. - Point2i text_pos(x_content, y_center - text_buf[p_index]->get_size().y / 2); - if (outline_size > 0 && font_outline_color.a > 0) { - text_buf[p_index]->draw_outline(canvas, text_pos, outline_size, font_outline_color); - } - text_buf[p_index]->draw(canvas, text_pos, p_font_color); -} - -void TabContainer::_refresh_texts() { - text_buf.clear(); - Vector<Control *> tabs = _get_tabs(); - bool rtl = is_layout_rtl(); - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); - for (int i = 0; i < tabs.size(); i++) { - Control *control = Object::cast_to<Control>(tabs[i]); - String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name())); - - Ref<TextLine> name; - name.instantiate(); - name->set_direction(rtl ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); - name->add_string(text, font, font_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); - text_buf.push_back(name); - } -} - void TabContainer::_on_theme_changed() { - if (!_theme_changing) { + if (!theme_changing) { return; } - _refresh_texts(); - - update_minimum_size(); + tab_bar->add_theme_style_override(SNAME("tab_unselected"), get_theme_stylebox(SNAME("tab_unselected"))); + tab_bar->add_theme_style_override(SNAME("tab_selected"), get_theme_stylebox(SNAME("tab_selected"))); + tab_bar->add_theme_style_override(SNAME("tab_disabled"), get_theme_stylebox(SNAME("tab_disabled"))); + tab_bar->add_theme_icon_override(SNAME("increment"), get_theme_icon(SNAME("increment"))); + tab_bar->add_theme_icon_override(SNAME("increment_highlight"), get_theme_icon(SNAME("increment_highlight"))); + tab_bar->add_theme_icon_override(SNAME("decrement"), get_theme_icon(SNAME("decrement"))); + tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), get_theme_icon(SNAME("decrement_highlight"))); + tab_bar->add_theme_color_override(SNAME("font_selected_color"), get_theme_color(SNAME("font_selected_color"))); + tab_bar->add_theme_color_override(SNAME("font_unselected_color"), get_theme_color(SNAME("font_unselected_color"))); + tab_bar->add_theme_color_override(SNAME("font_disabled_color"), get_theme_color(SNAME("font_disabled_color"))); + tab_bar->add_theme_color_override(SNAME("font_outline_color"), get_theme_color(SNAME("font_outline_color"))); + tab_bar->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("font"))); + tab_bar->add_theme_constant_override(SNAME("font_size"), get_theme_constant(SNAME("font_size"))); + tab_bar->add_theme_constant_override(SNAME("icon_separation"), get_theme_constant(SNAME("icon_separation"))); + tab_bar->add_theme_constant_override(SNAME("outline_size"), get_theme_constant(SNAME("outline_size"))); + + _update_margins(); if (get_tab_count() > 0) { _repaint(); - update(); + } else { + update_minimum_size(); } - _theme_changing = false; + update(); + + theme_changing = false; } void TabContainer::_repaint() { Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel")); - Vector<Control *> tabs = _get_tabs(); - for (int i = 0; i < tabs.size(); i++) { - Control *c = tabs[i]; + Vector<Control *> controls = _get_tab_controls(); + int current = get_current_tab(); + + for (int i = 0; i < controls.size(); i++) { + Control *c = controls[i]; + if (i == current) { c->show(); c->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + if (tabs_visible) { c->set_offset(SIDE_TOP, _get_top_margin()); } + c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + sb->get_margin(SIDE_TOP)); c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + sb->get_margin(SIDE_LEFT)); c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - sb->get_margin(SIDE_RIGHT)); c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - sb->get_margin(SIDE_BOTTOM)); - } else { c->hide(); } } -} - -void TabContainer::_on_mouse_exited() { - if (menu_hovered || highlight_arrow > -1) { - menu_hovered = false; - highlight_arrow = -1; - update(); - } -} - -int TabContainer::_get_tab_width(int p_index) const { - ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0); - Control *control = get_tab_control(p_index); - if (!control || get_tab_hidden(p_index)) { - return 0; - } - - // Get the width of the text displayed on the tab. - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); - String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name())); - int width = font->get_string_size(text, font_size).width; - - // Add space for a tab icon. - if (control->has_meta("_tab_icon")) { - Ref<Texture2D> icon = control->get_meta("_tab_icon"); - if (icon.is_valid()) { - width += icon->get_width(); - if (!text.is_empty()) { - width += get_theme_constant(SNAME("icon_separation")); - } - } - } - - // Respect a minimum size. - Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected")); - Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected")); - Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled")); - if (get_tab_disabled(p_index)) { - width += tab_disabled->get_minimum_size().width; - } else if (p_index == current) { - width += tab_selected->get_minimum_size().width; - } else { - width += tab_unselected->get_minimum_size().width; - } - return width; + update_minimum_size(); } -Vector<Control *> TabContainer::_get_tabs() const { - Vector<Control *> controls; - for (int i = 0; i < get_child_count(); i++) { - Control *control = Object::cast_to<Control>(get_child(i)); - if (!control || control->is_set_as_top_level()) { - continue; - } - - controls.push_back(control); - } - return controls; -} +void TabContainer::_update_margins() { + int menu_width = get_theme_icon(SNAME("menu"))->get_width(); + int side_margin = get_theme_constant(SNAME("side_margin")); -void TabContainer::_child_renamed_callback() { - _refresh_texts(); - update(); -} + // Directly check for validity, to avoid errors when quitting. + bool has_popup = popup_obj_id.is_valid(); -void TabContainer::add_child_notify(Node *p_child) { - Container::add_child_notify(p_child); + if (get_tab_count() == 0) { + tab_bar->set_offset(SIDE_LEFT, 0); + tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0); - Control *c = Object::cast_to<Control>(p_child); - if (!c || c->is_set_as_top_level()) { return; } - _refresh_texts(); - call_deferred(SNAME("_repaint")); - update(); - - bool first = (_get_tabs().size() == 1); - if (first) { - current = 0; - previous = 0; - } - - p_child->connect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback)); - if (first && is_inside_tree()) { - emit_signal(SNAME("tab_changed"), current); - } -} - -void TabContainer::move_child_notify(Node *p_child) { - Container::move_child_notify(p_child); - - Control *c = Object::cast_to<Control>(p_child); - if (!c || c->is_set_as_top_level()) { - return; - } + switch (get_tab_alignment()) { + case TabBar::ALIGNMENT_LEFT: { + tab_bar->set_offset(SIDE_LEFT, side_margin); + tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0); + } break; - _update_current_tab(); - update(); -} + case TabBar::ALIGNMENT_CENTER: { + tab_bar->set_offset(SIDE_LEFT, 0); + tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0); + } break; -int TabContainer::get_tab_count() const { - return _get_tabs().size(); -} + case TabBar::ALIGNMENT_RIGHT: { + tab_bar->set_offset(SIDE_LEFT, 0); -void TabContainer::set_current_tab(int p_current) { - ERR_FAIL_INDEX(p_current, get_tab_count()); + if (has_popup) { + tab_bar->set_offset(SIDE_RIGHT, -menu_width); + return; + } - int pending_previous = current; - current = p_current; + int first_tab_pos = tab_bar->get_tab_rect(0).position.x; + Rect2 last_tab_rect = tab_bar->get_tab_rect(get_tab_count() - 1); + int total_tabs_width = last_tab_rect.position.x - first_tab_pos + last_tab_rect.size.width; - _repaint(); + // Calculate if all the tabs would still fit if the margin was present. + if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + side_margin) > get_size().width))) { + tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0); + } else { + tab_bar->set_offset(SIDE_RIGHT, -side_margin); + } + } break; - if (pending_previous == current) { - emit_signal(SNAME("tab_selected"), current); - } else { - previous = pending_previous; - emit_signal(SNAME("tab_selected"), current); - emit_signal(SNAME("tab_changed"), current); + case TabBar::ALIGNMENT_MAX: + break; // Can't happen, but silences warning. } - - update(); -} - -int TabContainer::get_current_tab() const { - return current; -} - -int TabContainer::get_previous_tab() const { - return previous; } -Control *TabContainer::get_tab_control(int p_idx) const { - Vector<Control *> tabs = _get_tabs(); - if (p_idx >= 0 && p_idx < tabs.size()) { - return tabs[p_idx]; - } else { - return nullptr; +void TabContainer::_on_mouse_exited() { + if (menu_hovered) { + menu_hovered = false; + update(); } } -Control *TabContainer::get_current_tab_control() const { - return get_tab_control(current); -} - -void TabContainer::remove_child_notify(Node *p_child) { - Container::remove_child_notify(p_child); +Vector<Control *> TabContainer::_get_tab_controls() const { + Vector<Control *> controls; + for (int i = 0; i < get_child_count(); i++) { + Control *control = Object::cast_to<Control>(get_child(i)); + if (!control || control->is_set_as_top_level() || control == tab_bar) { + continue; + } - Control *c = Object::cast_to<Control>(p_child); - if (!c || c->is_set_as_top_level()) { - return; + controls.push_back(control); } - // Defer the call because tab is not yet removed (remove_child_notify is called right before p_child is actually removed). - call_deferred(SNAME("_update_current_tab")); - - p_child->disconnect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback)); - - update(); -} - -void TabContainer::_update_current_tab() { - _refresh_texts(); - - int tc = get_tab_count(); - if (current >= tc) { - current = tc - 1; - } - if (current < 0) { - current = 0; - } else { - set_current_tab(current); - } + return controls; } -Variant TabContainer::get_drag_data(const Point2 &p_point) { +Variant TabContainer::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) { if (!drag_to_rearrange_enabled) { return Variant(); } int tab_over = get_tab_idx_at_point(p_point); - if (tab_over < 0) { return Variant(); } @@ -824,18 +338,20 @@ Variant TabContainer::get_drag_data(const Point2 &p_point) { tf->set_texture(icon); drag_preview->add_child(tf); } + Label *label = memnew(Label(get_tab_title(tab_over))); - drag_preview->add_child(label); set_drag_preview(drag_preview); + drag_preview->add_child(label); Dictionary drag_data; drag_data["type"] = "tabc_element"; drag_data["tabc_element"] = tab_over; drag_data["from_path"] = get_path(); + return drag_data; } -bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) const { +bool TabContainer::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const { if (!drag_to_rearrange_enabled) { return false; } @@ -851,7 +367,7 @@ bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) c if (from_path == to_path) { return true; } else if (get_tabs_rearrange_group() != -1) { - // drag and drop between other TabContainers + // Drag and drop between other TabContainers. Node *from_node = get_node(from_path); TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node); if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) { @@ -859,10 +375,11 @@ bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) c } } } + return false; } -void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) { +void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) { if (!drag_to_rearrange_enabled) { return; } @@ -882,85 +399,195 @@ void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) { if (hover_now < 0) { hover_now = get_tab_count() - 1; } - move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index()); - set_current_tab(hover_now); + + move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index(false)); + if (!is_tab_disabled(hover_now)) { + set_current_tab(hover_now); + } + } else if (get_tabs_rearrange_group() != -1) { - // drag and drop between TabContainers + // Drag and drop between TabContainers. Node *from_node = get_node(from_path); TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node); if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) { Control *moving_tabc = from_tabc->get_tab_control(tab_from_id); from_tabc->remove_child(moving_tabc); - add_child(moving_tabc, false, INTERNAL_MODE_FRONT); + add_child(moving_tabc, true); + if (hover_now < 0) { hover_now = get_tab_count() - 1; } - move_child(moving_tabc, get_tab_control(hover_now)->get_index()); - set_current_tab(hover_now); - emit_signal(SNAME("tab_changed"), hover_now); + + move_child(moving_tabc, get_tab_control(hover_now)->get_index(false)); + if (!is_tab_disabled(hover_now)) { + set_current_tab(hover_now); + } } } } - update(); } -int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const { - if (get_tab_count() == 0) { - return -1; +void TabContainer::_on_tab_changed(int p_tab) { + call_deferred(SNAME("_repaint")); + + emit_signal(SNAME("tab_changed"), p_tab); +} + +void TabContainer::_on_tab_selected(int p_tab) { + if (p_tab != get_previous_tab()) { + call_deferred(SNAME("_repaint")); + } + + emit_signal(SNAME("tab_selected"), p_tab); +} + +void TabContainer::_refresh_tab_names() { + Vector<Control *> controls = _get_tab_controls(); + for (int i = 0; i < controls.size(); i++) { + if (!controls[i]->has_meta("_tab_name") && String(controls[i]->get_name()) != get_tab_title(i)) { + tab_bar->set_tab_title(i, controls[i]->get_name()); + } } +} - // must be on tabs in the tab header area. - if (p_point.y > _get_top_margin()) { - return -1; +void TabContainer::add_child_notify(Node *p_child) { + if (p_child == tab_bar) { + return; + } + + Container::add_child_notify(p_child); + + Control *c = Object::cast_to<Control>(p_child); + if (!c || c->is_set_as_top_level()) { + return; } + c->hide(); + + tab_bar->add_tab(p_child->get_name()); - Size2 size = get_size(); - int button_ofs = 0; - int px = p_point.x; + _update_margins(); - if (is_layout_rtl()) { - px = size.width - px; + p_child->connect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names)); + + // TabBar won't emit the "tab_changed" signal when not inside the tree. + if (!is_inside_tree()) { + call_deferred("_repaint"); } +} - if (px < tabs_ofs_cache) { - return -1; +void TabContainer::move_child_notify(Node *p_child) { + if (p_child == tab_bar) { + return; } - Popup *popup = get_popup(); - if (popup) { - Ref<Texture2D> menu = get_theme_icon(SNAME("menu")); - button_ofs += menu->get_width(); + Container::move_child_notify(p_child); + + Control *c = Object::cast_to<Control>(p_child); + if (c && !c->is_set_as_top_level()) { + int old_idx = -1; + String tab_name = c->has_meta("_tab_name") ? String(c->get_meta("_tab_name")) : String(c->get_name()); + + // Find the previous tab index of the control. + for (int i = 0; i < get_tab_count(); i++) { + if (get_tab_title(i) == tab_name) { + old_idx = i; + break; + } + } + + tab_bar->move_tab(old_idx, get_tab_idx_from_control(c)); } - if (buttons_visible_cache) { - Ref<Texture2D> increment = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement")); - button_ofs += increment->get_width() + decrement->get_width(); +} + +void TabContainer::remove_child_notify(Node *p_child) { + if (p_child == tab_bar) { + return; } - if (px > size.width - button_ofs) { - return -1; + + Container::remove_child_notify(p_child); + + Control *c = Object::cast_to<Control>(p_child); + if (!c || c->is_set_as_top_level()) { + return; } - // get the tab at the point - Vector<Control *> tabs = _get_tabs(); - px -= tabs_ofs_cache; - for (int i = first_tab_cache; i <= last_tab_cache; i++) { - int tab_width = _get_tab_width(i); - if (px < tab_width) { + tab_bar->remove_tab(get_tab_idx_from_control(c)); + + _update_margins(); + + if (p_child->has_meta("_tab_name")) { + p_child->remove_meta("_tab_name"); + } + p_child->disconnect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names)); + + // TabBar won't emit the "tab_changed" signal when not inside the tree. + if (!is_inside_tree()) { + call_deferred("_repaint"); + } +} + +int TabContainer::get_tab_count() const { + return tab_bar->get_tab_count(); +} + +void TabContainer::set_current_tab(int p_current) { + tab_bar->set_current_tab(p_current); +} + +int TabContainer::get_current_tab() const { + return tab_bar->get_current_tab(); +} + +int TabContainer::get_previous_tab() const { + return tab_bar->get_previous_tab(); +} + +Control *TabContainer::get_tab_control(int p_idx) const { + Vector<Control *> controls = _get_tab_controls(); + if (p_idx >= 0 && p_idx < controls.size()) { + return controls[p_idx]; + } else { + return nullptr; + } +} + +Control *TabContainer::get_current_tab_control() const { + return get_tab_control(tab_bar->get_current_tab()); +} + +int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const { + return tab_bar->get_tab_idx_at_point(p_point); +} + +int TabContainer::get_tab_idx_from_control(Control *p_child) const { + ERR_FAIL_NULL_V(p_child, -1); + ERR_FAIL_COND_V(p_child->get_parent() != this, -1); + + Vector<Control *> controls = _get_tab_controls(); + for (int i = 0; i < controls.size(); i++) { + if (controls[i] == p_child) { return i; } - px -= tab_width; } + return -1; } -void TabContainer::set_tab_alignment(AlignmentMode p_alignment) { - ERR_FAIL_INDEX(p_alignment, 3); - alignment = p_alignment; - update(); +void TabContainer::set_tab_alignment(TabBar::AlignmentMode p_alignment) { + tab_bar->set_tab_alignment(p_alignment); + _update_margins(); } -TabContainer::AlignmentMode TabContainer::get_tab_alignment() const { - return alignment; +TabBar::AlignmentMode TabContainer::get_tab_alignment() const { + return tab_bar->get_tab_alignment(); +} + +void TabContainer::set_clip_tabs(bool p_clip_tabs) { + tab_bar->set_clip_tabs(p_clip_tabs); +} + +bool TabContainer::get_clip_tabs() const { + return tab_bar->get_clip_tabs(); } void TabContainer::set_tabs_visible(bool p_visible) { @@ -969,11 +596,12 @@ void TabContainer::set_tabs_visible(bool p_visible) { } tabs_visible = p_visible; + tab_bar->set_visible(tabs_visible); - Vector<Control *> tabs = _get_tabs(); - for (int i = 0; i < tabs.size(); i++) { - Control *c = tabs[i]; - if (p_visible) { + Vector<Control *> controls = _get_tab_controls(); + for (int i = 0; i < controls.size(); i++) { + Control *c = controls[i]; + if (tabs_visible) { c->set_offset(SIDE_TOP, _get_top_margin()); } else { c->set_offset(SIDE_TOP, 0); @@ -995,7 +623,8 @@ void TabContainer::set_all_tabs_in_front(bool p_in_front) { all_tabs_in_front = p_in_front; - update(); + remove_child(tab_bar); + add_child(tab_bar, false, all_tabs_in_front ? INTERNAL_MODE_FRONT : INTERNAL_MODE_BACK); } bool TabContainer::is_all_tabs_in_front() const { @@ -1005,95 +634,78 @@ bool TabContainer::is_all_tabs_in_front() const { void TabContainer::set_tab_title(int p_tab, const String &p_title) { Control *child = get_tab_control(p_tab); ERR_FAIL_COND(!child); - child->set_meta("_tab_name", p_title); - _refresh_texts(); - update(); -} -String TabContainer::get_tab_title(int p_tab) const { - Control *child = get_tab_control(p_tab); - ERR_FAIL_COND_V(!child, ""); - if (child->has_meta("_tab_name")) { - return child->get_meta("_tab_name"); + tab_bar->set_tab_title(p_tab, p_title); + + if (p_title == child->get_name()) { + if (child->has_meta("_tab_name")) { + child->remove_meta("_tab_name"); + } } else { - return child->get_name(); + child->set_meta("_tab_name", p_title); + } + + _update_margins(); + if (!get_clip_tabs()) { + update_minimum_size(); } } +String TabContainer::get_tab_title(int p_tab) const { + return tab_bar->get_tab_title(p_tab); +} + void TabContainer::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) { - Control *child = get_tab_control(p_tab); - ERR_FAIL_COND(!child); - child->set_meta("_tab_icon", p_icon); - update(); + tab_bar->set_tab_icon(p_tab, p_icon); + + _update_margins(); + _repaint(); } Ref<Texture2D> TabContainer::get_tab_icon(int p_tab) const { - Control *child = get_tab_control(p_tab); - ERR_FAIL_COND_V(!child, Ref<Texture2D>()); - if (child->has_meta("_tab_icon")) { - return child->get_meta("_tab_icon"); - } else { - return Ref<Texture2D>(); - } + return tab_bar->get_tab_icon(p_tab); } void TabContainer::set_tab_disabled(int p_tab, bool p_disabled) { - Control *child = get_tab_control(p_tab); - ERR_FAIL_COND(!child); - child->set_meta("_tab_disabled", p_disabled); - update(); -} + tab_bar->set_tab_disabled(p_tab, p_disabled); -bool TabContainer::get_tab_disabled(int p_tab) const { - Control *child = get_tab_control(p_tab); - ERR_FAIL_COND_V(!child, false); - if (child->has_meta("_tab_disabled")) { - return child->get_meta("_tab_disabled"); - } else { - return false; + _update_margins(); + if (!get_clip_tabs()) { + update_minimum_size(); } } +bool TabContainer::is_tab_disabled(int p_tab) const { + return tab_bar->is_tab_disabled(p_tab); +} + void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) { Control *child = get_tab_control(p_tab); ERR_FAIL_COND(!child); - child->set_meta("_tab_hidden", p_hidden); - update(); - for (int i = 0; i < get_tab_count(); i++) { - int try_tab = (p_tab + 1 + i) % get_tab_count(); - if (get_tab_disabled(try_tab) || get_tab_hidden(try_tab)) { - continue; - } - - set_current_tab(try_tab); - return; - } - //assumed no other tab can be switched to, just hide + tab_bar->set_tab_hidden(p_tab, p_hidden); child->hide(); -} -bool TabContainer::get_tab_hidden(int p_tab) const { - Control *child = get_tab_control(p_tab); - ERR_FAIL_COND_V(!child, false); - if (child->has_meta("_tab_hidden")) { - return child->get_meta("_tab_hidden"); - } else { - return false; + _update_margins(); + if (!get_clip_tabs()) { + update_minimum_size(); } } +bool TabContainer::is_tab_hidden(int p_tab) const { + return tab_bar->is_tab_hidden(p_tab); +} + void TabContainer::get_translatable_strings(List<String> *p_strings) const { - Vector<Control *> tabs = _get_tabs(); - for (int i = 0; i < tabs.size(); i++) { - Control *c = tabs[i]; + Vector<Control *> controls = _get_tab_controls(); + for (int i = 0; i < controls.size(); i++) { + Control *c = controls[i]; if (!c->has_meta("_tab_name")) { continue; } String name = c->get_meta("_tab_name"); - if (!name.is_empty()) { p_strings->push_back(name); } @@ -1103,9 +715,26 @@ void TabContainer::get_translatable_strings(List<String> *p_strings) const { Size2 TabContainer::get_minimum_size() const { Size2 ms; - Vector<Control *> tabs = _get_tabs(); - for (int i = 0; i < tabs.size(); i++) { - Control *c = tabs[i]; + if (tabs_visible) { + ms = tab_bar->get_minimum_size(); + + if (!get_clip_tabs()) { + if (get_popup()) { + ms.x += get_theme_icon(SNAME("menu"))->get_width(); + } + + int side_margin = get_theme_constant(SNAME("side_margin")); + if (side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER && + (get_tab_alignment() != TabBar::ALIGNMENT_RIGHT || !get_popup())) { + ms.x += side_margin; + } + } + } + + Vector<Control *> controls = _get_tab_controls(); + int max_control_height = 0; + for (int i = 0; i < controls.size(); i++) { + Control *c = controls[i]; if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size) { continue; @@ -1113,29 +742,30 @@ Size2 TabContainer::get_minimum_size() const { Size2 cms = c->get_combined_minimum_size(); ms.x = MAX(ms.x, cms.x); - ms.y = MAX(ms.y, cms.y); - } - - Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected")); - Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected")); - Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled")); - - if (tabs_visible) { - ms.y += MAX(MAX(tab_unselected->get_minimum_size().y, tab_selected->get_minimum_size().y), tab_disabled->get_minimum_size().y); - ms.y += _get_top_margin(); + max_control_height = MAX(max_control_height, cms.y); } + ms.y += max_control_height; - Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel")); - ms += sb->get_minimum_size(); + Size2 panel_ms = get_theme_stylebox(SNAME("panel"))->get_minimum_size(); + ms.x = MAX(ms.x, panel_ms.x); + ms.y += panel_ms.y; return ms; } void TabContainer::set_popup(Node *p_popup) { - ERR_FAIL_NULL(p_popup); + bool had_popup = get_popup(); + Popup *popup = Object::cast_to<Popup>(p_popup); popup_obj_id = popup ? popup->get_instance_id() : ObjectID(); - update(); + + if (had_popup != bool(popup)) { + update(); + _update_margins(); + if (!get_clip_tabs()) { + update_minimum_size(); + } + } } Popup *TabContainer::get_popup() const { @@ -1150,6 +780,7 @@ Popup *TabContainer::get_popup() const { popup_obj_id = ObjectID(); } } + return nullptr; } @@ -1162,15 +793,16 @@ bool TabContainer::get_drag_to_rearrange_enabled() const { } void TabContainer::set_tabs_rearrange_group(int p_group_id) { - tabs_rearrange_group = p_group_id; + tab_bar->set_tabs_rearrange_group(p_group_id); } int TabContainer::get_tabs_rearrange_group() const { - return tabs_rearrange_group; + return tab_bar->get_tabs_rearrange_group(); } void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) { use_hidden_tabs_for_min_size = p_use_hidden_tabs; + update_minimum_size(); } bool TabContainer::get_use_hidden_tabs_for_min_size() const { @@ -1194,6 +826,8 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_control", "tab_idx"), &TabContainer::get_tab_control); ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabContainer::set_tab_alignment); ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabContainer::get_tab_alignment); + ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabContainer::set_clip_tabs); + ClassDB::bind_method(D_METHOD("get_clip_tabs"), &TabContainer::get_clip_tabs); ClassDB::bind_method(D_METHOD("set_tabs_visible", "visible"), &TabContainer::set_tabs_visible); ClassDB::bind_method(D_METHOD("are_tabs_visible"), &TabContainer::are_tabs_visible); ClassDB::bind_method(D_METHOD("set_all_tabs_in_front", "is_front"), &TabContainer::set_all_tabs_in_front); @@ -1203,23 +837,25 @@ void TabContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabContainer::set_tab_icon); ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabContainer::get_tab_icon); ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabContainer::set_tab_disabled); - ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabContainer::get_tab_disabled); + ClassDB::bind_method(D_METHOD("is_tab_disabled", "tab_idx"), &TabContainer::is_tab_disabled); ClassDB::bind_method(D_METHOD("set_tab_hidden", "tab_idx", "hidden"), &TabContainer::set_tab_hidden); - ClassDB::bind_method(D_METHOD("get_tab_hidden", "tab_idx"), &TabContainer::get_tab_hidden); + ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabContainer::is_tab_hidden); ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabContainer::get_tab_idx_at_point); + ClassDB::bind_method(D_METHOD("get_tab_idx_from_control", "control"), &TabContainer::get_tab_idx_from_control); ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup); ClassDB::bind_method(D_METHOD("get_popup"), &TabContainer::get_popup); ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabContainer::set_drag_to_rearrange_enabled); ClassDB::bind_method(D_METHOD("get_drag_to_rearrange_enabled"), &TabContainer::get_drag_to_rearrange_enabled); ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group); ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group); - ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size); ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size); ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint); ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed); - ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &TabContainer::_get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TabContainer::_can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TabContainer::_drop_data_fw); ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab"))); ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab"))); @@ -1227,16 +863,21 @@ void TabContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "all_tabs_in_front"), "set_all_tabs_in_front", "is_all_tabs_in_front"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "tabs_rearrange_group"), "set_tabs_rearrange_group", "get_tabs_rearrange_group"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size"); - - BIND_ENUM_CONSTANT(ALIGNMENT_LEFT); - BIND_ENUM_CONSTANT(ALIGNMENT_CENTER); - BIND_ENUM_CONSTANT(ALIGNMENT_RIGHT); } TabContainer::TabContainer() { + tab_bar = memnew(TabBar); + tab_bar->set_drag_forwarding(this); + add_child(tab_bar, false, INTERNAL_MODE_FRONT); + tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE); + tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed)); + tab_bar->connect("tab_selected", callable_mp(this, &TabContainer::_on_tab_selected)); + connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited)); } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index ee1b3fea51..c54934b37b 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -33,65 +33,51 @@ #include "scene/gui/container.h" #include "scene/gui/popup.h" -#include "scene/resources/text_line.h" +#include "scene/gui/tab_bar.h" class TabContainer : public Container { GDCLASS(TabContainer, Container); -public: - enum AlignmentMode { - ALIGNMENT_LEFT, - ALIGNMENT_CENTER, - ALIGNMENT_RIGHT, - }; - -private: - int first_tab_cache = 0; - int tabs_ofs_cache = 0; - int last_tab_cache = 0; - int current = 0; - int previous = 0; + TabBar *tab_bar; bool tabs_visible = true; bool all_tabs_in_front = false; - bool buttons_visible_cache = false; bool menu_hovered = false; - int highlight_arrow = -1; - AlignmentMode alignment = ALIGNMENT_CENTER; - int _get_top_margin() const; mutable ObjectID popup_obj_id; bool drag_to_rearrange_enabled = false; bool use_hidden_tabs_for_min_size = false; - int tabs_rearrange_group = -1; + bool theme_changing = false; - Vector<Ref<TextLine>> text_buf; - Vector<Control *> _get_tabs() const; - int _get_tab_width(int p_index) const; - bool _theme_changing = false; + int _get_top_margin() const; + Vector<Control *> _get_tab_controls() const; void _on_theme_changed(); void _repaint(); + void _refresh_tab_names(); + void _update_margins(); void _on_mouse_exited(); - void _update_current_tab(); - void _draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x); - void _refresh_texts(); + void _on_tab_changed(int p_tab); + void _on_tab_selected(int p_tab); + + Variant _get_drag_data_fw(const Point2 &p_point, Control *p_from_control); + bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const; + void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control); protected: - void _child_renamed_callback(); virtual void gui_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); virtual void add_child_notify(Node *p_child) override; virtual void move_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; + static void _bind_methods(); - Variant get_drag_data(const Point2 &p_point) override; - bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override; - void drop_data(const Point2 &p_point, const Variant &p_data) override; +public: int get_tab_idx_at_point(const Point2 &p_point) const; + int get_tab_idx_from_control(Control *p_child) const; - static void _bind_methods(); + void set_tab_alignment(TabBar::AlignmentMode p_alignment); + TabBar::AlignmentMode get_tab_alignment() const; -public: - void set_tab_alignment(AlignmentMode p_alignment); - AlignmentMode get_tab_alignment() const; + void set_clip_tabs(bool p_clip_tabs); + bool get_clip_tabs() const; void set_tabs_visible(bool p_visible); bool are_tabs_visible() const; @@ -106,10 +92,10 @@ public: Ref<Texture2D> get_tab_icon(int p_tab) const; void set_tab_disabled(int p_tab, bool p_disabled); - bool get_tab_disabled(int p_tab) const; + bool is_tab_disabled(int p_tab) const; void set_tab_hidden(int p_tab, bool p_hidden); - bool get_tab_hidden(int p_tab) const; + bool is_tab_hidden(int p_tab) const; int get_tab_count() const; void set_current_tab(int p_current); @@ -139,6 +125,4 @@ public: TabContainer(); }; -VARIANT_ENUM_CAST(TabContainer::AlignmentMode); - #endif // TAB_CONTAINER_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 5295acce8f..3c80e3f987 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -432,32 +432,38 @@ void TextEdit::_notification(int p_what) { } _update_wrap_at_column(true); } break; + case NOTIFICATION_RESIZED: { _update_scrollbars(); _update_wrap_at_column(); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { if (is_visible()) { call_deferred(SNAME("_update_scrollbars")); call_deferred(SNAME("_update_wrap_at_column")); } } break; + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_THEME_CHANGED: { _update_caches(); _update_wrap_at_column(true); } break; + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { window_has_focus = true; draw_caret = true; update(); } break; + case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { window_has_focus = false; draw_caret = false; update(); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (scrolling && get_v_scroll() != target_v_scroll) { double target_y = target_v_scroll - get_v_scroll(); @@ -479,6 +485,7 @@ void TextEdit::_notification(int p_what) { set_physics_process_internal(false); } } break; + case NOTIFICATION_DRAW: { if (first_draw) { // Size may not be the final one, so attempts to ensure caret was visible may have failed. @@ -961,7 +968,7 @@ void TextEdit::_notification(int p_what) { // Give visual indication of empty selected line. if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) { - int char_w = font->get_char_size(' ', 0, font_size).width; + float char_w = font->get_char_size(' ', 0, font_size).width; if (rtl) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), selection_color); } else { @@ -1276,7 +1283,8 @@ void TextEdit::_notification(int p_what) { } // Carets. - const int caret_width = get_theme_constant(SNAME("caret_width")) * get_theme_default_base_scale(); + // Prevent carets from disappearing at theme scales below 1.0 (if the caret width is 1). + const int caret_width = get_theme_constant(SNAME("caret_width")) * MAX(1, get_theme_default_base_scale()); if (!clipped && caret.line == line && line_wrap_index == caret_wrap_index) { caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index); @@ -1427,6 +1435,7 @@ void TextEdit::_notification(int p_what) { } } } break; + case NOTIFICATION_FOCUS_ENTER: { if (caret_blink_enabled) { caret_blink_timer->start(); @@ -1458,6 +1467,7 @@ void TextEdit::_notification(int p_what) { DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true, -1, caret_start, caret_end); } } break; + case NOTIFICATION_FOCUS_EXIT: { if (caret_blink_enabled) { caret_blink_timer->stop(); @@ -1481,6 +1491,7 @@ void TextEdit::_notification(int p_what) { deselect(); } } break; + case MainLoop::NOTIFICATION_OS_IME_UPDATE: { if (has_focus()) { ime_text = DisplayServer::get_singleton()->ime_get_text(); @@ -1497,7 +1508,8 @@ void TextEdit::_notification(int p_what) { update(); } } break; - case Control::NOTIFICATION_DRAG_BEGIN: { + + case NOTIFICATION_DRAG_BEGIN: { selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; drag_action = true; dragging_minimap = false; @@ -1505,7 +1517,8 @@ void TextEdit::_notification(int p_what) { can_drag_minimap = false; click_select_held->stop(); } break; - case Control::NOTIFICATION_DRAG_END: { + + case NOTIFICATION_DRAG_END: { if (is_drag_successful()) { if (selection.drag_attempt) { selection.drag_attempt = false; @@ -2362,7 +2375,7 @@ void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { if (p_all_to_left) { int caret_current_column = caret.column; - caret.column = 0; + set_caret_column(0); _remove_text(caret.line, 0, caret.line, caret_current_column); return; } @@ -2908,15 +2921,20 @@ void TextEdit::_clear() { end_complex_operation(); return; } + // Cannot merge with above, as we are not part of the tree on creation. + int old_text_size = text.size(); + clear_undo_history(); text.clear(); - caret.column = 0; - caret.line = 0; + set_caret_line(0, false); + set_caret_column(0); caret.x_ofs = 0; caret.line_ofs = 0; caret.wrap_ofs = 0; caret.last_fit_x = 0; selection.active = false; + + emit_signal(SNAME("lines_edited_from"), old_text_size, 0); } void TextEdit::set_text(const String &p_text) { @@ -2975,14 +2993,16 @@ void TextEdit::set_line(int p_line, const String &p_new_text) { if (p_line < 0 || p_line >= text.size()) { return; } + begin_complex_operation(); _remove_text(p_line, 0, p_line, text[p_line].length()); _insert_text(p_line, 0, p_new_text); - if (caret.line == p_line) { - caret.column = MIN(caret.column, p_new_text.length()); + if (caret.line == p_line && caret.column > p_new_text.length()) { + set_caret_column(MIN(caret.column, p_new_text.length()), false); } if (has_selection() && p_line == selection.to_line && selection.to_column > text[p_line].length()) { selection.to_column = text[p_line].length(); } + end_complex_operation(); } String TextEdit::get_line(int p_line) const { @@ -3037,8 +3057,10 @@ void TextEdit::swap_lines(int p_from_line, int p_to_line) { String tmp = get_line(p_from_line); String tmp2 = get_line(p_to_line); + begin_complex_operation(); set_line(p_to_line, tmp); set_line(p_from_line, tmp2); + end_complex_operation(); } void TextEdit::insert_line_at(int p_at, const String &p_text) { @@ -3047,7 +3069,7 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) { _insert_text(p_at, 0, p_text + "\n"); if (caret.line >= p_at) { // offset caret when located after inserted line - ++caret.line; + set_caret_line(caret.line + 1, false); } if (has_selection()) { if (selection.from_line >= p_at) { @@ -3952,6 +3974,7 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_ } } } + bool caret_moved = caret.line != p_line; caret.line = p_line; int n_col = _get_char_pos_for_line(caret.last_fit_x, p_line, p_wrap_index); @@ -3965,15 +3988,16 @@ void TextEdit::set_caret_line(int p_line, bool p_adjust_viewport, bool p_can_be_ n_col -= 1; } } + caret_moved = (caret_moved || caret.column != n_col); caret.column = n_col; - if (p_adjust_viewport) { + if (is_inside_tree() && p_adjust_viewport) { adjust_viewport_to_caret(); } setting_caret_line = false; - if (!caret_pos_dirty) { + if (caret_moved && !caret_pos_dirty) { if (is_inside_tree()) { MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed"); } @@ -3990,6 +4014,7 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport) { p_col = 0; } + bool caret_moved = caret.column != p_col; caret.column = p_col; if (caret.column > get_line(caret.line).length()) { caret.column = get_line(caret.line).length(); @@ -3997,11 +4022,11 @@ void TextEdit::set_caret_column(int p_col, bool p_adjust_viewport) { caret.last_fit_x = _get_column_x_offset_for_line(caret.column, caret.line); - if (p_adjust_viewport) { + if (is_inside_tree() && p_adjust_viewport) { adjust_viewport_to_caret(); } - if (!caret_pos_dirty) { + if (caret_moved && !caret_pos_dirty) { if (is_inside_tree()) { MessageQueue::get_singleton()->push_call(this, "_emit_caret_changed"); } @@ -4444,7 +4469,11 @@ int TextEdit::get_visible_line_count() const { int TextEdit::get_visible_line_count_in_range(int p_from_line, int p_to_line) const { ERR_FAIL_INDEX_V(p_from_line, text.size(), 0); ERR_FAIL_INDEX_V(p_to_line, text.size(), 0); - ERR_FAIL_COND_V(p_from_line > p_to_line, 0); + + // So we can handle inputs in whatever order + if (p_from_line > p_to_line) { + SWAP(p_from_line, p_to_line); + } /* Returns the total number of (lines + wrapped - hidden). */ if (!_is_hiding_enabled() && get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) { @@ -5639,8 +5668,10 @@ void TextEdit::_generate_context_menu() { if (editable) { menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_paste") : Key::NONE); } - menu->add_separator(); - if (is_selecting_enabled()) { + if (selecting_enabled || editable) { + menu->add_separator(); + } + if (selecting_enabled) { menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : Key::NONE); } if (editable) { @@ -6554,7 +6585,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li emit_signal(SNAME("lines_edited_from"), p_to_line, p_from_line); } -TextEdit::TextEdit() { +TextEdit::TextEdit(const String &p_placeholder) { placeholder_data_buf.instantiate(); clear(); @@ -6596,5 +6627,7 @@ TextEdit::TextEdit() { undo_stack_max_size = GLOBAL_GET("gui/common/text_edit_undo_stack_max_size"); + set_placeholder(p_placeholder); + set_editable(true); } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 83a63ae40a..6deaf76e5e 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -940,7 +940,7 @@ public: void set_draw_spaces(bool p_enabled); bool is_drawing_spaces() const; - TextEdit(); + TextEdit(const String &p_placeholder = String()); }; VARIANT_ENUM_CAST(TextEdit::CaretType); diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index a8cdeb44f5..ecdf55caf0 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -29,84 +29,87 @@ /*************************************************************************/ #include "texture_rect.h" + #include "core/core_string_names.h" #include "servers/rendering_server.h" void TextureRect::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - if (texture.is_null()) { - return; - } - - Size2 size; - Point2 offset; - Rect2 region; - bool tile = false; - - switch (stretch_mode) { - case STRETCH_SCALE: { - size = get_size(); - } break; - case STRETCH_TILE: { - size = get_size(); - tile = true; - } break; - case STRETCH_KEEP: { - size = texture->get_size(); - } break; - case STRETCH_KEEP_CENTERED: { - offset = (get_size() - texture->get_size()) / 2; - size = texture->get_size(); - } break; - case STRETCH_KEEP_ASPECT_CENTERED: - case STRETCH_KEEP_ASPECT: { - size = get_size(); - int tex_width = texture->get_width() * size.height / texture->get_height(); - int tex_height = size.height; - - if (tex_width > size.width) { - tex_width = size.width; - tex_height = texture->get_height() * tex_width / texture->get_width(); - } - - if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { - offset.x += (size.width - tex_width) / 2; - offset.y += (size.height - tex_height) / 2; - } - - size.width = tex_width; - size.height = tex_height; - } break; - case STRETCH_KEEP_ASPECT_COVERED: { - size = get_size(); - - Size2 tex_size = texture->get_size(); - Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height); - float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height; - Size2 scaled_tex_size = tex_size * scale; - - region.position = ((scaled_tex_size - size) / scale).abs() / 2.0f; - region.size = size / scale; - } break; - } - - Ref<AtlasTexture> p_atlas = texture; - - if (p_atlas.is_valid() && region.has_no_area()) { - Size2 scale_size(size.width / texture->get_width(), size.height / texture->get_height()); - - offset.width += hflip ? p_atlas->get_margin().get_position().width * scale_size.width * 2 : 0; - offset.height += vflip ? p_atlas->get_margin().get_position().height * scale_size.height * 2 : 0; - } - - size.width *= hflip ? -1.0f : 1.0f; - size.height *= vflip ? -1.0f : 1.0f; - - if (region.has_no_area()) { - draw_texture_rect(texture, Rect2(offset, size), tile); - } else { - draw_texture_rect_region(texture, Rect2(offset, size), region); - } + switch (p_what) { + case NOTIFICATION_DRAW: { + if (texture.is_null()) { + return; + } + + Size2 size; + Point2 offset; + Rect2 region; + bool tile = false; + + switch (stretch_mode) { + case STRETCH_SCALE: { + size = get_size(); + } break; + case STRETCH_TILE: { + size = get_size(); + tile = true; + } break; + case STRETCH_KEEP: { + size = texture->get_size(); + } break; + case STRETCH_KEEP_CENTERED: { + offset = (get_size() - texture->get_size()) / 2; + size = texture->get_size(); + } break; + case STRETCH_KEEP_ASPECT_CENTERED: + case STRETCH_KEEP_ASPECT: { + size = get_size(); + int tex_width = texture->get_width() * size.height / texture->get_height(); + int tex_height = size.height; + + if (tex_width > size.width) { + tex_width = size.width; + tex_height = texture->get_height() * tex_width / texture->get_width(); + } + + if (stretch_mode == STRETCH_KEEP_ASPECT_CENTERED) { + offset.x += (size.width - tex_width) / 2; + offset.y += (size.height - tex_height) / 2; + } + + size.width = tex_width; + size.height = tex_height; + } break; + case STRETCH_KEEP_ASPECT_COVERED: { + size = get_size(); + + Size2 tex_size = texture->get_size(); + Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height); + float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height; + Size2 scaled_tex_size = tex_size * scale; + + region.position = ((scaled_tex_size - size) / scale).abs() / 2.0f; + region.size = size / scale; + } break; + } + + Ref<AtlasTexture> p_atlas = texture; + + if (p_atlas.is_valid() && region.has_no_area()) { + Size2 scale_size(size.width / texture->get_width(), size.height / texture->get_height()); + + offset.width += hflip ? p_atlas->get_margin().get_position().width * scale_size.width * 2 : 0; + offset.height += vflip ? p_atlas->get_margin().get_position().height * scale_size.height * 2 : 0; + } + + size.width *= hflip ? -1.0f : 1.0f; + size.height *= vflip ? -1.0f : 1.0f; + + if (region.has_no_area()) { + draw_texture_rect(texture, Rect2(offset, size), tile); + } else { + draw_texture_rect_region(texture, Rect2(offset, size), region); + } + } break; } } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index a36eaaa0ee..ff8d2b88b1 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -37,10 +37,9 @@ #include "core/os/os.h" #include "core/string/print_string.h" #include "core/string/translation.h" +#include "scene/gui/box_container.h" #include "scene/main/window.h" -#include "box_container.h" - #include <limits.h> Size2 TreeItem::Cell::get_icon_size() const { @@ -1187,7 +1186,7 @@ void recursive_call_aux(TreeItem *p_item, const StringName &p_method, const Vari if (!p_item) { return; } - p_item->call(p_method, p_args, p_argcount, r_error); + p_item->callp(p_method, p_args, p_argcount, r_error); TreeItem *c = p_item->get_first_child(); while (c) { recursive_call_aux(c, p_method, p_args, p_argcount, r_error); @@ -1702,8 +1701,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 bool skip = (p_item == root && hide_root); if (!skip && (p_pos.y + label_h - cache.offset.y) > 0) { - //draw separation. - //if (p_item->get_parent()!=root || !hide_root) + // Draw separation. ERR_FAIL_COND_V(cache.font.is_null(), -1); @@ -2260,11 +2258,6 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c emit_signal(SNAME("item_selected")); emitted_row = true; } - /* - if (p_col==i) - p_current->selected_signal.call(p_col); - */ - } else if (c.selected) { if (p_selected != p_current) { // Deselect other rows. @@ -3293,8 +3286,21 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } else { Rect2 rect = get_selected()->get_meta("__focus_rect"); Point2 mpos = b->get_position(); + int icon_size_x = 0; + Ref<Texture2D> icon = get_selected()->get_icon(selected_col); + if (icon.is_valid()) { + Rect2i icon_region = get_selected()->get_icon_region(selected_col); + if (icon_region == Rect2i()) { + icon_size_x = icon->get_width(); + } else { + icon_size_x = icon_region.size.width; + } + } + // Icon is treated as if it is outside of the rect so that double clicking on it will emit the item_double_clicked signal. if (rtl) { - mpos.x = get_size().width - mpos.x; + mpos.x = get_size().width - (mpos.x + icon_size_x); + } else { + mpos.x -= icon_size_x; } if (rect.has_point(mpos)) { if (!edit_selected()) { @@ -3636,178 +3642,187 @@ int Tree::_get_title_button_height() const { } void Tree::_notification(int p_what) { - if (p_what == NOTIFICATION_FOCUS_ENTER) { - if (get_viewport()) { - focus_in_id = get_viewport()->get_processed_events_count(); - } - } - if (p_what == NOTIFICATION_MOUSE_EXIT) { - if (cache.hover_type != Cache::CLICK_NONE) { - cache.hover_type = Cache::CLICK_NONE; - update(); - } - } - - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - drag_touching = false; - } + switch (p_what) { + case NOTIFICATION_FOCUS_ENTER: { + if (get_viewport()) { + focus_in_id = get_viewport()->get_processed_events_count(); + } + } break; - if (p_what == NOTIFICATION_ENTER_TREE) { - update_cache(); - } - if (p_what == NOTIFICATION_DRAG_END) { - drop_mode_flags = 0; - scrolling = false; - set_physics_process_internal(false); - update(); - } - if (p_what == NOTIFICATION_DRAG_BEGIN) { - single_select_defer = nullptr; - if (cache.scroll_speed > 0) { - scrolling = true; - set_physics_process_internal(true); - } - } - if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - if (drag_touching) { - if (drag_touching_deaccel) { - float pos = v_scroll->get_value(); - pos += drag_speed * get_physics_process_delta_time(); + case NOTIFICATION_MOUSE_EXIT: { + if (cache.hover_type != Cache::CLICK_NONE) { + cache.hover_type = Cache::CLICK_NONE; + update(); + } + } break; - bool turnoff = false; - if (pos < 0) { - pos = 0; - turnoff = true; - set_physics_process_internal(false); - drag_touching = false; - drag_touching_deaccel = false; - } - if (pos > (v_scroll->get_max() - v_scroll->get_page())) { - pos = v_scroll->get_max() - v_scroll->get_page(); - turnoff = true; - } + case NOTIFICATION_VISIBILITY_CHANGED: { + drag_touching = false; + } break; - v_scroll->set_value(pos); - float sgn = drag_speed < 0 ? -1 : 1; - float val = Math::abs(drag_speed); - val -= 1000 * get_physics_process_delta_time(); + case NOTIFICATION_ENTER_TREE: { + update_cache(); + } break; - if (val < 0) { - turnoff = true; - } - drag_speed = sgn * val; + case NOTIFICATION_DRAG_END: { + drop_mode_flags = 0; + scrolling = false; + set_physics_process_internal(false); + update(); + } break; - if (turnoff) { - set_physics_process_internal(false); - drag_touching = false; - drag_touching_deaccel = false; - } + case NOTIFICATION_DRAG_BEGIN: { + single_select_defer = nullptr; + if (cache.scroll_speed > 0) { + scrolling = true; + set_physics_process_internal(true); } - } + } break; - Point2 mouse_position = get_viewport()->get_mouse_position() - get_global_position(); - if (scrolling && get_rect().grow(cache.scroll_border).has_point(mouse_position)) { - Point2 point; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (drag_touching) { + if (drag_touching_deaccel) { + float pos = v_scroll->get_value(); + pos += drag_speed * get_physics_process_delta_time(); - if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < cache.scroll_border)) { - point.x = mouse_position.x - cache.scroll_border; - } else if (ABS(mouse_position.x - get_size().width) < cache.scroll_border) { - point.x = mouse_position.x - (get_size().width - cache.scroll_border); - } + bool turnoff = false; + if (pos < 0) { + pos = 0; + turnoff = true; + set_physics_process_internal(false); + drag_touching = false; + drag_touching_deaccel = false; + } + if (pos > (v_scroll->get_max() - v_scroll->get_page())) { + pos = v_scroll->get_max() - v_scroll->get_page(); + turnoff = true; + } + + v_scroll->set_value(pos); + float sgn = drag_speed < 0 ? -1 : 1; + float val = Math::abs(drag_speed); + val -= 1000 * get_physics_process_delta_time(); - if ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < cache.scroll_border)) { - point.y = mouse_position.y - cache.scroll_border; - } else if (ABS(mouse_position.y - get_size().height) < cache.scroll_border) { - point.y = mouse_position.y - (get_size().height - cache.scroll_border); + if (val < 0) { + turnoff = true; + } + drag_speed = sgn * val; + + if (turnoff) { + set_physics_process_internal(false); + drag_touching = false; + drag_touching_deaccel = false; + } + } } - point *= cache.scroll_speed * get_physics_process_delta_time(); - point += get_scroll(); - h_scroll->set_value(point.x); - v_scroll->set_value(point.y); - } - } + Point2 mouse_position = get_viewport()->get_mouse_position() - get_global_position(); + if (scrolling && get_rect().grow(cache.scroll_border).has_point(mouse_position)) { + Point2 point; - if (p_what == NOTIFICATION_DRAW) { - update_cache(); - update_scrollbars(); - RID ci = get_canvas_item(); + if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < cache.scroll_border)) { + point.x = mouse_position.x - cache.scroll_border; + } else if (ABS(mouse_position.x - get_size().width) < cache.scroll_border) { + point.x = mouse_position.x - (get_size().width - cache.scroll_border); + } - Ref<StyleBox> bg = cache.bg; - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); + if ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < cache.scroll_border)) { + point.y = mouse_position.y - cache.scroll_border; + } else if (ABS(mouse_position.y - get_size().height) < cache.scroll_border) { + point.y = mouse_position.y - (get_size().height - cache.scroll_border); + } - Point2 draw_ofs; - draw_ofs += bg->get_offset(); - Size2 draw_size = get_size() - bg->get_minimum_size(); - if (h_scroll->is_visible()) { - draw_size.width -= h_scroll->get_minimum_size().width; - } + point *= cache.scroll_speed * get_physics_process_delta_time(); + point += get_scroll(); + h_scroll->set_value(point.x); + v_scroll->set_value(point.y); + } + } break; - bg->draw(ci, Rect2(Point2(), get_size())); + case NOTIFICATION_DRAW: { + update_cache(); + update_scrollbars(); + RID ci = get_canvas_item(); + + Ref<StyleBox> bg = cache.bg; + Color font_outline_color = get_theme_color(SNAME("font_outline_color")); + int outline_size = get_theme_constant(SNAME("outline_size")); + + Point2 draw_ofs; + draw_ofs += bg->get_offset(); + Size2 draw_size = get_size() - bg->get_minimum_size(); + if (h_scroll->is_visible()) { + draw_size.width -= h_scroll->get_minimum_size().width; + } - int tbh = _get_title_button_height(); + bg->draw(ci, Rect2(Point2(), get_size())); - draw_ofs.y += tbh; - draw_size.y -= tbh; + int tbh = _get_title_button_height(); - cache.rtl = is_layout_rtl(); + draw_ofs.y += tbh; + draw_size.y -= tbh; - if (root && get_size().x > 0 && get_size().y > 0) { - draw_item(Point2(), draw_ofs, draw_size, root); - } + cache.rtl = is_layout_rtl(); - if (show_column_titles) { - //title buttons - int ofs2 = cache.bg->get_margin(SIDE_LEFT); - for (int i = 0; i < columns.size(); i++) { - Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? cache.title_button_hover : cache.title_button); - Ref<Font> f = cache.tb_font; - Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh); - if (cache.rtl) { - tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x; - } - sb->draw(ci, tbrect); - ofs2 += tbrect.size.width; - //text - int clip_w = tbrect.size.width - sb->get_minimum_size().width; - columns.write[i].text_buf->set_width(clip_w); - - Vector2 text_pos = tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2); - if (outline_size > 0 && font_outline_color.a > 0) { - columns[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); - } - columns[i].text_buf->draw(ci, text_pos, cache.title_button_color); + if (root && get_size().x > 0 && get_size().y > 0) { + draw_item(Point2(), draw_ofs, draw_size, root); } - } - // Draw the background focus outline last, so that it is drawn in front of the section headings. - // Otherwise, section heading backgrounds can appear to be in front of the focus outline when scrolling. - if (has_focus()) { - RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true); - const Ref<StyleBox> bg_focus = get_theme_stylebox(SNAME("bg_focus")); - bg_focus->draw(ci, Rect2(Point2(), get_size())); - RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false); - } - } + if (show_column_titles) { + //title buttons + int ofs2 = cache.bg->get_margin(SIDE_LEFT); + for (int i = 0; i < columns.size(); i++) { + Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? cache.title_button_hover : cache.title_button); + Ref<Font> f = cache.tb_font; + Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh); + if (cache.rtl) { + tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x; + } + sb->draw(ci, tbrect); + ofs2 += tbrect.size.width; + //text + int clip_w = tbrect.size.width - sb->get_minimum_size().width; + columns.write[i].text_buf->set_width(clip_w); + + Vector2 text_pos = tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2); + if (outline_size > 0 && font_outline_color.a > 0) { + columns[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + columns[i].text_buf->draw(ci, text_pos, cache.title_button_color); + } + } - if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || p_what == NOTIFICATION_TRANSLATION_CHANGED) { - update_cache(); - _update_all(); - } + // Draw the background focus outline last, so that it is drawn in front of the section headings. + // Otherwise, section heading backgrounds can appear to be in front of the focus outline when scrolling. + if (has_focus()) { + RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true); + const Ref<StyleBox> bg_focus = get_theme_stylebox(SNAME("bg_focus")); + bg_focus->draw(ci, Rect2(Point2(), get_size())); + RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false); + } + } break; - if (p_what == NOTIFICATION_RESIZED || p_what == NOTIFICATION_TRANSFORM_CHANGED) { - if (popup_edited_item != nullptr) { - Rect2 rect = popup_edited_item->get_meta("__focus_rect"); - Vector2 ofs(0, (text_editor->get_size().height - rect.size.height) / 2); - Point2i textedpos = get_global_position() + rect.position - ofs; + case NOTIFICATION_THEME_CHANGED: + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: + case NOTIFICATION_TRANSLATION_CHANGED: { + update_cache(); + _update_all(); + } break; - if (cache.text_editor_position != textedpos) { - cache.text_editor_position = textedpos; - text_editor->set_position(textedpos); - value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height)); + case NOTIFICATION_RESIZED: + case NOTIFICATION_TRANSFORM_CHANGED: { + if (popup_edited_item != nullptr) { + Rect2 rect = popup_edited_item->get_meta("__focus_rect"); + Vector2 ofs(0, (text_editor->get_size().height - rect.size.height) / 2); + Point2i textedpos = get_global_position() + rect.position - ofs; + + if (cache.text_editor_position != textedpos) { + cache.text_editor_position = textedpos; + text_editor->set_position(textedpos); + value_editor->set_position(textedpos + Point2i(0, text_editor->get_size().height)); + } } - } + } break; } } @@ -4057,10 +4072,6 @@ int Tree::get_edited_column() const { } TreeItem *Tree::get_next_selected(TreeItem *p_item) { - /* - if (!p_item) - return nullptr; - */ if (!root) { return nullptr; } diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp index 1f2a8c8aa1..d7c76aa070 100644 --- a/scene/gui/video_stream_player.cpp +++ b/scene/gui/video_stream_player.cpp @@ -134,7 +134,6 @@ void VideoStreamPlayer::_notification(int p_notification) { if (stream.is_valid() && autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } - } break; case NOTIFICATION_EXIT_TREE: { @@ -162,7 +161,6 @@ void VideoStreamPlayer::_notification(int p_notification) { if (!playback->is_playing()) { emit_signal(SceneStringNames::get_singleton()->finished); } - } break; case NOTIFICATION_DRAW: { @@ -175,10 +173,9 @@ void VideoStreamPlayer::_notification(int p_notification) { Size2 s = expand ? get_size() : texture->get_size(); draw_texture_rect(texture, Rect2(Point2(), s), false); - } break; - }; -}; + } +} Size2 VideoStreamPlayer::get_minimum_size() const { if (!expand && !texture.is_null()) { @@ -243,11 +240,11 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) { if (!expand) { update_minimum_size(); } -}; +} Ref<VideoStream> VideoStreamPlayer::get_stream() const { return stream; -}; +} void VideoStreamPlayer::play() { ERR_FAIL_COND(!is_inside_tree()); @@ -257,10 +254,8 @@ void VideoStreamPlayer::play() { playback->stop(); playback->play(); set_process_internal(true); - // AudioServer::get_singleton()->stream_set_active(stream_rid,true); - // AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); last_audio_time = 0; -}; +} void VideoStreamPlayer::stop() { if (!is_inside_tree()) { @@ -271,11 +266,10 @@ void VideoStreamPlayer::stop() { } playback->stop(); - // AudioServer::get_singleton()->stream_set_active(stream_rid,false); resampler.flush(); set_process_internal(false); last_audio_time = 0; -}; +} bool VideoStreamPlayer::is_playing() const { if (playback.is_null()) { @@ -283,16 +277,16 @@ bool VideoStreamPlayer::is_playing() const { } return playback->is_playing(); -}; +} void VideoStreamPlayer::set_paused(bool p_paused) { paused = p_paused; if (playback.is_valid()) { playback->set_paused(p_paused); set_process_internal(!p_paused); - }; + } last_audio_time = 0; -}; +} bool VideoStreamPlayer::is_paused() const { return paused; @@ -316,11 +310,11 @@ int VideoStreamPlayer::get_audio_track() const { void VideoStreamPlayer::set_volume(float p_vol) { volume = p_vol; -}; +} float VideoStreamPlayer::get_volume() const { return volume; -}; +} void VideoStreamPlayer::set_volume_db(float p_db) { if (p_db < -79) { @@ -328,7 +322,7 @@ void VideoStreamPlayer::set_volume_db(float p_db) { } else { set_volume(Math::db2linear(p_db)); } -}; +} float VideoStreamPlayer::get_volume_db() const { if (volume == 0) { @@ -336,21 +330,21 @@ float VideoStreamPlayer::get_volume_db() const { } else { return Math::linear2db(volume); } -}; +} String VideoStreamPlayer::get_stream_name() const { if (stream.is_null()) { return "<No Stream>"; } return stream->get_name(); -}; +} float VideoStreamPlayer::get_stream_position() const { if (playback.is_null()) { return 0; } return playback->get_playback_position(); -}; +} void VideoStreamPlayer::set_stream_position(float p_position) { if (playback.is_valid()) { @@ -368,14 +362,14 @@ Ref<Texture2D> VideoStreamPlayer::get_video_texture() const { void VideoStreamPlayer::set_autoplay(bool p_enable) { autoplay = p_enable; -}; +} bool VideoStreamPlayer::has_autoplay() const { return autoplay; -}; +} void VideoStreamPlayer::set_bus(const StringName &p_bus) { - //if audio is active, must lock this + // If audio is active, must lock this. AudioServer::get_singleton()->lock(); bus = p_bus; AudioServer::get_singleton()->unlock(); @@ -449,7 +443,6 @@ void VideoStreamPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_track", PROPERTY_HINT_RANGE, "0,128,1"), "set_audio_track", "get_audio_track"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "VideoStream"), "set_stream", "get_stream"); - //ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), "set_loop", "has_loop") ; ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01"), "set_volume_db", "get_volume_db"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume", PROPERTY_HINT_RANGE, "0,15,0.01,exp", PROPERTY_USAGE_NONE), "set_volume", "get_volume"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "has_autoplay"); @@ -464,7 +457,5 @@ void VideoStreamPlayer::_bind_methods() { VideoStreamPlayer::VideoStreamPlayer() {} VideoStreamPlayer::~VideoStreamPlayer() { - // if (stream_rid.is_valid()) - // AudioServer::get_singleton()->free(stream_rid); - resampler.clear(); //Not necessary here, but make in consistent with other "stream_player" classes -}; + resampler.clear(); // Not necessary here, but make in consistent with other "stream_player" classes. +} diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index b794bbbc57..d2f5b52dbf 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -56,32 +56,19 @@ Transform2D CanvasItem::_edit_get_transform() const { #endif bool CanvasItem::is_visible_in_tree() const { - return visible && visible_in_tree; + return visible && parent_visible_in_tree; } -void CanvasItem::_propagate_visibility_changed(bool p_visible, bool p_was_visible) { - if (p_visible && first_draw) { //avoid propagating it twice - first_draw = false; - } - visible_in_tree = p_visible; - notification(NOTIFICATION_VISIBILITY_CHANGED); - - if (visible && p_visible) { - update(); - } else if (!p_visible && (visible || p_was_visible)) { - emit_signal(SceneStringNames::get_singleton()->hidden); +void CanvasItem::_propagate_visibility_changed(bool p_parent_visible_in_tree) { + parent_visible_in_tree = p_parent_visible_in_tree; + if (!visible) { + return; } - _block(); - - for (int i = 0; i < get_child_count(); i++) { - CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i)); - - if (c && c->visible) { //should the top_levels stop propagation? i think so but.. - c->_propagate_visibility_changed(p_visible); - } + if (p_parent_visible_in_tree && first_draw) { // Avoid propagating it twice. + first_draw = false; } - _unblock(); + _handle_visibility_change(p_parent_visible_in_tree); } void CanvasItem::set_visible(bool p_visible) { @@ -90,13 +77,34 @@ void CanvasItem::set_visible(bool p_visible) { } visible = p_visible; - RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible); - if (!is_inside_tree()) { + if (!parent_visible_in_tree) { + notification(NOTIFICATION_VISIBILITY_CHANGED); return; } - _propagate_visibility_changed(p_visible, !p_visible); + _handle_visibility_change(p_visible); +} + +void CanvasItem::_handle_visibility_change(bool p_visible) { + RenderingServer::get_singleton()->canvas_item_set_visible(canvas_item, p_visible); + notification(NOTIFICATION_VISIBILITY_CHANGED); + + if (p_visible) { + update(); + } else { + emit_signal(SceneStringNames::get_singleton()->hidden); + } + + _block(); + for (int i = 0; i < get_child_count(); i++) { + CanvasItem *c = Object::cast_to<CanvasItem>(get_child(i)); + + if (c) { // Should the top_levels stop propagation? I think so, but... + c->_propagate_visibility_changed(p_visible); + } + } + _unblock(); } void CanvasItem::show() { @@ -264,13 +272,13 @@ void CanvasItem::_notification(int p_what) { CanvasItem *ci = Object::cast_to<CanvasItem>(parent); if (ci) { - visible_in_tree = ci->is_visible_in_tree(); + parent_visible_in_tree = ci->is_visible_in_tree(); C = ci->children_items.push_back(this); } else { CanvasLayer *cl = Object::cast_to<CanvasLayer>(parent); if (cl) { - visible_in_tree = cl->is_visible(); + parent_visible_in_tree = cl->is_visible(); } else { // Look for a window. Viewport *viewport = nullptr; @@ -288,9 +296,9 @@ void CanvasItem::_notification(int p_what) { window = Object::cast_to<Window>(viewport); if (window) { window->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed)); - visible_in_tree = window->is_visible(); + parent_visible_in_tree = window->is_visible(); } else { - visible_in_tree = true; + parent_visible_in_tree = true; } } } @@ -305,6 +313,7 @@ void CanvasItem::_notification(int p_what) { get_tree()->xform_change_list.add(&xform_change); } } break; + case NOTIFICATION_MOVED_IN_PARENT: { if (!is_inside_tree()) { break; @@ -317,8 +326,8 @@ void CanvasItem::_notification(int p_what) { ERR_FAIL_COND(!p); RenderingServer::get_singleton()->canvas_item_set_draw_index(canvas_item, get_index()); } - } break; + case NOTIFICATION_EXIT_TREE: { if (xform_change.in_list()) { get_tree()->xform_change_list.remove(&xform_change); @@ -332,11 +341,9 @@ void CanvasItem::_notification(int p_what) { window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed)); } global_invalid = true; - visible_in_tree = false; - } break; - case NOTIFICATION_DRAW: - case NOTIFICATION_TRANSFORM_CHANGED: { + parent_visible_in_tree = false; } break; + case NOTIFICATION_VISIBILITY_CHANGED: { emit_signal(SceneStringNames::get_singleton()->visibility_changed); } break; diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 2a9e7bac3d..1b2c188fc0 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -85,7 +85,7 @@ private: Window *window = nullptr; bool first_draw = false; bool visible = true; - bool visible_in_tree = false; + bool parent_visible_in_tree = false; bool clip_children = false; bool pending_update = false; bool top_level = false; @@ -108,7 +108,8 @@ private: void _top_level_raise_self(); - void _propagate_visibility_changed(bool p_visible, bool p_was_visible = false); + void _propagate_visibility_changed(bool p_parent_visible_in_tree); + void _handle_visibility_change(bool p_visible); void _update_callback(); diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index d4418a3cde..7aa4d391f8 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -58,15 +58,19 @@ void CanvasLayer::set_visible(bool p_visible) { if (c) { RenderingServer::get_singleton()->canvas_item_set_visible(c->get_canvas_item(), p_visible && c->is_visible()); - if (c->is_visible()) { - c->_propagate_visibility_changed(p_visible); - } else { - c->notification(CanvasItem::NOTIFICATION_VISIBILITY_CHANGED); - } + c->_propagate_visibility_changed(p_visible); } } } +void CanvasLayer::show() { + set_visible(true); +} + +void CanvasLayer::hide() { + set_visible(false); +} + bool CanvasLayer::is_visible() const { return visible; } @@ -166,8 +170,8 @@ void CanvasLayer::_notification(int p_what) { RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index()); RenderingServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); _update_follow_viewport(); - } break; + case NOTIFICATION_EXIT_TREE: { ERR_FAIL_NULL_MSG(vp, "Viewport is not initialized."); @@ -175,13 +179,12 @@ void CanvasLayer::_notification(int p_what) { RenderingServer::get_singleton()->viewport_remove_canvas(viewport, canvas); viewport = RID(); _update_follow_viewport(false); - } break; + case NOTIFICATION_MOVED_IN_PARENT: { if (is_inside_tree()) { RenderingServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_index()); } - } break; } } @@ -295,6 +298,8 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_visible", "visible"), &CanvasLayer::set_visible); ClassDB::bind_method(D_METHOD("is_visible"), &CanvasLayer::is_visible); + ClassDB::bind_method(D_METHOD("show"), &CanvasLayer::show); + ClassDB::bind_method(D_METHOD("hide"), &CanvasLayer::hide); ClassDB::bind_method(D_METHOD("set_transform", "transform"), &CanvasLayer::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &CanvasLayer::get_transform); diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index b7bd793440..2493675b31 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -72,6 +72,8 @@ public: void set_visible(bool p_visible); bool is_visible() const; + void show(); + void hide(); void set_transform(const Transform2D &p_xform); Transform2D get_transform() const; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 4e91548d14..700ba761f6 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -464,20 +464,22 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra } void HTTPRequest::_notification(int p_what) { - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (use_threads.is_set()) { - return; - } - bool done = _update_connection(); - if (done) { - set_process_internal(false); - } - } + switch (p_what) { + case NOTIFICATION_INTERNAL_PROCESS: { + if (use_threads.is_set()) { + return; + } + bool done = _update_connection(); + if (done) { + set_process_internal(false); + } + } break; - if (p_what == NOTIFICATION_EXIT_TREE) { - if (requesting) { - cancel_request(); - } + case NOTIFICATION_EXIT_TREE: { + if (requesting) { + cancel_request(); + } + } break; } } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 05086541a5..208bbe4d72 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -54,12 +54,12 @@ void Node::_notification(int p_notification) { switch (p_notification) { case NOTIFICATION_PROCESS: { GDVIRTUAL_CALL(_process, get_process_delta_time()); - } break; + case NOTIFICATION_PHYSICS_PROCESS: { GDVIRTUAL_CALL(_physics_process, get_physics_process_delta_time()); - } break; + case NOTIFICATION_ENTER_TREE: { ERR_FAIL_COND(!get_viewport()); ERR_FAIL_COND(!get_tree()); @@ -88,8 +88,8 @@ void Node::_notification(int p_notification) { get_tree()->node_count++; orphan_node_count--; - } break; + case NOTIFICATION_EXIT_TREE: { ERR_FAIL_COND(!get_viewport()); ERR_FAIL_COND(!get_tree()); @@ -113,12 +113,14 @@ void Node::_notification(int p_notification) { data.path_cache = nullptr; } } break; + case NOTIFICATION_PATH_RENAMED: { if (data.path_cache) { memdelete(data.path_cache); data.path_cache = nullptr; } } break; + case NOTIFICATION_READY: { if (GDVIRTUAL_IS_OVERRIDDEN(_input)) { set_process_input(true); @@ -141,9 +143,11 @@ void Node::_notification(int p_notification) { GDVIRTUAL_CALL(_ready); } break; + case NOTIFICATION_POSTINITIALIZE: { data.in_constructor = false; } break; + case NOTIFICATION_PREDELETE: { if (data.parent) { data.parent->remove_child(this); @@ -207,7 +211,7 @@ void Node::_propagate_enter_tree() { if (data.parent) { Variant c = this; const Variant *cptr = &c; - data.parent->emit_signal(SNAME("child_entered_tree"), &cptr, 1); + data.parent->emit_signalp(SNAME("child_entered_tree"), &cptr, 1); } data.blocked++; @@ -283,7 +287,7 @@ void Node::_propagate_exit_tree() { if (data.parent) { Variant c = this; const Variant *cptr = &c; - data.parent->emit_signal(SNAME("child_exited_tree"), &cptr, 1); + data.parent->emit_signalp(SNAME("child_exited_tree"), &cptr, 1); } // exit groups @@ -578,34 +582,6 @@ uint16_t Node::rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc /***** RPC FUNCTIONS ********/ -void Node::rpc(const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - rpcp(0, p_method, argptr, argc); -} - -void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - rpcp(p_peer_id, p_method, argptr, argc); -} - Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; @@ -1340,27 +1316,45 @@ bool Node::has_node(const NodePath &p_path) const { return get_node_or_null(p_path) != nullptr; } -Node *Node::find_node(const String &p_mask, bool p_recursive, bool p_owned) const { +TypedArray<Node> Node::find_nodes(const String &p_mask, const String &p_type, bool p_recursive, bool p_owned) const { + TypedArray<Node> ret; + ERR_FAIL_COND_V(p_mask.is_empty() && p_type.is_empty(), ret); + Node *const *cptr = data.children.ptr(); int ccount = data.children.size(); for (int i = 0; i < ccount; i++) { if (p_owned && !cptr[i]->data.owner) { continue; } - if (cptr[i]->data.name.operator String().match(p_mask)) { - return cptr[i]; + + if (!p_mask.is_empty()) { + if (!cptr[i]->data.name.operator String().match(p_mask)) { + continue; + } else if (p_type.is_empty()) { + ret.append(cptr[i]); + } } - if (!p_recursive) { - continue; + if (cptr[i]->is_class(p_type)) { + ret.append(cptr[i]); + } else if (cptr[i]->get_script_instance()) { + Ref<Script> script = cptr[i]->get_script_instance()->get_script(); + while (script.is_valid()) { + if ((ScriptServer::is_global_class(p_type) && ScriptServer::get_global_class_path(p_type) == script->get_path()) || p_type == script->get_path()) { + ret.append(cptr[i]); + break; + } + + script = script->get_base_script(); + } } - Node *ret = cptr[i]->find_node(p_mask, true, p_owned); - if (ret) { - return ret; + if (p_recursive) { + ret.append_array(cptr[i]->find_nodes(p_mask, p_type, true, p_owned)); } } - return nullptr; + + return ret; } Node *Node::get_parent() const { @@ -2367,42 +2361,6 @@ void Node::_replace_connections_target(Node *p_new_target) { } } -Vector<Variant> Node::make_binds(VARIANT_ARG_DECLARE) { - Vector<Variant> ret; - - if (p_arg1.get_type() == Variant::NIL) { - return ret; - } else { - ret.push_back(p_arg1); - } - - if (p_arg2.get_type() == Variant::NIL) { - return ret; - } else { - ret.push_back(p_arg2); - } - - if (p_arg3.get_type() == Variant::NIL) { - return ret; - } else { - ret.push_back(p_arg3); - } - - if (p_arg4.get_type() == Variant::NIL) { - return ret; - } else { - ret.push_back(p_arg4); - } - - if (p_arg5.get_type() == Variant::NIL) { - return ret; - } else { - ret.push_back(p_arg5); - } - - return ret; -} - bool Node::has_node_and_resource(const NodePath &p_path) const { if (!has_node(p_path)) { return false; @@ -2702,7 +2660,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_node", "path"), &Node::get_node); ClassDB::bind_method(D_METHOD("get_node_or_null", "path"), &Node::get_node_or_null); ClassDB::bind_method(D_METHOD("get_parent"), &Node::get_parent); - ClassDB::bind_method(D_METHOD("find_node", "mask", "recursive", "owned"), &Node::find_node, DEFVAL(true), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("find_nodes", "mask", "type", "recursive", "owned"), &Node::find_nodes, DEFVAL(""), DEFVAL(true), DEFVAL(true)); ClassDB::bind_method(D_METHOD("find_parent", "mask"), &Node::find_parent); ClassDB::bind_method(D_METHOD("has_node_and_resource", "path"), &Node::has_node_and_resource); ClassDB::bind_method(D_METHOD("get_node_and_resource", "path"), &Node::_get_node_and_resource); @@ -2841,6 +2799,9 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_WM_CLOSE_REQUEST); BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST); BIND_CONSTANT(NOTIFICATION_WM_SIZE_CHANGED); + BIND_CONSTANT(NOTIFICATION_WM_DPI_CHANGE); + BIND_CONSTANT(NOTIFICATION_VP_MOUSE_ENTER); + BIND_CONSTANT(NOTIFICATION_VP_MOUSE_EXIT); BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); BIND_CONSTANT(NOTIFICATION_WM_ABOUT); diff --git a/scene/main/node.h b/scene/main/node.h index f2dcdf4b43..f5fbcf6587 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -268,6 +268,8 @@ public: NOTIFICATION_WM_GO_BACK_REQUEST = 1007, NOTIFICATION_WM_SIZE_CHANGED = 1008, NOTIFICATION_WM_DPI_CHANGE = 1009, + NOTIFICATION_VP_MOUSE_ENTER = 1010, + NOTIFICATION_VP_MOUSE_EXIT = 1011, NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING, NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED, @@ -299,7 +301,7 @@ public: bool has_node(const NodePath &p_path) const; Node *get_node(const NodePath &p_path) const; Node *get_node_or_null(const NodePath &p_path) const; - Node *find_node(const String &p_mask, bool p_recursive = true, bool p_owned = true) const; + TypedArray<Node> find_nodes(const String &p_mask, const String &p_type = "", bool p_recursive = true, bool p_owned = true) const; bool has_node_and_resource(const NodePath &p_path) const; Node *get_node_and_resource(const NodePath &p_path, RES &r_res, Vector<StringName> &r_leftover_subpath, bool p_last_is_property = true) const; @@ -418,7 +420,11 @@ public: void set_scene_instance_load_placeholder(bool p_enable); bool get_scene_instance_load_placeholder() const; - static Vector<Variant> make_binds(VARIANT_ARG_LIST); + template <typename... VarArgs> + Vector<Variant> make_binds(VarArgs... p_args) { + Vector<Variant> binds = { p_args... }; + return binds; + } void replace_by(Node *p_node, bool p_keep_data = false); @@ -470,8 +476,26 @@ public: uint16_t rpc_config(const StringName &p_method, Multiplayer::RPCMode p_rpc_mode, bool p_call_local = false, Multiplayer::TransferMode p_transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE, int p_channel = 0); // config a local method for RPC Vector<Multiplayer::RPCConfig> get_node_rpc_methods() const; - void rpc(const StringName &p_method, VARIANT_ARG_LIST); // RPC, honors RPCMode, TransferMode, channel - void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); // RPC to specific peer(s), honors RPCMode, TransferMode, channel + template <typename... VarArgs> + void rpc(const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + rpcp(0, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + template <typename... VarArgs> + void rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + void rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount); Ref<MultiplayerAPI> get_multiplayer() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index f02032a6c9..3ddce28b69 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -175,13 +175,13 @@ void SceneTree::_flush_ugc() { while (unique_group_calls.size()) { Map<UGCall, Vector<Variant>>::Element *E = unique_group_calls.front(); - Variant v[VARIANT_ARG_MAX]; + const Variant **argptrs = (const Variant **)alloca(E->get().size() * sizeof(Variant *)); + for (int i = 0; i < E->get().size(); i++) { - v[i] = E->get()[i]; + argptrs[i] = &E->get()[i]; } - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); - call_group_flags(GROUP_CALL_REALTIME, E->key().group, E->key().call, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + call_group_flagsp(GROUP_CALL_REALTIME, E->key().group, E->key().call, argptrs, E->get().size()); unique_group_calls.erase(E); } @@ -210,7 +210,7 @@ void SceneTree::_update_group_order(Group &g, bool p_use_priority) { g.changed = false; } -void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) { +void SceneTree::call_group_flagsp(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, const Variant **p_args, int p_argcount) { Map<StringName, Group>::Element *E = group_map.find(p_group); if (!E) { return; @@ -231,14 +231,9 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou return; } - VARIANT_ARGPTRS; - Vector<Variant> args; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - args.push_back(*argptr[i]); + for (int i = 0; i < p_argcount; i++) { + args.push_back(*p_args[i]); } unique_group_calls[ug] = args; @@ -260,9 +255,10 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou } if (p_call_flags & GROUP_CALL_REALTIME) { - nodes[i]->call(p_function, VARIANT_ARG_PASS); + Callable::CallError ce; + nodes[i]->callp(p_function, p_args, p_argcount, ce); } else { - MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); + MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount); } } @@ -273,9 +269,10 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou } if (p_call_flags & GROUP_CALL_REALTIME) { - nodes[i]->call(p_function, VARIANT_ARG_PASS); + Callable::CallError ce; + nodes[i]->callp(p_function, p_args, p_argcount, ce); } else { - MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); + MessageQueue::get_singleton()->push_callp(nodes[i], p_function, p_args, p_argcount); } } } @@ -388,10 +385,6 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group } } -void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) { - call_group_flags(0, p_group, p_function, VARIANT_ARG_PASS); -} - void SceneTree::notify_group(const StringName &p_group, int p_notification) { notify_group_flags(0, p_group, p_notification); } @@ -486,7 +479,7 @@ bool SceneTree::process(double p_time) { } E->get()->set_time_left(time_left); - if (time_left < 0) { + if (time_left <= 0) { E->get()->emit_signal(SNAME("timeout")); timers.erase(E); } @@ -616,6 +609,7 @@ void SceneTree::_notification(int p_notification) { get_root()->propagate_notification(p_notification); } } break; + case NOTIFICATION_OS_MEMORY_WARNING: case NOTIFICATION_OS_IME_UPDATE: case NOTIFICATION_WM_ABOUT: @@ -624,13 +618,11 @@ void SceneTree::_notification(int p_notification) { case NOTIFICATION_APPLICATION_PAUSED: case NOTIFICATION_APPLICATION_FOCUS_IN: case NOTIFICATION_APPLICATION_FOCUS_OUT: { - get_root()->propagate_notification(p_notification); //pass these to nodes, since they are mirrored + // Pass these to nodes, since they are mirrored. + get_root()->propagate_notification(p_notification); } break; - - default: - break; - }; -}; + } +} void SceneTree::set_auto_accept_quit(bool p_enable) { accept_quit = p_enable; @@ -931,14 +923,8 @@ Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Cal int flags = *p_args[0]; StringName group = *p_args[1]; StringName method = *p_args[2]; - Variant v[VARIANT_ARG_MAX]; - - for (int i = 0; i < MIN(p_argcount - 3, 5); i++) { - v[i] = *p_args[i + 3]; - } - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); - call_group_flags(flags, group, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + call_group_flagsp(flags, group, method, p_args + 3, p_argcount - 3); return Variant(); } @@ -951,14 +937,8 @@ Variant SceneTree::_call_group(const Variant **p_args, int p_argcount, Callable: StringName group = *p_args[0]; StringName method = *p_args[1]; - Variant v[VARIANT_ARG_MAX]; - - for (int i = 0; i < MIN(p_argcount - 2, 5); i++) { - v[i] = *p_args[i + 2]; - } - static_assert(VARIANT_ARG_MAX == 8, "This code needs to be updated if VARIANT_ARG_MAX != 8"); - call_group_flags(0, group, method, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + call_group_flagsp(0, group, method, p_args + 2, p_argcount - 2); return Variant(); } @@ -1257,8 +1237,6 @@ void SceneTree::_bind_methods() { ADD_SIGNAL(MethodInfo("process_frame")); ADD_SIGNAL(MethodInfo("physics_frame")); - ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); - BIND_ENUM_CONSTANT(GROUP_CALL_DEFAULT); BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE); BIND_ENUM_CONSTANT(GROUP_CALL_REALTIME); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 5f7c1729e8..6197e52fc1 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -229,14 +229,33 @@ public: _FORCE_INLINE_ Window *get_root() const { return root; } - void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); + void call_group_flagsp(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, const Variant **p_args, int p_argcount); void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification); void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value); - void call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); void notify_group(const StringName &p_group, int p_notification); void set_group(const StringName &p_group, const String &p_name, const Variant &p_value); + template <typename... VarArgs> + void call_group(const StringName &p_group, const StringName &p_function, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + call_group_flagsp(0, p_group, p_function, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + + template <typename... VarArgs> + void call_group_flags(uint32_t p_flags, const StringName &p_group, const StringName &p_function, VarArgs... p_args) { + Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported. + const Variant *argptrs[sizeof...(p_args) + 1]; + for (uint32_t i = 0; i < sizeof...(p_args); i++) { + argptrs[i] = &args[i]; + } + call_group_flagsp(p_flags, p_group, p_function, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); + } + void flush_transform_notifications(); virtual void initialize() override; diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index 09dfc50066..5387dc01e2 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -247,26 +247,29 @@ void ShaderGlobalsOverride::_activate() { } void ShaderGlobalsOverride::_notification(int p_what) { - if (p_what == Node3D::NOTIFICATION_ENTER_TREE) { - add_to_group(SceneStringNames::get_singleton()->shader_overrides_group); - _activate(); + switch (p_what) { + case Node3D::NOTIFICATION_ENTER_TREE: { + add_to_group(SceneStringNames::get_singleton()->shader_overrides_group); + _activate(); + } break; - } else if (p_what == Node3D::NOTIFICATION_EXIT_TREE) { - if (active) { - //remove overrides - const StringName *K = nullptr; - while ((K = overrides.next(K))) { - Override *o = overrides.getptr(*K); - if (o->in_use) { - RS::get_singleton()->global_variable_set_override(*K, Variant()); + case Node3D::NOTIFICATION_EXIT_TREE: { + if (active) { + //remove overrides + const StringName *K = nullptr; + while ((K = overrides.next(K))) { + Override *o = overrides.getptr(*K); + if (o->in_use) { + RS::get_singleton()->global_variable_set_override(*K, Variant()); + } } } - } - remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group_active); - remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group); - get_tree()->call_group(SceneStringNames::get_singleton()->shader_overrides_group, "_activate"); //another may want to activate when this is removed - active = false; + remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group_active); + remove_from_group(SceneStringNames::get_singleton()->shader_overrides_group); + get_tree()->call_group(SceneStringNames::get_singleton()->shader_overrides_group, "_activate"); //another may want to activate when this is removed + active = false; + } break; } } diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index babe62f453..120b537e4f 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -43,6 +43,7 @@ void Timer::_notification(int p_what) { autostart = false; } } break; + case NOTIFICATION_INTERNAL_PROCESS: { if (!processing || timer_process_callback == TIMER_PROCESS_PHYSICS || !is_processing_internal()) { return; @@ -58,8 +59,8 @@ void Timer::_notification(int p_what) { emit_signal(SNAME("timeout")); } - } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!processing || timer_process_callback == TIMER_PROCESS_IDLE || !is_physics_processing_internal()) { return; @@ -74,7 +75,6 @@ void Timer::_notification(int p_what) { } emit_signal(SNAME("timeout")); } - } break; } } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index a1ff95ea9a..de6aa2b139 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -406,8 +406,8 @@ void Viewport::_notification(int p_what) { #endif // _3D_DISABLED set_physics_process_internal(true); } - } break; + case NOTIFICATION_READY: { #ifndef _3D_DISABLED if (audio_listener_3d_set.size() && !audio_listener_3d) { @@ -438,6 +438,7 @@ void Viewport::_notification(int p_what) { } #endif // _3D_DISABLED } break; + case NOTIFICATION_EXIT_TREE: { _gui_cancel_tooltip(); @@ -461,6 +462,7 @@ void Viewport::_notification(int p_what) { RS::get_singleton()->viewport_set_active(viewport, false); RenderingServer::get_singleton()->viewport_set_parent_viewport(viewport, RID()); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (!get_tree()) { return; @@ -493,17 +495,20 @@ void Viewport::_notification(int p_what) { } #endif // _3D_DISABLED } break; - case NOTIFICATION_WM_MOUSE_ENTER: { - gui.mouse_in_window = true; + + case NOTIFICATION_VP_MOUSE_ENTER: { + gui.mouse_in_viewport = true; } break; - case NOTIFICATION_WM_MOUSE_EXIT: { - gui.mouse_in_window = false; + + case NOTIFICATION_VP_MOUSE_EXIT: { + gui.mouse_in_viewport = false; _drop_physics_mouseover(); _drop_mouse_over(); - // When the mouse exits the window, we want to end mouse_over, but + // When the mouse exits the viewport, we want to end mouse_over, but // not mouse_focus, because, for example, we want to continue - // dragging a scrollbar even if the mouse has left the window. + // dragging a scrollbar even if the mouse has left the viewport. } break; + case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { _drop_physics_mouseover(); if (gui.mouse_focus && !gui.forced_mouse_focus) { @@ -1234,6 +1239,7 @@ void Viewport::_gui_show_tooltip() { panel->set_transient(true); panel->set_flag(Window::FLAG_NO_FOCUS, true); + panel->set_flag(Window::FLAG_POPUP, false); panel->set_wrap_controls(true); panel->add_child(base_tooltip); @@ -1263,7 +1269,10 @@ void Viewport::_gui_show_tooltip() { gui.tooltip_popup->set_position(r.position); gui.tooltip_popup->set_size(r.size); - gui.tooltip_popup->show(); + DisplayServer::WindowID active_popup = DisplayServer::get_singleton()->window_get_active_popup(); + if (active_popup == DisplayServer::INVALID_WINDOW_ID || active_popup == window->get_window_id()) { + gui.tooltip_popup->show(); + } gui.tooltip_popup->child_controls_changed(); } @@ -1678,7 +1687,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *over = nullptr; if (gui.mouse_focus) { over = gui.mouse_focus; - } else if (gui.mouse_in_window) { + } else if (gui.mouse_in_viewport) { over = gui_find_control(mpos); } @@ -1714,7 +1723,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.tooltip_popup) { if (gui.tooltip_control) { String tooltip = _gui_get_tooltip(over, gui.tooltip_control->get_global_transform().xform_inv(mpos)); - + tooltip = tooltip.strip_edges(); if (tooltip.length() == 0) { _gui_cancel_tooltip(); } else if (gui.tooltip_label) { @@ -3939,11 +3948,14 @@ Transform2D SubViewport::_stretch_transform() { } void SubViewport::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); - } - if (p_what == NOTIFICATION_EXIT_TREE) { - RS::get_singleton()->viewport_set_active(get_viewport_rid(), false); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); + } break; + + case NOTIFICATION_EXIT_TREE: { + RS::get_singleton()->viewport_set_active(get_viewport_rid(), false); + } break; } } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 3a71745f44..93e42f1838 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -335,7 +335,7 @@ private: // info used when this is a window bool forced_mouse_focus = false; //used for menu buttons - bool mouse_in_window = true; + bool mouse_in_viewport = true; bool key_event_accepted = false; Control *mouse_focus = nullptr; Control *last_mouse_focus = nullptr; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 77c0fa2a48..6837fcae21 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -340,9 +340,11 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) { case DisplayServer::WINDOW_EVENT_MOUSE_ENTER: { _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER); emit_signal(SNAME("mouse_entered")); + notification(NOTIFICATION_VP_MOUSE_ENTER); DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape } break; case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: { + notification(NOTIFICATION_VP_MOUSE_EXIT); _propagate_window_notification(this, NOTIFICATION_WM_MOUSE_EXIT); emit_signal(SNAME("mouse_exited")); } break; @@ -434,8 +436,12 @@ void Window::set_visible(bool p_visible) { //update transient exclusive if (transient_parent) { if (exclusive && visible) { - ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); - transient_parent->exclusive_child = this; +#ifdef TOOLS_ENABLED + if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { + ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); + transient_parent->exclusive_child = this; + } +#endif } else { if (transient_parent->exclusive_child == this) { transient_parent->exclusive_child = nullptr; @@ -738,18 +744,16 @@ void Window::_notification(int p_what) { bool embedded = false; { embedder = _get_embedder(); - if (embedder) { embedded = true; - if (!visible) { - embedder = nullptr; //not yet since not visible + embedder = nullptr; // Not yet since not visible. } } } if (embedded) { - //create as embedded + // Create as embedded. if (embedder) { embedder->_sub_window_register(this); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); @@ -757,22 +761,22 @@ void Window::_notification(int p_what) { } } else { - if (get_parent() == nullptr) { - //it's the root window! - visible = true; //always visible + if (!get_parent()) { + // It's the root window! + visible = true; // Always visible. window_id = DisplayServer::MAIN_WINDOW_ID; DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); _update_from_window(); - //since this window already exists (created on start), we must update pos and size from it + // Since this window already exists (created on start), we must update pos and size from it. { position = DisplayServer::get_singleton()->window_get_position(window_id); size = DisplayServer::get_singleton()->window_get_size(window_id); } - _update_viewport_size(); //then feed back to the viewport + _update_viewport_size(); // Then feed back to the viewport. _update_window_callbacks(); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_WHEN_VISIBLE); } else { - //create + // Create. if (visible) { _make_window(); } @@ -788,11 +792,13 @@ void Window::_notification(int p_what) { RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); } } break; + case NOTIFICATION_READY: { if (wrap_controls) { _update_child_controls(); } } break; + case NOTIFICATION_TRANSLATION_CHANGED: { if (embedder) { embedder->_sub_window_update(this); @@ -811,6 +817,7 @@ void Window::_notification(int p_what) { child_controls_changed(); } break; + case NOTIFICATION_EXIT_TREE: { if (transient) { _clear_transient(); @@ -948,7 +955,7 @@ bool Window::_can_consume_input_events() const { void Window::_window_input(const Ref<InputEvent> &p_ev) { if (EngineDebugger::is_active()) { - //quit from game window using F8 + // Quit from game window using F8. Ref<InputEventKey> k = p_ev; if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::F8) { EngineDebugger::get_singleton()->send_message("request_quit", Array()); @@ -956,15 +963,7 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) { } if (exclusive_child != nullptr) { - /* - Window *focus_target = exclusive_child; - focus_target->grab_focus(); - while (focus_target->exclusive_child != nullptr) { - focus_target = focus_target->exclusive_child; - focus_target->grab_focus(); - }*/ - - if (!is_embedding_subwindows()) { //not embedding, no need for event + if (!is_embedding_subwindows()) { // Not embedding, no need for event. return; } } @@ -1584,6 +1583,7 @@ void Window::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "always_on_top"), "set_flag", "get_flag", FLAG_ALWAYS_ON_TOP); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP); ADD_GROUP("Limits", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size"), "set_min_size", "get_min_size"); @@ -1627,6 +1627,7 @@ void Window::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_ALWAYS_ON_TOP); BIND_ENUM_CONSTANT(FLAG_TRANSPARENT); BIND_ENUM_CONSTANT(FLAG_NO_FOCUS); + BIND_ENUM_CONSTANT(FLAG_POPUP); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED); diff --git a/scene/main/window.h b/scene/main/window.h index f37689f905..3d8e337b4a 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -55,6 +55,7 @@ public: FLAG_ALWAYS_ON_TOP = DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, FLAG_TRANSPARENT = DisplayServer::WINDOW_FLAG_TRANSPARENT, FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS, + FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP, FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX, }; diff --git a/scene/multiplayer/multiplayer_spawner.cpp b/scene/multiplayer/multiplayer_spawner.cpp index 4f2a9d9e83..25ab27f3e7 100644 --- a/scene/multiplayer/multiplayer_spawner.cpp +++ b/scene/multiplayer/multiplayer_spawner.cpp @@ -84,22 +84,26 @@ void MultiplayerSpawner::_update_spawn_node() { } void MultiplayerSpawner::_notification(int p_what) { - if (p_what == NOTIFICATION_POST_ENTER_TREE) { - _update_spawn_node(); - } else if (p_what == NOTIFICATION_EXIT_TREE) { - _update_spawn_node(); - const ObjectID *oid = nullptr; - while ((oid = tracked_nodes.next(oid))) { - Node *node = Object::cast_to<Node>(ObjectDB::get_instance(*oid)); - ERR_CONTINUE(!node); - node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit)); - // This is unlikely, but might still crash the engine. - if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready))) { - node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready)); + switch (p_what) { + case NOTIFICATION_POST_ENTER_TREE: { + _update_spawn_node(); + } break; + + case NOTIFICATION_EXIT_TREE: { + _update_spawn_node(); + const ObjectID *oid = nullptr; + while ((oid = tracked_nodes.next(oid))) { + Node *node = Object::cast_to<Node>(ObjectDB::get_instance(*oid)); + ERR_CONTINUE(!node); + node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit)); + // This is unlikely, but might still crash the engine. + if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready))) { + node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready)); + } + get_multiplayer()->despawn(node, this); } - get_multiplayer()->despawn(node, this); - } - tracked_nodes.clear(); + tracked_nodes.clear(); + } break; } } diff --git a/scene/multiplayer/multiplayer_synchronizer.cpp b/scene/multiplayer/multiplayer_synchronizer.cpp index fbe1b99cc9..33e845a7a3 100644 --- a/scene/multiplayer/multiplayer_synchronizer.cpp +++ b/scene/multiplayer/multiplayer_synchronizer.cpp @@ -108,10 +108,15 @@ void MultiplayerSynchronizer::_notification(int p_what) { if (root_path.is_empty()) { return; } - if (p_what == NOTIFICATION_ENTER_TREE) { - _start(); - } else if (p_what == NOTIFICATION_EXIT_TREE) { - _stop(); + + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + _start(); + } break; + + case NOTIFICATION_EXIT_TREE: { + _stop(); + } break; } } diff --git a/scene/multiplayer/scene_cache_interface.cpp b/scene/multiplayer/scene_cache_interface.cpp index 2f278ed864..f05dc5a2da 100644 --- a/scene/multiplayer/scene_cache_interface.cpp +++ b/scene/multiplayer/scene_cache_interface.cpp @@ -139,74 +139,46 @@ void SceneCacheInterface::process_confirm_path(int p_from, const uint8_t *p_pack E->get() = true; } -bool SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target) { - bool has_all_peers = true; - List<int> peers_to_add; // If one is missing, take note to add it. - - for (const Set<int>::Element *E = multiplayer->get_connected_peers().front(); E; E = E->next()) { - if (p_target < 0 && E->get() == -p_target) { - continue; // Continue, excluded. - } - - if (p_target > 0 && E->get() != p_target) { - continue; // Continue, not for this peer. - } - - Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); - - if (!F || !F->get()) { - // Path was not cached, or was cached but is unconfirmed. - if (!F) { - // Not cached at all, take note. - peers_to_add.push_back(E->get()); - } +Error SceneCacheInterface::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers) { + // Encode function name. + const CharString path = String(p_path).utf8(); + const int path_len = encode_cstring(path.get_data(), nullptr); - has_all_peers = false; - } - } - - if (peers_to_add.size() > 0) { - // Those that need to be added, send a message for this. - - // Encode function name. - const CharString path = String(p_path).utf8(); - const int path_len = encode_cstring(path.get_data(), nullptr); + // Extract MD5 from rpc methods list. + const String methods_md5 = multiplayer->get_rpc_md5(p_node); + const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. - // Extract MD5 from rpc methods list. - const String methods_md5 = multiplayer->get_rpc_md5(p_node); - const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. - - Vector<uint8_t> packet; - packet.resize(1 + 4 + path_len + methods_md5_len); - int ofs = 0; + Vector<uint8_t> packet; + packet.resize(1 + 4 + path_len + methods_md5_len); + int ofs = 0; - packet.write[ofs] = MultiplayerAPI::NETWORK_COMMAND_SIMPLIFY_PATH; - ofs += 1; + packet.write[ofs] = MultiplayerAPI::NETWORK_COMMAND_SIMPLIFY_PATH; + ofs += 1; - ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]); + ofs += encode_cstring(methods_md5.utf8().get_data(), &packet.write[ofs]); - ofs += encode_uint32(psc->id, &packet.write[ofs]); + ofs += encode_uint32(psc->id, &packet.write[ofs]); - ofs += encode_cstring(path.get_data(), &packet.write[ofs]); + ofs += encode_cstring(path.get_data(), &packet.write[ofs]); - Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); - ERR_FAIL_COND_V(multiplayer_peer.is_null(), false); + Ref<MultiplayerPeer> multiplayer_peer = multiplayer->get_multiplayer_peer(); + ERR_FAIL_COND_V(multiplayer_peer.is_null(), ERR_BUG); #ifdef DEBUG_ENABLED - multiplayer->profile_bandwidth("out", packet.size() * peers_to_add.size()); + multiplayer->profile_bandwidth("out", packet.size() * p_peers.size()); #endif - for (int &E : peers_to_add) { - multiplayer_peer->set_target_peer(E); // To all of you. - multiplayer_peer->set_transfer_channel(0); - multiplayer_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); - multiplayer_peer->put_packet(packet.ptr(), packet.size()); - - psc->confirmed_peers.insert(E, false); // Insert into confirmed, but as false since it was not confirmed. - } + Error err = OK; + for (int peer_id : p_peers) { + multiplayer_peer->set_target_peer(peer_id); + multiplayer_peer->set_transfer_channel(0); + multiplayer_peer->set_transfer_mode(Multiplayer::TRANSFER_MODE_RELIABLE); + err = multiplayer_peer->put_packet(packet.ptr(), packet.size()); + ERR_FAIL_COND_V(err != OK, err); + // Insert into confirmed, but as false since it was not confirmed. + psc->confirmed_peers.insert(peer_id, false); } - - return has_all_peers; + return err; } bool SceneCacheInterface::is_cache_confirmed(NodePath p_path, int p_peer) { @@ -230,7 +202,43 @@ bool SceneCacheInterface::send_object_cache(Object *p_obj, NodePath p_path, int } r_id = psc->id; - return _send_confirm_path(node, p_path, psc, p_peer_id); + bool has_all_peers = true; + List<int> peers_to_add; // If one is missing, take note to add it. + + if (p_peer_id > 0) { + // Fast single peer check. + Map<int, bool>::Element *F = psc->confirmed_peers.find(p_peer_id); + if (!F) { + peers_to_add.push_back(p_peer_id); // Need to also be notified. + has_all_peers = false; + } else if (!F->get()) { + has_all_peers = false; + } + } else { + // Long and painful. + for (const Set<int>::Element *E = multiplayer->get_connected_peers().front(); E; E = E->next()) { + if (p_peer_id < 0 && E->get() == -p_peer_id) { + continue; // Continue, excluded. + } + if (p_peer_id > 0 && E->get() != p_peer_id) { + continue; // Continue, not for this peer. + } + + Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get()); + if (!F) { + peers_to_add.push_back(E->get()); // Need to also be notified. + has_all_peers = false; + } else if (!F->get()) { + has_all_peers = false; + } + } + } + + if (peers_to_add.size()) { + _send_confirm_path(node, p_path, psc, peers_to_add); + } + + return has_all_peers; } Object *SceneCacheInterface::get_cached_object(int p_from, uint32_t p_cache_id) { diff --git a/scene/multiplayer/scene_cache_interface.h b/scene/multiplayer/scene_cache_interface.h index 91a53cb948..c709d26b51 100644 --- a/scene/multiplayer/scene_cache_interface.h +++ b/scene/multiplayer/scene_cache_interface.h @@ -60,7 +60,7 @@ private: int last_send_cache_id = 1; protected: - bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); + Error _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, const List<int> &p_peers); static MultiplayerCacheInterface *_create(MultiplayerAPI *p_multiplayer); public: diff --git a/scene/multiplayer/scene_replication_interface.cpp b/scene/multiplayer/scene_replication_interface.cpp index 25a704b37e..0764f136e4 100644 --- a/scene/multiplayer/scene_replication_interface.cpp +++ b/scene/multiplayer/scene_replication_interface.cpp @@ -350,11 +350,12 @@ void SceneReplicationInterface::_send_sync(int p_peer, uint64_t p_msec) { } if (size) { uint32_t net_id = rep_state->get_net_id(oid); - if (net_id == 0) { + if (net_id == 0 || (net_id & 0x80000000)) { // First time path based ID. NodePath rel_path = multiplayer->get_root_path().rel_path_to(sync->get_path()); int path_id = 0; multiplayer->send_object_cache(sync, rel_path, p_peer, path_id); + ERR_CONTINUE_MSG(net_id && net_id != (uint32_t(path_id) | 0x80000000), "This should never happen!"); net_id = path_id; rep_state->set_net_id(oid, net_id | 0x80000000); } diff --git a/scene/multiplayer/scene_rpc_interface.cpp b/scene/multiplayer/scene_rpc_interface.cpp index 2239a5d81c..84700a82f3 100644 --- a/scene/multiplayer/scene_rpc_interface.cpp +++ b/scene/multiplayer/scene_rpc_interface.cpp @@ -278,7 +278,7 @@ void SceneRPCInterface::_process_rpc(Node *p_node, const uint16_t p_rpc_method_i Callable::CallError ce; - p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce); + p_node->callp(config.name, (const Variant **)argp.ptr(), argc, ce); if (ce.error != Callable::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce); error = "RPC - " + error; @@ -480,7 +480,7 @@ void SceneRPCInterface::rpcp(Object *p_obj, int p_peer_id, const StringName &p_m Callable::CallError ce; multiplayer->set_remote_sender_override(peer->get_unique_id()); - node->call(p_method, p_arg, p_argcount, ce); + node->callp(p_method, p_arg, p_argcount, ce); multiplayer->set_remote_sender_override(0); if (ce.error != Callable::CallError::CALL_OK) { @@ -496,7 +496,7 @@ void SceneRPCInterface::rpcp(Object *p_obj, int p_peer_id, const StringName &p_m ce.error = Callable::CallError::CALL_OK; multiplayer->set_remote_sender_override(peer->get_unique_id()); - node->get_script_instance()->call(p_method, p_arg, p_argcount, ce); + node->get_script_instance()->callp(p_method, p_arg, p_argcount, ce); multiplayer->set_remote_sender_override(0); if (ce.error != Callable::CallError::CALL_OK) { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 87e9bd023b..fb5d57ab9e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -260,9 +260,9 @@ static Ref<ResourceFormatSaverText> resource_saver_text; static Ref<ResourceFormatLoaderText> resource_loader_text; -static Ref<ResourceFormatLoaderStreamTexture2D> resource_loader_stream_texture; -static Ref<ResourceFormatLoaderStreamTextureLayered> resource_loader_texture_layered; -static Ref<ResourceFormatLoaderStreamTexture3D> resource_loader_texture_3d; +static Ref<ResourceFormatLoaderCompressedTexture2D> resource_loader_stream_texture; +static Ref<ResourceFormatLoaderCompressedTextureLayered> resource_loader_texture_layered; +static Ref<ResourceFormatLoaderCompressedTexture3D> resource_loader_texture_3d; static Ref<ResourceFormatSaverShader> resource_saver_shader; static Ref<ResourceFormatLoaderShader> resource_loader_shader; @@ -300,9 +300,9 @@ void register_scene_types() { GDREGISTER_CLASS(Object); GDREGISTER_CLASS(Node); - GDREGISTER_VIRTUAL_CLASS(InstancePlaceholder); + GDREGISTER_ABSTRACT_CLASS(InstancePlaceholder); - GDREGISTER_VIRTUAL_CLASS(Viewport); + GDREGISTER_ABSTRACT_CLASS(Viewport); GDREGISTER_CLASS(SubViewport); GDREGISTER_CLASS(ViewportTexture); GDREGISTER_CLASS(HTTPRequest); @@ -324,11 +324,11 @@ void register_scene_types() { GDREGISTER_CLASS(Control); GDREGISTER_CLASS(Button); GDREGISTER_CLASS(Label); - GDREGISTER_VIRTUAL_CLASS(ScrollBar); + GDREGISTER_ABSTRACT_CLASS(ScrollBar); GDREGISTER_CLASS(HScrollBar); GDREGISTER_CLASS(VScrollBar); GDREGISTER_CLASS(ProgressBar); - GDREGISTER_VIRTUAL_CLASS(Slider); + GDREGISTER_ABSTRACT_CLASS(Slider); GDREGISTER_CLASS(HSlider); GDREGISTER_CLASS(VSlider); GDREGISTER_CLASS(Popup); @@ -349,19 +349,19 @@ void register_scene_types() { GDREGISTER_CLASS(AspectRatioContainer); GDREGISTER_CLASS(TabContainer); GDREGISTER_CLASS(TabBar); - GDREGISTER_VIRTUAL_CLASS(Separator); + GDREGISTER_ABSTRACT_CLASS(Separator); GDREGISTER_CLASS(HSeparator); GDREGISTER_CLASS(VSeparator); GDREGISTER_CLASS(TextureButton); GDREGISTER_CLASS(Container); - GDREGISTER_VIRTUAL_CLASS(BoxContainer); + GDREGISTER_ABSTRACT_CLASS(BoxContainer); GDREGISTER_CLASS(HBoxContainer); GDREGISTER_CLASS(VBoxContainer); GDREGISTER_CLASS(GridContainer); GDREGISTER_CLASS(CenterContainer); GDREGISTER_CLASS(ScrollContainer); GDREGISTER_CLASS(PanelContainer); - GDREGISTER_VIRTUAL_CLASS(FlowContainer); + GDREGISTER_ABSTRACT_CLASS(FlowContainer); GDREGISTER_CLASS(HFlowContainer); GDREGISTER_CLASS(VFlowContainer); @@ -384,7 +384,7 @@ void register_scene_types() { GDREGISTER_CLASS(SyntaxHighlighter); GDREGISTER_CLASS(CodeHighlighter); - GDREGISTER_VIRTUAL_CLASS(TreeItem); + GDREGISTER_ABSTRACT_CLASS(TreeItem); GDREGISTER_CLASS(OptionButton); GDREGISTER_CLASS(SpinBox); GDREGISTER_CLASS(ColorPicker); @@ -398,7 +398,7 @@ void register_scene_types() { GDREGISTER_CLASS(MarginContainer); GDREGISTER_CLASS(SubViewportContainer); - GDREGISTER_VIRTUAL_CLASS(SplitContainer); + GDREGISTER_ABSTRACT_CLASS(SplitContainer); GDREGISTER_CLASS(HSplitContainer); GDREGISTER_CLASS(VSplitContainer); @@ -418,7 +418,7 @@ void register_scene_types() { GDREGISTER_CLASS(AnimationPlayer); GDREGISTER_CLASS(Tween); - GDREGISTER_VIRTUAL_CLASS(Tweener); + GDREGISTER_ABSTRACT_CLASS(Tweener); GDREGISTER_CLASS(PropertyTweener); GDREGISTER_CLASS(IntervalTweener); GDREGISTER_CLASS(CallbackTweener); @@ -453,9 +453,9 @@ void register_scene_types() { #ifndef _3D_DISABLED GDREGISTER_CLASS(Node3D); - GDREGISTER_VIRTUAL_CLASS(Node3DGizmo); + GDREGISTER_ABSTRACT_CLASS(Node3DGizmo); GDREGISTER_CLASS(Skin); - GDREGISTER_VIRTUAL_CLASS(SkinReference); + GDREGISTER_ABSTRACT_CLASS(SkinReference); GDREGISTER_CLASS(Skeleton3D); GDREGISTER_CLASS(ImporterMesh); GDREGISTER_CLASS(ImporterMeshInstance3D); @@ -464,22 +464,22 @@ void register_scene_types() { GDREGISTER_CLASS(Camera3D); GDREGISTER_CLASS(AudioListener3D); GDREGISTER_CLASS(XRCamera3D); - GDREGISTER_VIRTUAL_CLASS(XRNode3D); + GDREGISTER_ABSTRACT_CLASS(XRNode3D); GDREGISTER_CLASS(XRController3D); GDREGISTER_CLASS(XRAnchor3D); GDREGISTER_CLASS(XROrigin3D); GDREGISTER_CLASS(MeshInstance3D); GDREGISTER_CLASS(OccluderInstance3D); - GDREGISTER_VIRTUAL_CLASS(Occluder3D); + GDREGISTER_ABSTRACT_CLASS(Occluder3D); GDREGISTER_CLASS(ArrayOccluder3D); GDREGISTER_CLASS(QuadOccluder3D); GDREGISTER_CLASS(BoxOccluder3D); GDREGISTER_CLASS(SphereOccluder3D); GDREGISTER_CLASS(PolygonOccluder3D); - GDREGISTER_VIRTUAL_CLASS(SpriteBase3D); + GDREGISTER_ABSTRACT_CLASS(SpriteBase3D); GDREGISTER_CLASS(Sprite3D); GDREGISTER_CLASS(AnimatedSprite3D); - GDREGISTER_VIRTUAL_CLASS(Light3D); + GDREGISTER_ABSTRACT_CLASS(Light3D); GDREGISTER_CLASS(DirectionalLight3D); GDREGISTER_CLASS(OmniLight3D); GDREGISTER_CLASS(SpotLight3D); @@ -490,14 +490,14 @@ void register_scene_types() { GDREGISTER_CLASS(LightmapGI); GDREGISTER_CLASS(LightmapGIData); GDREGISTER_CLASS(LightmapProbe); - GDREGISTER_VIRTUAL_CLASS(Lightmapper); + GDREGISTER_ABSTRACT_CLASS(Lightmapper); GDREGISTER_CLASS(GPUParticles3D); - GDREGISTER_VIRTUAL_CLASS(GPUParticlesCollision3D); + GDREGISTER_ABSTRACT_CLASS(GPUParticlesCollision3D); GDREGISTER_CLASS(GPUParticlesCollisionBox3D); GDREGISTER_CLASS(GPUParticlesCollisionSphere3D); GDREGISTER_CLASS(GPUParticlesCollisionSDF3D); GDREGISTER_CLASS(GPUParticlesCollisionHeightField3D); - GDREGISTER_VIRTUAL_CLASS(GPUParticlesAttractor3D); + GDREGISTER_ABSTRACT_CLASS(GPUParticlesAttractor3D); GDREGISTER_CLASS(GPUParticlesAttractorBox3D); GDREGISTER_CLASS(GPUParticlesAttractorSphere3D); GDREGISTER_CLASS(GPUParticlesAttractorVectorField3D); @@ -509,8 +509,8 @@ void register_scene_types() { OS::get_singleton()->yield(); // may take time to init - GDREGISTER_VIRTUAL_CLASS(CollisionObject3D); - GDREGISTER_VIRTUAL_CLASS(PhysicsBody3D); + GDREGISTER_ABSTRACT_CLASS(CollisionObject3D); + GDREGISTER_ABSTRACT_CLASS(PhysicsBody3D); GDREGISTER_CLASS(StaticBody3D); GDREGISTER_CLASS(AnimatableBody3D); GDREGISTER_CLASS(RigidDynamicBody3D); @@ -542,7 +542,7 @@ void register_scene_types() { GDREGISTER_CLASS(FogMaterial); GDREGISTER_CLASS(RemoteTransform3D); - GDREGISTER_VIRTUAL_CLASS(Joint3D); + GDREGISTER_ABSTRACT_CLASS(Joint3D); GDREGISTER_CLASS(PinJoint3D); GDREGISTER_CLASS(HingeJoint3D); GDREGISTER_CLASS(SliderJoint3D); @@ -560,14 +560,14 @@ void register_scene_types() { GDREGISTER_CLASS(Shader); GDREGISTER_CLASS(VisualShader); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNode); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNode); GDREGISTER_CLASS(VisualShaderNodeCustom); GDREGISTER_CLASS(VisualShaderNodeInput); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeOutput); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeResizableBase); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeGroupBase); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeConstant); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeVectorBase); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeOutput); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeResizableBase); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeGroupBase); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeConstant); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVectorBase); GDREGISTER_CLASS(VisualShaderNodeComment); GDREGISTER_CLASS(VisualShaderNodeFloatConstant); GDREGISTER_CLASS(VisualShaderNodeIntConstant); @@ -607,11 +607,11 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeTexture); GDREGISTER_CLASS(VisualShaderNodeCurveTexture); GDREGISTER_CLASS(VisualShaderNodeCurveXYZTexture); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeSample3D); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeSample3D); GDREGISTER_CLASS(VisualShaderNodeTexture2DArray); GDREGISTER_CLASS(VisualShaderNodeTexture3D); GDREGISTER_CLASS(VisualShaderNodeCubemap); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeUniform); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeUniform); GDREGISTER_CLASS(VisualShaderNodeUniformRef); GDREGISTER_CLASS(VisualShaderNodeFloatUniform); GDREGISTER_CLASS(VisualShaderNodeIntUniform); @@ -634,6 +634,9 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeCompare); GDREGISTER_CLASS(VisualShaderNodeMultiplyAdd); GDREGISTER_CLASS(VisualShaderNodeBillboard); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVarying); + GDREGISTER_CLASS(VisualShaderNodeVaryingSetter); + GDREGISTER_CLASS(VisualShaderNodeVaryingGetter); GDREGISTER_CLASS(VisualShaderNodeSDFToScreenUV); GDREGISTER_CLASS(VisualShaderNodeScreenUVToSDF); @@ -642,7 +645,7 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeSDFRaymarch); GDREGISTER_CLASS(VisualShaderNodeParticleOutput); - GDREGISTER_VIRTUAL_CLASS(VisualShaderNodeParticleEmitter); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeParticleEmitter); GDREGISTER_CLASS(VisualShaderNodeParticleSphereEmitter); GDREGISTER_CLASS(VisualShaderNodeParticleBoxEmitter); GDREGISTER_CLASS(VisualShaderNodeParticleRingEmitter); @@ -654,7 +657,7 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeParticleEmit); GDREGISTER_CLASS(ShaderMaterial); - GDREGISTER_VIRTUAL_CLASS(CanvasItem); + GDREGISTER_ABSTRACT_CLASS(CanvasItem); GDREGISTER_CLASS(CanvasTexture); GDREGISTER_CLASS(CanvasItemMaterial); SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes); @@ -673,8 +676,8 @@ void register_scene_types() { GDREGISTER_CLASS(Line2D); GDREGISTER_CLASS(MeshInstance2D); GDREGISTER_CLASS(MultiMeshInstance2D); - GDREGISTER_VIRTUAL_CLASS(CollisionObject2D); - GDREGISTER_VIRTUAL_CLASS(PhysicsBody2D); + GDREGISTER_ABSTRACT_CLASS(CollisionObject2D); + GDREGISTER_ABSTRACT_CLASS(PhysicsBody2D); GDREGISTER_CLASS(StaticBody2D); GDREGISTER_CLASS(AnimatableBody2D); GDREGISTER_CLASS(RigidDynamicBody2D); @@ -690,7 +693,7 @@ void register_scene_types() { GDREGISTER_CLASS(Polygon2D); GDREGISTER_CLASS(Skeleton2D); GDREGISTER_CLASS(Bone2D); - GDREGISTER_VIRTUAL_CLASS(Light2D); + GDREGISTER_ABSTRACT_CLASS(Light2D); GDREGISTER_CLASS(PointLight2D); GDREGISTER_CLASS(DirectionalLight2D); GDREGISTER_CLASS(LightOccluder2D); @@ -701,12 +704,12 @@ void register_scene_types() { GDREGISTER_CLASS(Camera2D); GDREGISTER_CLASS(AudioListener2D); - GDREGISTER_VIRTUAL_CLASS(Joint2D); + GDREGISTER_ABSTRACT_CLASS(Joint2D); GDREGISTER_CLASS(PinJoint2D); GDREGISTER_CLASS(GrooveJoint2D); GDREGISTER_CLASS(DampedSpringJoint2D); GDREGISTER_CLASS(TileSet); - GDREGISTER_VIRTUAL_CLASS(TileSetSource); + GDREGISTER_ABSTRACT_CLASS(TileSetSource); GDREGISTER_CLASS(TileSetAtlasSource); GDREGISTER_CLASS(TileSetScenesCollectionSource); GDREGISTER_CLASS(TileMapPattern); @@ -733,7 +736,7 @@ void register_scene_types() { /* REGISTER RESOURCES */ - GDREGISTER_VIRTUAL_CLASS(Shader); + GDREGISTER_ABSTRACT_CLASS(Shader); GDREGISTER_CLASS(ParticlesMaterial); SceneTree::add_idle_callback(ParticlesMaterial::flush_changes); ParticlesMaterial::init_shaders(); @@ -762,7 +765,7 @@ void register_scene_types() { GDREGISTER_CLASS(RibbonTrailMesh); GDREGISTER_CLASS(PointMesh); GDREGISTER_VIRTUAL_CLASS(Material); - GDREGISTER_VIRTUAL_CLASS(BaseMaterial3D); + GDREGISTER_ABSTRACT_CLASS(BaseMaterial3D); GDREGISTER_CLASS(StandardMaterial3D); GDREGISTER_CLASS(ORMMaterial3D); SceneTree::add_idle_callback(BaseMaterial3D::flush_changes); @@ -772,7 +775,7 @@ void register_scene_types() { OS::get_singleton()->yield(); // may take time to init - GDREGISTER_VIRTUAL_CLASS(Shape3D); + GDREGISTER_ABSTRACT_CLASS(Shape3D); GDREGISTER_CLASS(SeparationRayShape3D); GDREGISTER_CLASS(SphereShape3D); GDREGISTER_CLASS(BoxShape3D); @@ -805,7 +808,7 @@ void register_scene_types() { GDREGISTER_VIRTUAL_CLASS(Texture); GDREGISTER_VIRTUAL_CLASS(Texture2D); GDREGISTER_CLASS(Sky); - GDREGISTER_CLASS(StreamTexture2D); + GDREGISTER_CLASS(CompressedTexture2D); GDREGISTER_CLASS(ImageTexture); GDREGISTER_CLASS(AtlasTexture); GDREGISTER_CLASS(MeshTexture); @@ -817,17 +820,17 @@ void register_scene_types() { GDREGISTER_CLASS(AnimatedTexture); GDREGISTER_CLASS(CameraTexture); GDREGISTER_VIRTUAL_CLASS(TextureLayered); - GDREGISTER_VIRTUAL_CLASS(ImageTextureLayered); + GDREGISTER_ABSTRACT_CLASS(ImageTextureLayered); GDREGISTER_VIRTUAL_CLASS(Texture3D); GDREGISTER_CLASS(ImageTexture3D); - GDREGISTER_CLASS(StreamTexture3D); + GDREGISTER_CLASS(CompressedTexture3D); GDREGISTER_CLASS(Cubemap); GDREGISTER_CLASS(CubemapArray); GDREGISTER_CLASS(Texture2DArray); - GDREGISTER_VIRTUAL_CLASS(StreamTextureLayered); - GDREGISTER_CLASS(StreamCubemap); - GDREGISTER_CLASS(StreamCubemapArray); - GDREGISTER_CLASS(StreamTexture2DArray); + GDREGISTER_ABSTRACT_CLASS(CompressedTextureLayered); + GDREGISTER_CLASS(CompressedCubemap); + GDREGISTER_CLASS(CompressedCubemapArray); + GDREGISTER_CLASS(CompressedTexture2DArray); GDREGISTER_CLASS(Animation); GDREGISTER_CLASS(FontData); @@ -857,12 +860,12 @@ void register_scene_types() { #ifndef _3D_DISABLED GDREGISTER_CLASS(AudioStreamPlayer3D); #endif - GDREGISTER_VIRTUAL_CLASS(VideoStream); + GDREGISTER_ABSTRACT_CLASS(VideoStream); GDREGISTER_CLASS(AudioStreamSample); OS::get_singleton()->yield(); // may take time to init - GDREGISTER_VIRTUAL_CLASS(Shape2D); + GDREGISTER_ABSTRACT_CLASS(Shape2D); GDREGISTER_CLASS(WorldBoundaryShape2D); GDREGISTER_CLASS(SegmentShape2D); GDREGISTER_CLASS(SeparationRayShape2D); @@ -883,11 +886,11 @@ void register_scene_types() { OS::get_singleton()->yield(); // may take time to init - GDREGISTER_VIRTUAL_CLASS(SceneState); + GDREGISTER_ABSTRACT_CLASS(SceneState); GDREGISTER_CLASS(PackedScene); GDREGISTER_CLASS(SceneTree); - GDREGISTER_VIRTUAL_CLASS(SceneTreeTimer); // sorry, you can't create it + GDREGISTER_ABSTRACT_CLASS(SceneTreeTimer); // sorry, you can't create it #ifndef DISABLE_DEPRECATED // Dropped in 4.0, near approximation. @@ -925,8 +928,6 @@ void register_scene_types() { ClassDB::add_compatibility_class("ARVRServer", "XRServer"); ClassDB::add_compatibility_class("BoneAttachment", "BoneAttachment3D"); ClassDB::add_compatibility_class("BoxShape", "BoxShape3D"); - ClassDB::add_compatibility_class("BulletPhysicsDirectBodyState", "BulletPhysicsDirectBodyState3D"); - ClassDB::add_compatibility_class("BulletPhysicsServer", "BulletPhysicsServer3D"); ClassDB::add_compatibility_class("Camera", "Camera3D"); ClassDB::add_compatibility_class("CapsuleShape", "CapsuleShape3D"); ClassDB::add_compatibility_class("ClippedCamera", "ClippedCamera3D"); @@ -1013,7 +1014,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("SpringArm", "SpringArm3D"); ClassDB::add_compatibility_class("Sprite", "Sprite2D"); ClassDB::add_compatibility_class("StaticBody", "StaticBody3D"); - ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D"); + ClassDB::add_compatibility_class("StreamTexture", "CompressedTexture2D"); ClassDB::add_compatibility_class("TextureProgress", "TextureProgressBar"); ClassDB::add_compatibility_class("VehicleBody", "VehicleBody3D"); ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D"); @@ -1043,6 +1044,14 @@ void register_scene_types() { ClassDB::add_compatibility_class("VisualShaderNodeScalarDerivativeFunc", "VisualShaderNodeDerivativeFunc"); ClassDB::add_compatibility_class("VisualShaderNodeVectorDerivativeFunc", "VisualShaderNodeDerivativeFunc"); ClassDB::add_compatibility_class("World", "World3D"); + + // Renamed during 4.0 alpha, added to ease transition between alphas. + ClassDB::add_compatibility_class("StreamCubemap", "CompressedCubemap"); + ClassDB::add_compatibility_class("StreamCubemapArray", "CompressedCubemapArray"); + ClassDB::add_compatibility_class("StreamTexture2D", "CompressedTexture2D"); + ClassDB::add_compatibility_class("StreamTexture2DArray", "CompressedTexture2DArray"); + ClassDB::add_compatibility_class("StreamTexture3D", "CompressedTexture3D"); + ClassDB::add_compatibility_class("StreamTextureLayered", "CompressedTextureLayered"); #endif /* DISABLE_DEPRECATED */ OS::get_singleton()->yield(); // may take time to init @@ -1075,11 +1084,22 @@ void initialize_theme() { // Allow creating the default theme at a different scale to suit higher/lower base resolutions. float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + String theme_path = GLOBAL_DEF_RST("gui/theme/custom", ""); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", ""); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + bool font_antialiased = (bool)GLOBAL_DEF_RST("gui/theme/default_font_antialiased", true); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiased", PropertyInfo(Variant::BOOL, "gui/theme/default_font_antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + + TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST("gui/theme/default_font_subpixel_positioning", TextServer::SUBPIXEL_POSITIONING_AUTO); + ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_subpixel_positioning", PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); + Ref<Font> font; if (!font_path.is_empty()) { font = ResourceLoader::load(font_path); @@ -1090,7 +1110,7 @@ void initialize_theme() { // Always make the default theme to avoid invalid default font/icon/style in the given theme. if (RenderingServer::get_singleton()) { - make_default_theme(default_theme_scale, font); + make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiased); } if (!theme_path.is_empty()) { diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index b6151bccf4..f6e0df0265 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2320,22 +2320,12 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) { //mix of real and int + real_t a = p_a; + real_t b = p_b; + real_t pa = p_pre_a; + real_t pb = p_post_b; - real_t p0 = p_pre_a; - real_t p1 = p_a; - real_t p2 = p_b; - real_t p3 = p_post_b; - - real_t t = p_c; - real_t t2 = t * t; - real_t t3 = t2 * t; - - return 0.5f * - ((p1 * 2.0f) + - (-p0 + p2) * t + - (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 + - (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3); - + return Math::cubic_interpolate(a, b, pa, pb, p_c); } else if ((vformat & (vformat - 1))) { return p_a; //can't interpolate, mix of types } @@ -2423,7 +2413,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol real_t c = 0.0; // prepare for all cases of interpolation - if ((loop_mode == LOOP_LINEAR || loop_mode == LOOP_PINGPONG) && p_loop_wrap) { + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { // loop if (!p_backward) { // no backward @@ -2577,11 +2567,19 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol case INTERPOLATION_CUBIC: { int pre = idx - 1; if (pre < 0) { - pre = 0; + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + pre = len - 1; + } else { + pre = 0; + } } int post = next + 1; if (post >= len) { - post = next; + if (loop_mode == LOOP_LINEAR && p_loop_wrap) { + post = 0; + } else { + post = next; + } } return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c); @@ -4349,7 +4347,7 @@ struct AnimationCompressionDataState { if (temp_packets.size() == 0) { return; //nohing to do } -#define DEBUG_PACKET_PUSH +//#define DEBUG_PACKET_PUSH #ifdef DEBUG_PACKET_PUSH #ifndef _MSC_VER #warning Debugging packet push, disable this code in production to gain a bit more import performance. @@ -4380,7 +4378,7 @@ struct AnimationCompressionDataState { header_bytes += 2; } - while (header_bytes % 4 != 0) { + while (header_bytes < 8 && header_bytes % 4 != 0) { // First cond needed to silence wrong GCC warning. header[header_bytes++] = 0; } diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp index a1ec9a2230..1abbf366fd 100644 --- a/scene/resources/box_shape_3d.cpp +++ b/scene/resources/box_shape_3d.cpp @@ -77,6 +77,7 @@ bool BoxShape3D::_get(const StringName &p_name, Variant &r_property) const { #endif // DISABLE_DEPRECATED void BoxShape3D::set_size(const Vector3 &p_size) { + ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0 || p_size.z < 0, "BoxShape3D size cannot be negative."); size = p_size; _update_shape(); notify_change_to_owners(); diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 4d2698d27d..a1ad487bff 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -59,6 +59,7 @@ void CapsuleShape2D::_update_shape() { } void CapsuleShape2D::set_radius(real_t p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CapsuleShape2D radius cannot be negative."); radius = p_radius; if (radius > height * 0.5) { height = radius * 2.0; @@ -71,6 +72,7 @@ real_t CapsuleShape2D::get_radius() const { } void CapsuleShape2D::set_height(real_t p_height) { + ERR_FAIL_COND_MSG(p_height < 0, "CapsuleShape2D height cannot be negative."); height = p_height; if (radius > height * 0.5) { radius = height * 0.5; diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp index c16ddad984..2179ce82dd 100644 --- a/scene/resources/capsule_shape_3d.cpp +++ b/scene/resources/capsule_shape_3d.cpp @@ -79,6 +79,7 @@ void CapsuleShape3D::_update_shape() { } void CapsuleShape3D::set_radius(float p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CapsuleShape3D radius cannot be negative."); radius = p_radius; if (radius > height * 0.5) { height = radius * 2.0; @@ -92,6 +93,7 @@ float CapsuleShape3D::get_radius() const { } void CapsuleShape3D::set_height(float p_height) { + ERR_FAIL_COND_MSG(p_height < 0, "CapsuleShape3D height cannot be negative."); height = p_height; if (radius > height * 0.5) { radius = height * 0.5; diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index 9c16ac2eed..de931fca7e 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -43,6 +43,7 @@ void CircleShape2D::_update_shape() { } void CircleShape2D::set_radius(real_t p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CircleShape2D radius cannot be negative."); radius = p_radius; _update_shape(); } diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp index 5eeb62d17b..c4f1cba341 100644 --- a/scene/resources/cylinder_shape_3d.cpp +++ b/scene/resources/cylinder_shape_3d.cpp @@ -72,6 +72,7 @@ void CylinderShape3D::_update_shape() { } void CylinderShape3D::set_radius(float p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "CylinderShape3D radius cannot be negative."); radius = p_radius; _update_shape(); notify_change_to_owners(); @@ -82,6 +83,7 @@ float CylinderShape3D::get_radius() const { } void CylinderShape3D::set_height(float p_height) { + ERR_FAIL_COND_MSG(p_height < 0, "CylinderShape3D height cannot be negative."); height = p_height; _update_shape(); notify_change_to_owners(); diff --git a/scene/resources/default_theme/color_picker_sample.svg b/scene/resources/default_theme/color_picker_sample.svg deleted file mode 100644 index 140ac20a99..0000000000 --- a/scene/resources/default_theme/color_picker_sample.svg +++ /dev/null @@ -1 +0,0 @@ -<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 256 20" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m0 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m5 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m80 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m85 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m159.978 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m164.978 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m39.991 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m44.991 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m119.99 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m124.99 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m199.968 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m204.968 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m9.98 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m14.98 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m89.98 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m94.98 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m169.957 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m174.957 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m49.97 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m54.97 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m129.97 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m134.97 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m209.948 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m214.948 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m19.995 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m24.995 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m99.995 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m104.995 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m179.973 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m184.973 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m59.986 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m64.986 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m139.986 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m144.986 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m219.964 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m224.964 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m30.011 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m35.011 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m110.011 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m115.011 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m189.989 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m194.989 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m70.001 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m75.001 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m150.001 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m155.001 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m229.979 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m234.979 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m240.017 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m245.017 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m249.996 0v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m254.996 0v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m249.996 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m254.996 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m240.017 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m245.017 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m0 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m5 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m80 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m85 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m159.978 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m164.978 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m39.991 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m44.991 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m119.99 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m124.99 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m199.968 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m204.968 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m9.98 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m14.98 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m89.98 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m94.98 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m169.957 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m174.957 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m49.97 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m54.97 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m129.97 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m134.97 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m209.948 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m214.948 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m19.995 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m24.995 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m99.995 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m104.995 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m179.973 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m184.973 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m59.986 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m64.986 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m139.986 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m144.986 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m219.964 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m224.964 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m30.011 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m35.011 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m110.011 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m115.011 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m189.989 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m194.989 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m70.001 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m75.001 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m150.001 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m155.001 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/><path d="m229.979 10v5h5v-5zm5 5v5h5v-5z" fill="#e0e0e0"/><path d="m234.979 10v5h5v-5zm0 5h-5v5h5z" fill="#fff"/></g></svg> diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index c92a46a98c..da37228ed9 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -103,7 +103,7 @@ static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margi return style; } -void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale) { +void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale) { scale = p_scale; // Font colors @@ -466,7 +466,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Te theme->set_color("completion_background_color", "CodeEdit", Color(0.17, 0.16, 0.2)); theme->set_color("completion_selected_color", "CodeEdit", Color(0.26, 0.26, 0.27)); theme->set_color("completion_existing_color", "CodeEdit", Color(0.87, 0.87, 0.87, 0.13)); - theme->set_color("completion_scroll_color", "CodeEdit", control_font_pressed_color); + theme->set_color("completion_scroll_color", "CodeEdit", control_font_pressed_color * Color(1, 1, 1, 0.29)); theme->set_color("completion_font_color", "CodeEdit", Color(0.67, 0.67, 0.67)); theme->set_color("font_color", "CodeEdit", control_font_color); theme->set_color("font_selected_color", "CodeEdit", Color(0, 0, 0)); @@ -490,7 +490,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Te theme->set_constant("completion_lines", "CodeEdit", 7); theme->set_constant("completion_max_width", "CodeEdit", 50); - theme->set_constant("completion_scroll_width", "CodeEdit", 3); + theme->set_constant("completion_scroll_width", "CodeEdit", 6); theme->set_constant("line_spacing", "CodeEdit", 4 * scale); theme->set_constant("outline_size", "CodeEdit", 0); @@ -864,7 +864,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Te theme->set_icon("screen_picker", "ColorPicker", icons["color_picker_pipette"]); theme->set_icon("add_preset", "ColorPicker", icons["add"]); theme->set_icon("color_hue", "ColorPicker", icons["color_picker_hue"]); - theme->set_icon("color_sample", "ColorPicker", icons["color_picker_sample"]); theme->set_icon("sample_bg", "ColorPicker", icons["mini_checkerboard"]); theme->set_icon("overbright_indicator", "ColorPicker", icons["color_picker_overbright"]); theme->set_icon("bar_arrow", "ColorPicker", icons["color_picker_bar_arrow"]); @@ -925,9 +924,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Te theme->set_stylebox("normal", "RichTextLabel", make_empty_stylebox(0, 0, 0, 0)); theme->set_font("normal_font", "RichTextLabel", Ref<Font>()); - theme->set_font("bold_font", "RichTextLabel", Ref<Font>()); - theme->set_font("italics_font", "RichTextLabel", Ref<Font>()); - theme->set_font("bold_italics_font", "RichTextLabel", Ref<Font>()); + theme->set_font("bold_font", "RichTextLabel", bold_font); + theme->set_font("italics_font", "RichTextLabel", italics_font); + theme->set_font("bold_italics_font", "RichTextLabel", bold_italics_font); theme->set_font("mono_font", "RichTextLabel", Ref<Font>()); theme->set_font_size("normal_font_size", "RichTextLabel", -1); @@ -1019,13 +1018,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Te default_style = make_flat_stylebox(Color(1, 0.365, 0.365), 4, 4, 4, 4, 0, false, 2); } -void make_default_theme(float p_scale, Ref<Font> p_font) { +void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_subpixel, TextServer::Hinting p_hinting, bool p_aa) { Ref<Theme> t; t.instantiate(); Ref<StyleBox> default_style; Ref<Texture2D> default_icon; Ref<Font> default_font; + Ref<Font> bold_font; + Ref<Font> bold_italics_font; + Ref<Font> italics_font; float default_scale = CLAMP(p_scale, 0.5, 8.0); if (p_font.is_valid()) { @@ -1041,12 +1043,39 @@ void make_default_theme(float p_scale, Ref<Font> p_font) { Ref<FontData> dynamic_font_data; dynamic_font_data.instantiate(); dynamic_font_data->set_data_ptr(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size); + dynamic_font_data->set_subpixel_positioning(p_subpixel); + dynamic_font_data->set_hinting(p_hinting); + dynamic_font_data->set_antialiased(p_aa); dynamic_font->add_data(dynamic_font_data); default_font = dynamic_font; } - fill_default_theme(t, default_font, default_icon, default_style, default_scale); + if (default_font.is_valid()) { + bold_font.instantiate(); + for (int i = 0; i < default_font->get_data_count(); i++) { + Ref<FontData> data = default_font->get_data(i)->duplicate(); + data->set_embolden(1.2); + bold_font->add_data(data); + } + + bold_italics_font.instantiate(); + for (int i = 0; i < default_font->get_data_count(); i++) { + Ref<FontData> data = default_font->get_data(i)->duplicate(); + data->set_embolden(1.2); + data->set_transform(Transform2D(1.0, 0.4, 0.0, 1.0, 0.0, 0.0)); + bold_italics_font->add_data(data); + } + + italics_font.instantiate(); + for (int i = 0; i < default_font->get_data_count(); i++) { + Ref<FontData> data = default_font->get_data(i)->duplicate(); + data->set_transform(Transform2D(1.0, 0.4, 0.0, 1.0, 0.0, 0.0)); + italics_font->add_data(data); + } + } + + fill_default_theme(t, default_font, bold_font, bold_italics_font, italics_font, default_icon, default_style, default_scale); Theme::set_default(t); Theme::set_fallback_base_scale(default_scale); diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index 3016517824..a9e21dda3f 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -35,8 +35,8 @@ const int default_font_size = 16; -void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale); -void make_default_theme(float p_scale, Ref<Font> p_font); +void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale); +void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_subpixel, TextServer::Hinting p_hinting, bool p_aa); void clear_default_theme(); #endif diff --git a/scene/resources/default_theme/mini_checkerboard.svg b/scene/resources/default_theme/mini_checkerboard.svg index 0ae6a855bd..03438f75a6 100644 --- a/scene/resources/default_theme/mini_checkerboard.svg +++ b/scene/resources/default_theme/mini_checkerboard.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-linecap="round" stroke-linejoin="round" stroke-width="1.9994"><path d="m0 0v8h8v-8zm8 8v8h8v-8z" fill="#e0e0e0"/><path d="m8 0v8h8v-8zm0 8h-8v8h8z" fill="#fff"/></g></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g stroke-width="2"><path d="m0 0v8h8v-8zm8 8v8h8v-8z" fill="#808080"/><path d="m8 0v8h8v-8zm0 8h-8v8h8z" fill="#fff"/></g></svg> diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index bf17a6ea97..82d8ad4444 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -155,7 +155,9 @@ float Environment::get_ambient_light_energy() const { } void Environment::set_ambient_light_sky_contribution(float p_ratio) { - ambient_sky_contribution = p_ratio; + // Sky contribution values outside the [0.0; 1.0] range don't make sense and + // can result in negative colors. + ambient_sky_contribution = CLAMP(p_ratio, 0.0, 1.0); _update_ambient_light(); } diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index b512acdd8a..ce2a675854 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -60,6 +60,9 @@ _FORCE_INLINE_ void FontData::_ensure_rid(int p_cache_index) const { TS->font_set_fixed_size(cache[p_cache_index], fixed_size); TS->font_set_force_autohinter(cache[p_cache_index], force_autohinter); TS->font_set_hinting(cache[p_cache_index], hinting); + TS->font_set_subpixel_positioning(cache[p_cache_index], subpixel_positioning); + TS->font_set_embolden(cache[p_cache_index], embolden); + TS->font_set_transform(cache[p_cache_index], transform); TS->font_set_oversampling(cache[p_cache_index], oversampling); } } @@ -101,6 +104,15 @@ void FontData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hinting", "hinting"), &FontData::set_hinting); ClassDB::bind_method(D_METHOD("get_hinting"), &FontData::get_hinting); + ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &FontData::set_subpixel_positioning); + ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &FontData::get_subpixel_positioning); + + ClassDB::bind_method(D_METHOD("set_embolden", "strength"), &FontData::set_embolden); + ClassDB::bind_method(D_METHOD("get_embolden"), &FontData::get_embolden); + + ClassDB::bind_method(D_METHOD("set_transform", "transform"), &FontData::set_transform); + ClassDB::bind_method(D_METHOD("get_transform"), &FontData::get_transform); + ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &FontData::set_oversampling); ClassDB::bind_method(D_METHOD("get_oversampling"), &FontData::get_oversampling); @@ -204,6 +216,9 @@ void FontData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name"); ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_STORAGE), "set_subpixel_positioning", "get_subpixel_positioning"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_RANGE, "-2,2,0.01", PROPERTY_USAGE_STORAGE), "set_embolden", "get_embolden"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field"); ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_pixel_range", "get_msdf_pixel_range"); ADD_PROPERTY(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_msdf_size", "get_msdf_size"); @@ -430,9 +445,12 @@ void FontData::reset_state() { msdf = false; force_autohinter = false; hinting = TextServer::HINTING_LIGHT; + subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED; msdf_pixel_range = 14; msdf_size = 128; fixed_size = 0; + embolden = 0.f; + transform = Transform2D(); oversampling = 0.f; } @@ -1364,6 +1382,51 @@ TextServer::Hinting FontData::get_hinting() const { return hinting; } +void FontData::set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel) { + if (subpixel_positioning != p_subpixel) { + subpixel_positioning = p_subpixel; + for (int i = 0; i < cache.size(); i++) { + _ensure_rid(i); + TS->font_set_subpixel_positioning(cache[i], subpixel_positioning); + } + emit_changed(); + } +} + +TextServer::SubpixelPositioning FontData::get_subpixel_positioning() const { + return subpixel_positioning; +} + +void FontData::set_embolden(float p_strength) { + if (embolden != p_strength) { + embolden = p_strength; + for (int i = 0; i < cache.size(); i++) { + _ensure_rid(i); + TS->font_set_embolden(cache[i], embolden); + } + emit_changed(); + } +} + +float FontData::get_embolden() const { + return embolden; +} + +void FontData::set_transform(Transform2D p_transform) { + if (transform != p_transform) { + transform = p_transform; + for (int i = 0; i < cache.size(); i++) { + _ensure_rid(i); + TS->font_set_transform(cache[i], transform); + } + emit_changed(); + } +} + +Transform2D FontData::get_transform() const { + return transform; +} + void FontData::set_oversampling(real_t p_oversampling) { if (oversampling != p_oversampling) { oversampling = p_oversampling; diff --git a/scene/resources/font.h b/scene/resources/font.h index 93351a3493..0185b019f1 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -55,7 +55,10 @@ class FontData : public Resource { int fixed_size = 0; bool force_autohinter = false; TextServer::Hinting hinting = TextServer::HINTING_LIGHT; + TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO; real_t oversampling = 0.f; + real_t embolden = 0.f; + Transform2D transform; // Cache. mutable Vector<RID> cache; @@ -118,6 +121,15 @@ public: virtual void set_hinting(TextServer::Hinting p_hinting); virtual TextServer::Hinting get_hinting() const; + virtual void set_subpixel_positioning(TextServer::SubpixelPositioning p_subpixel); + virtual TextServer::SubpixelPositioning get_subpixel_positioning() const; + + virtual void set_embolden(float p_strength); + virtual float get_embolden() const; + + virtual void set_transform(Transform2D p_transform); + virtual Transform2D get_transform() const; + virtual void set_oversampling(real_t p_oversampling); virtual real_t get_oversampling() const; diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 92ab091b86..30deb5ccd5 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -275,6 +275,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli PackedInt32Array indices = surfaces[i].arrays[RS::ARRAY_INDEX]; Vector<Vector3> normals = surfaces[i].arrays[RS::ARRAY_NORMAL]; Vector<Vector2> uvs = surfaces[i].arrays[RS::ARRAY_TEX_UV]; + Vector<Vector2> uv2s = surfaces[i].arrays[RS::ARRAY_TEX_UV2]; unsigned int index_count = indices.size(); unsigned int vertex_count = vertices.size(); @@ -287,7 +288,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli const int *indices_ptr = indices.ptr(); if (normals.is_empty()) { - normals.resize(vertices.size()); + normals.resize(index_count); Vector3 *n_ptr = normals.ptrw(); for (unsigned int j = 0; j < index_count; j += 3) { const Vector3 &v0 = vertices_ptr[indices_ptr[j + 0]]; @@ -313,6 +314,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli LocalVector<Vector3> merged_normals; LocalVector<int> merged_normals_counts; const Vector2 *uvs_ptr = uvs.ptr(); + const Vector2 *uv2s_ptr = uv2s.ptr(); for (unsigned int j = 0; j < vertex_count; j++) { const Vector3 &v = vertices_ptr[j]; @@ -327,8 +329,10 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli for (unsigned int k = 0; k < close_verts.size(); k++) { const Pair<int, int> &idx = close_verts[k]; - // TODO check more attributes? - if ((!uvs_ptr || uvs_ptr[j].distance_squared_to(uvs_ptr[idx.second]) < CMP_EPSILON2) && normals[idx.second].dot(n) > normal_merge_threshold) { + bool is_uvs_close = (!uvs_ptr || uvs_ptr[j].distance_squared_to(uvs_ptr[idx.second]) < CMP_EPSILON2); + bool is_uv2s_close = (!uv2s_ptr || uv2s_ptr[j].distance_squared_to(uv2s_ptr[idx.second]) < CMP_EPSILON2); + bool is_normals_close = normals[idx.second].dot(n) > normal_merge_threshold; + if (is_uvs_close && is_uv2s_close && is_normals_close) { vertex_remap.push_back(idx.first); merged_normals[idx.first] += normals[idx.second]; merged_normals_counts[idx.first]++; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index b74f44c52f..a0e6cc28ce 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -88,6 +88,37 @@ void Material::inspect_native_shader_code() { } } +RID Material::get_shader_rid() const { + RID ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_shader_rid, ret)) { + return ret; + } + return RID(); +} +Shader::Mode Material::get_shader_mode() const { + Shader::Mode ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_shader_mode, ret)) { + return ret; + } + + return Shader::MODE_MAX; +} + +bool Material::_can_do_next_pass() const { + bool ret; + if (GDVIRTUAL_CALL(_can_do_next_pass, ret)) { + return ret; + } + return false; +} +bool Material::_can_use_render_priority() const { + bool ret; + if (GDVIRTUAL_CALL(_can_use_render_priority, ret)) { + return ret; + } + return false; +} + void Material::_bind_methods() { ClassDB::bind_method(D_METHOD("set_next_pass", "next_pass"), &Material::set_next_pass); ClassDB::bind_method(D_METHOD("get_next_pass"), &Material::get_next_pass); @@ -103,6 +134,11 @@ void Material::_bind_methods() { BIND_CONSTANT(RENDER_PRIORITY_MAX); BIND_CONSTANT(RENDER_PRIORITY_MIN); + + GDVIRTUAL_BIND(_get_shader_rid) + GDVIRTUAL_BIND(_get_shader_mode) + GDVIRTUAL_BIND(_can_do_next_pass) + GDVIRTUAL_BIND(_can_use_render_priority) } Material::Material() { @@ -330,7 +366,7 @@ void BaseMaterial3D::init_shaders() { shader_names->rim = "rim"; shader_names->rim_tint = "rim_tint"; shader_names->clearcoat = "clearcoat"; - shader_names->clearcoat_gloss = "clearcoat_gloss"; + shader_names->clearcoat_roughness = "clearcoat_roughness"; shader_names->anisotropy = "anisotropy_ratio"; shader_names->heightmap_scale = "heightmap_scale"; shader_names->subsurface_scattering_strength = "subsurface_scattering_strength"; @@ -541,12 +577,6 @@ void BaseMaterial3D::_update_shader() { case SPECULAR_SCHLICK_GGX: code += ",specular_schlick_ggx"; break; - case SPECULAR_BLINN: - code += ",specular_blinn"; - break; - case SPECULAR_PHONG: - code += ",specular_phong"; - break; case SPECULAR_TOON: code += ",specular_toon"; break; @@ -690,7 +720,7 @@ void BaseMaterial3D::_update_shader() { } if (features[FEATURE_CLEARCOAT]) { code += "uniform float clearcoat : hint_range(0,1);\n"; - code += "uniform float clearcoat_gloss : hint_range(0,1);\n"; + code += "uniform float clearcoat_roughness : hint_range(0,1);\n"; code += "uniform sampler2D texture_clearcoat : hint_white," + texfilter_str + ";\n"; } if (features[FEATURE_ANISOTROPY]) { @@ -1166,7 +1196,7 @@ void BaseMaterial3D::_update_shader() { code += " vec2 clearcoat_tex = texture(texture_clearcoat,base_uv).xy;\n"; } code += " CLEARCOAT = clearcoat*clearcoat_tex.x;"; - code += " CLEARCOAT_GLOSS = clearcoat_gloss*clearcoat_tex.y;\n"; + code += " CLEARCOAT_ROUGHNESS = clearcoat_roughness*clearcoat_tex.y;\n"; } if (features[FEATURE_ANISOTROPY]) { @@ -1408,13 +1438,13 @@ float BaseMaterial3D::get_clearcoat() const { return clearcoat; } -void BaseMaterial3D::set_clearcoat_gloss(float p_clearcoat_gloss) { - clearcoat_gloss = p_clearcoat_gloss; - RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_gloss, p_clearcoat_gloss); +void BaseMaterial3D::set_clearcoat_roughness(float p_clearcoat_roughness) { + clearcoat_roughness = p_clearcoat_roughness; + RS::get_singleton()->material_set_param(_get_material(), shader_names->clearcoat_roughness, p_clearcoat_roughness); } -float BaseMaterial3D::get_clearcoat_gloss() const { - return clearcoat_gloss; +float BaseMaterial3D::get_clearcoat_roughness() const { + return clearcoat_roughness; } void BaseMaterial3D::set_anisotropy(float p_anisotropy) { @@ -2271,8 +2301,8 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_clearcoat", "clearcoat"), &BaseMaterial3D::set_clearcoat); ClassDB::bind_method(D_METHOD("get_clearcoat"), &BaseMaterial3D::get_clearcoat); - ClassDB::bind_method(D_METHOD("set_clearcoat_gloss", "clearcoat_gloss"), &BaseMaterial3D::set_clearcoat_gloss); - ClassDB::bind_method(D_METHOD("get_clearcoat_gloss"), &BaseMaterial3D::get_clearcoat_gloss); + ClassDB::bind_method(D_METHOD("set_clearcoat_roughness", "clearcoat_roughness"), &BaseMaterial3D::set_clearcoat_roughness); + ClassDB::bind_method(D_METHOD("get_clearcoat_roughness"), &BaseMaterial3D::get_clearcoat_roughness); ClassDB::bind_method(D_METHOD("set_anisotropy", "anisotropy"), &BaseMaterial3D::set_anisotropy); ClassDB::bind_method(D_METHOD("get_anisotropy"), &BaseMaterial3D::get_anisotropy); @@ -2438,7 +2468,7 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Shading", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Toon"), "set_diffuse_mode", "get_diffuse_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Blinn,Phong,Toon,Disabled"), "set_specular_mode", "get_specular_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Toon,Disabled"), "set_specular_mode", "get_specular_mode"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT); ADD_GROUP("Vertex Color", "vertex_color"); @@ -2486,7 +2516,7 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Clearcoat", "clearcoat_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "clearcoat_enabled"), "set_feature", "get_feature", FEATURE_CLEARCOAT); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clearcoat", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat", "get_clearcoat"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clearcoat_gloss", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat_gloss", "get_clearcoat_gloss"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "clearcoat_roughness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat_roughness", "get_clearcoat_roughness"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "clearcoat_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_CLEARCOAT); ADD_GROUP("Anisotropy", "anisotropy_"); @@ -2693,8 +2723,6 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(DIFFUSE_TOON); BIND_ENUM_CONSTANT(SPECULAR_SCHLICK_GGX); - BIND_ENUM_CONSTANT(SPECULAR_BLINN); - BIND_ENUM_CONSTANT(SPECULAR_PHONG); BIND_ENUM_CONSTANT(SPECULAR_TOON); BIND_ENUM_CONSTANT(SPECULAR_DISABLED); @@ -2732,7 +2760,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_rim(1.0); set_rim_tint(0.5); set_clearcoat(1); - set_clearcoat_gloss(0.5); + set_clearcoat_roughness(0.5); set_anisotropy(0); set_heightmap_scale(0.05); set_subsurface_scattering_strength(0); diff --git a/scene/resources/material.h b/scene/resources/material.h index 57591bee2f..07227c037c 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -51,11 +51,15 @@ class Material : public Resource { protected: _FORCE_INLINE_ RID _get_material() const { return material; } static void _bind_methods(); - virtual bool _can_do_next_pass() const { return false; } - virtual bool _can_use_render_priority() const { return false; } + virtual bool _can_do_next_pass() const; + virtual bool _can_use_render_priority() const; void _validate_property(PropertyInfo &property) const override; + GDVIRTUAL0RC(RID, _get_shader_rid) + GDVIRTUAL0RC(Shader::Mode, _get_shader_mode) + GDVIRTUAL0RC(bool, _can_do_next_pass) + GDVIRTUAL0RC(bool, _can_use_render_priority) public: enum { RENDER_PRIORITY_MAX = RS::MATERIAL_RENDER_PRIORITY_MAX, @@ -68,9 +72,8 @@ public: int get_render_priority() const; virtual RID get_rid() const override; - virtual RID get_shader_rid() const = 0; - - virtual Shader::Mode get_shader_mode() const = 0; + virtual RID get_shader_rid() const; + virtual Shader::Mode get_shader_mode() const; Material(); virtual ~Material(); }; @@ -252,8 +255,6 @@ public: enum SpecularMode { SPECULAR_SCHLICK_GGX, - SPECULAR_BLINN, - SPECULAR_PHONG, SPECULAR_TOON, SPECULAR_DISABLED, SPECULAR_MAX @@ -387,7 +388,7 @@ private: StringName rim; StringName rim_tint; StringName clearcoat; - StringName clearcoat_gloss; + StringName clearcoat_roughness; StringName anisotropy; StringName heightmap_scale; StringName subsurface_scattering_strength; @@ -454,7 +455,7 @@ private: float rim; float rim_tint; float clearcoat; - float clearcoat_gloss; + float clearcoat_roughness; float anisotropy; float heightmap_scale; float subsurface_scattering_strength; @@ -572,8 +573,8 @@ public: void set_clearcoat(float p_clearcoat); float get_clearcoat() const; - void set_clearcoat_gloss(float p_clearcoat_gloss); - float get_clearcoat_gloss() const; + void set_clearcoat_roughness(float p_clearcoat_roughness); + float get_clearcoat_roughness() const; void set_anisotropy(float p_anisotropy); float get_anisotropy() const; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 441e84eccc..3c67a20f50 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -40,6 +40,122 @@ Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr; +int Mesh::get_surface_count() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_surface_count, ret)) { + return ret; + } + return 0; +} + +int Mesh::surface_get_array_len(int p_idx) const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_array_len, p_idx, ret)) { + return ret; + } + return 0; +} + +int Mesh::surface_get_array_index_len(int p_idx) const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_array_index_len, p_idx, ret)) { + return ret; + } + return 0; +} + +Array Mesh::surface_get_arrays(int p_surface) const { + Array ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_arrays, p_surface, ret)) { + return ret; + } + return Array(); +} + +Array Mesh::surface_get_blend_shape_arrays(int p_surface) const { + Array ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_blend_shape_arrays, p_surface, ret)) { + return ret; + } + + return Array(); +} + +Dictionary Mesh::surface_get_lods(int p_surface) const { + Dictionary ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_lods, p_surface, ret)) { + return ret; + } + + return Dictionary(); +} + +uint32_t Mesh::surface_get_format(int p_idx) const { + uint32_t ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_format, p_idx, ret)) { + return ret; + } + + return 0; +} + +Mesh::PrimitiveType Mesh::surface_get_primitive_type(int p_idx) const { + uint32_t ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_primitive_type, p_idx, ret)) { + return (Mesh::PrimitiveType)ret; + } + + return PRIMITIVE_MAX; +} + +void Mesh::surface_set_material(int p_idx, const Ref<Material> &p_material) { + if (GDVIRTUAL_REQUIRED_CALL(_surface_set_material, p_idx, p_material)) { + return; + } +} + +Ref<Material> Mesh::surface_get_material(int p_idx) const { + Ref<Material> ret; + if (GDVIRTUAL_REQUIRED_CALL(_surface_get_material, p_idx, ret)) { + return ret; + } + + return Ref<Material>(); +} + +int Mesh::get_blend_shape_count() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_blend_shape_count, ret)) { + return ret; + } + + return 0; +} + +StringName Mesh::get_blend_shape_name(int p_index) const { + StringName ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_blend_shape_name, p_index, ret)) { + return ret; + } + + return StringName(); +} + +void Mesh::set_blend_shape_name(int p_index, const StringName &p_name) { + if (GDVIRTUAL_REQUIRED_CALL(_set_blend_shape_name, p_index, p_name)) { + return; + } +} + +AABB Mesh::get_aabb() const { + AABB ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_aabb, ret)) { + return ret; + } + + return AABB(); +} + Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) { return triangle_mesh; @@ -502,6 +618,21 @@ void Mesh::_bind_methods() { BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); + + GDVIRTUAL_BIND(_get_surface_count) + GDVIRTUAL_BIND(_surface_get_array_len, "index") + GDVIRTUAL_BIND(_surface_get_array_index_len, "index") + GDVIRTUAL_BIND(_surface_get_arrays, "index") + GDVIRTUAL_BIND(_surface_get_blend_shape_arrays, "index") + GDVIRTUAL_BIND(_surface_get_lods, "index") + GDVIRTUAL_BIND(_surface_get_format, "index") + GDVIRTUAL_BIND(_surface_get_primitive_type, "index") + GDVIRTUAL_BIND(_surface_set_material, "index", "material") + GDVIRTUAL_BIND(_surface_get_material, "index") + GDVIRTUAL_BIND(_get_blend_shape_count) + GDVIRTUAL_BIND(_get_blend_shape_name, "index") + GDVIRTUAL_BIND(_set_blend_shape_name, "index", "name") + GDVIRTUAL_BIND(_get_aabb) } void Mesh::clear_cache() const { @@ -1684,6 +1815,7 @@ Error ArrayMesh::lightmap_unwrap(const Transform3D &p_base_transform, float p_te Error ArrayMesh::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, bool p_generate_cache) { ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes."); + ERR_FAIL_COND_V_MSG(p_texel_size <= 0.0f, ERR_PARAMETER_RANGE_ERROR, "Texel size must be greater than 0."); LocalVector<float> vertices; LocalVector<float> normals; diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 08d834bdb9..652c045a24 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -45,9 +45,34 @@ class Mesh : public Resource { mutable Vector<Vector3> debug_lines; Size2i lightmap_size_hint; +public: + enum PrimitiveType { + PRIMITIVE_POINTS = RenderingServer::PRIMITIVE_POINTS, + PRIMITIVE_LINES = RenderingServer::PRIMITIVE_LINES, + PRIMITIVE_LINE_STRIP = RenderingServer::PRIMITIVE_LINE_STRIP, + PRIMITIVE_TRIANGLES = RenderingServer::PRIMITIVE_TRIANGLES, + PRIMITIVE_TRIANGLE_STRIP = RenderingServer::PRIMITIVE_TRIANGLE_STRIP, + PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX, + }; + protected: static void _bind_methods(); + GDVIRTUAL0RC(int, _get_surface_count) + GDVIRTUAL1RC(int, _surface_get_array_len, int) + GDVIRTUAL1RC(int, _surface_get_array_index_len, int) + GDVIRTUAL1RC(Array, _surface_get_arrays, int) + GDVIRTUAL1RC(Array, _surface_get_blend_shape_arrays, int) + GDVIRTUAL1RC(Dictionary, _surface_get_lods, int) + GDVIRTUAL1RC(uint32_t, _surface_get_format, int) + GDVIRTUAL1RC(uint32_t, _surface_get_primitive_type, int) + GDVIRTUAL2(_surface_set_material, int, Ref<Material>) + GDVIRTUAL1RC(Ref<Material>, _surface_get_material, int) + GDVIRTUAL0RC(int, _get_blend_shape_count) + GDVIRTUAL1RC(StringName, _get_blend_shape_name, int) + GDVIRTUAL2(_set_blend_shape_name, int, StringName) + GDVIRTUAL0RC(AABB, _get_aabb) + public: enum { NO_INDEX_ARRAY = RenderingServer::NO_INDEX_ARRAY, @@ -120,28 +145,20 @@ public: }; - enum PrimitiveType { - PRIMITIVE_POINTS = RenderingServer::PRIMITIVE_POINTS, - PRIMITIVE_LINES = RenderingServer::PRIMITIVE_LINES, - PRIMITIVE_LINE_STRIP = RenderingServer::PRIMITIVE_LINE_STRIP, - PRIMITIVE_TRIANGLES = RenderingServer::PRIMITIVE_TRIANGLES, - PRIMITIVE_TRIANGLE_STRIP = RenderingServer::PRIMITIVE_TRIANGLE_STRIP, - PRIMITIVE_MAX = RenderingServer::PRIMITIVE_MAX, - }; - - virtual int get_surface_count() const = 0; - virtual int surface_get_array_len(int p_idx) const = 0; - virtual int surface_get_array_index_len(int p_idx) const = 0; - virtual Array surface_get_arrays(int p_surface) const = 0; - virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0; - virtual Dictionary surface_get_lods(int p_surface) const = 0; - virtual uint32_t surface_get_format(int p_idx) const = 0; - virtual PrimitiveType surface_get_primitive_type(int p_idx) const = 0; - virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) = 0; - virtual Ref<Material> surface_get_material(int p_idx) const = 0; - virtual int get_blend_shape_count() const = 0; - virtual StringName get_blend_shape_name(int p_index) const = 0; - virtual void set_blend_shape_name(int p_index, const StringName &p_name) = 0; + virtual int get_surface_count() const; + virtual int surface_get_array_len(int p_idx) const; + virtual int surface_get_array_index_len(int p_idx) const; + virtual Array surface_get_arrays(int p_surface) const; + virtual Array surface_get_blend_shape_arrays(int p_surface) const; + virtual Dictionary surface_get_lods(int p_surface) const; + virtual uint32_t surface_get_format(int p_idx) const; + virtual PrimitiveType surface_get_primitive_type(int p_idx) const; + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material); + virtual Ref<Material> surface_get_material(int p_idx) const; + virtual int get_blend_shape_count() const; + virtual StringName get_blend_shape_name(int p_index) const; + virtual void set_blend_shape_name(int p_index, const StringName &p_name); + virtual AABB get_aabb() const; Vector<Face3> get_faces() const; Ref<TriangleMesh> generate_triangle_mesh() const; @@ -153,8 +170,6 @@ public: Ref<Mesh> create_outline(float p_margin) const; - virtual AABB get_aabb() const = 0; - void set_lightmap_size_hint(const Size2i &p_size); Size2i get_lightmap_size_hint() const; void clear_cache() const; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index f9a4eba978..2f1ac7a83a 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -529,10 +529,6 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map if (!gi.persistent) { continue; } - /* - if (instance_state_node>=0 && instance_state->is_node_in_group(instance_state_node,gi.name)) - continue; //group was instantiated, don't add here - */ bool skip = false; for (const SceneState::PackState &ia : states_stack) { @@ -1657,7 +1653,7 @@ void PackedScene::recreate_state() { #endif } -Ref<SceneState> PackedScene::get_state() { +Ref<SceneState> PackedScene::get_state() const { return state; } diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 81b38840d9..96222937d0 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -228,7 +228,7 @@ public: virtual void set_last_modified_time(uint64_t p_time) override { state->set_last_modified_time(p_time); } #endif - Ref<SceneState> get_state(); + Ref<SceneState> get_state() const; PackedScene(); }; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 38acd0af0a..781e219f1f 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -36,11 +36,17 @@ */ void PrimitiveMesh::_update() const { Array arr; - arr.resize(RS::ARRAY_MAX); - _create_mesh_array(arr); + if (GDVIRTUAL_CALL(_create_mesh_array, arr)) { + ERR_FAIL_COND_MSG(arr.size() != RS::ARRAY_MAX, "_create_mesh_array must return an array of Mesh.ARRAY_MAX elements."); + } else { + arr.resize(RS::ARRAY_MAX); + _create_mesh_array(arr); + } Vector<Vector3> points = arr[RS::ARRAY_VERTEX]; + ERR_FAIL_COND_MSG(points.size() == 0, "_create_mesh_array must return at least a vertex array."); + aabb = AABB(); int pc = points.size(); @@ -210,6 +216,8 @@ void PrimitiveMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces"); + + GDVIRTUAL_BIND(_create_mesh_array); } void PrimitiveMesh::set_material(const Ref<Material> &p_material) { diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 3fc5fd4a16..eef5eb3f7d 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -64,8 +64,9 @@ protected: static void _bind_methods(); - virtual void _create_mesh_array(Array &p_arr) const = 0; + virtual void _create_mesh_array(Array &p_arr) const {} void _request_update(); + GDVIRTUAL0RC(Array, _create_mesh_array) public: virtual int get_surface_count() const override; diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index 27659f724e..5e88c9974c 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -58,6 +58,7 @@ bool RectangleShape2D::_get(const StringName &p_name, Variant &r_property) const #endif // DISABLE_DEPRECATED void RectangleShape2D::set_size(const Vector2 &p_size) { + ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0, "RectangleShape2D size cannot be negative."); size = p_size; _update_shape(); } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index c03faa2c2d..fd6f018651 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -153,7 +153,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R RES res = ResourceLoader::load_threaded_get(path); if (res.is_null()) { if (ResourceLoader::get_abort_on_missing_resources()) { - error = ERR_FILE_CORRUPT; + error = ERR_FILE_MISSING_DEPENDENCIES; error_text = "[ext_resource] referenced nonexistent resource at: " + path; _printerr(); return error; @@ -165,7 +165,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R r_res = res; } } else { - error = ERR_FILE_CORRUPT; + error = ERR_FILE_MISSING_DEPENDENCIES; error_text = "[ext_resource] referenced non-loaded resource at: " + path; _printerr(); return error; @@ -265,7 +265,9 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &parser); if (error) { - if (error != ERR_FILE_EOF) { + if (error == ERR_FILE_MISSING_DEPENDENCIES) { + // Resource loading error, just skip it. + } else if (error != ERR_FILE_EOF) { _printerr(); return Ref<PackedScene>(); } else { @@ -906,10 +908,9 @@ Error ResourceLoaderText::rename_dependencies(FileAccess *p_f, const String &p_p return ERR_CANT_CREATE; } - DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); da->remove(p_path); da->rename(p_path + ".depren", p_path); - memdelete(da); return OK; } diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp index ee789362c9..8282992401 100644 --- a/scene/resources/sphere_shape_3d.cpp +++ b/scene/resources/sphere_shape_3d.cpp @@ -63,6 +63,7 @@ void SphereShape3D::_update_shape() { } void SphereShape3D::set_radius(float p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0, "SphereShape3D radius cannot be negative."); radius = p_radius; _update_shape(); notify_change_to_owners(); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 5afd424e03..fe52761482 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -34,10 +34,28 @@ #include <limits.h> +float StyleBox::get_style_margin(Side p_side) const { + float ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_style_margin, p_side, ret)) { + return ret; + } + return 0; +} bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const { + bool ret; + if (GDVIRTUAL_CALL(_test_mask, p_point, p_rect, ret)) { + return ret; + } + return true; } +void StyleBox::draw(RID p_canvas_item, const Rect2 &p_rect) const { + if (GDVIRTUAL_REQUIRED_CALL(_draw, p_canvas_item, p_rect)) { + return; + } +} + void StyleBox::set_default_margin(Side p_side, float p_value) { ERR_FAIL_INDEX((int)p_side, 4); @@ -74,10 +92,19 @@ Point2 StyleBox::get_offset() const { } Size2 StyleBox::get_center_size() const { + Size2 ret; + if (GDVIRTUAL_CALL(_get_center_size, ret)) { + return ret; + } + return Size2(); } Rect2 StyleBox::get_draw_rect(const Rect2 &p_rect) const { + Rect2 ret; + if (GDVIRTUAL_CALL(_get_draw_rect, p_rect, ret)) { + return ret; + } return p_rect; } @@ -100,6 +127,12 @@ void StyleBox::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_BOTTOM); + + GDVIRTUAL_BIND(_get_style_margin, "side") + GDVIRTUAL_BIND(_test_mask, "point", "rect") + GDVIRTUAL_BIND(_get_center_size) + GDVIRTUAL_BIND(_get_draw_rect, "rect") + GDVIRTUAL_BIND(_draw, "to_canvas_item", "rect") } StyleBox::StyleBox() { diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 4c41f42293..68ad41b69c 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -44,9 +44,15 @@ class StyleBox : public Resource { float margin[4]; protected: - virtual float get_style_margin(Side p_side) const = 0; + virtual float get_style_margin(Side p_side) const; static void _bind_methods(); + GDVIRTUAL1RC(float, _get_style_margin, Side) + GDVIRTUAL2RC(bool, _test_mask, Point2, Rect2) + GDVIRTUAL0RC(Size2, _get_center_size) + GDVIRTUAL1RC(Rect2, _get_draw_rect, Rect2) + GDVIRTUAL2C(_draw, RID, Rect2) + public: virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const; @@ -56,7 +62,7 @@ public: virtual Size2 get_center_size() const; virtual Rect2 get_draw_rect(const Rect2 &p_rect) const; - virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const = 0; + virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const; CanvasItem *get_current_item_drawn() const; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 52151ae846..8ff1fde2cf 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -150,12 +150,15 @@ uint32_t SurfaceTool::TriangleHasher::hash(const int *p_triangle) { int t1 = p_triangle[1]; int t2 = p_triangle[2]; - if (t0 > t1) + if (t0 > t1) { SWAP(t0, t1); - if (t1 > t2) + } + if (t1 > t2) { SWAP(t1, t2); - if (t0 > t1) + } + if (t0 > t1) { SWAP(t0, t1); + } return (t0 * 73856093) ^ (t1 * 19349663) ^ (t2 * 83492791); } @@ -165,23 +168,29 @@ bool SurfaceTool::TriangleHasher::compare(const int *p_lhs, const int *p_rhs) { int r1 = p_rhs[1]; int r2 = p_rhs[2]; - if (r0 > r1) + if (r0 > r1) { SWAP(r0, r1); - if (r1 > r2) + } + if (r1 > r2) { SWAP(r1, r2); - if (r0 > r1) + } + if (r0 > r1) { SWAP(r0, r1); + } int l0 = p_lhs[0]; int l1 = p_lhs[1]; int l2 = p_lhs[2]; - if (l0 > l1) + if (l0 > l1) { SWAP(l0, l1); - if (l1 > l2) + } + if (l1 > l2) { SWAP(l1, l2); - if (l0 > l1) + } + if (l0 > l1) { SWAP(l0, l1); + } return l0 == r0 && l1 == r1 && l2 == r2; } diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 0ee0e4b33e..1930fa2682 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -38,23 +38,61 @@ #include "scene/resources/bit_map.h" #include "servers/camera/camera_feed.h" +int Texture2D::get_width() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_width, ret)) { + return ret; + } + return 0; +} + +int Texture2D::get_height() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_height, ret)) { + return ret; + } + return 0; +} + Size2 Texture2D::get_size() const { return Size2(get_width(), get_height()); } bool Texture2D::is_pixel_opaque(int p_x, int p_y) const { + bool ret; + if (GDVIRTUAL_CALL(_is_pixel_opaque, p_x, p_y, ret)) { + return ret; + } + + return true; +} +bool Texture2D::has_alpha() const { + bool ret; + if (GDVIRTUAL_CALL(_has_alpha, ret)) { + return ret; + } + return true; } void Texture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { + if (GDVIRTUAL_CALL(_draw, p_canvas_item, p_pos, p_modulate, p_transpose)) { + return; + } RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose); } void Texture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { + if (GDVIRTUAL_CALL(_draw_rect, p_canvas_item, p_rect, p_tile, p_modulate, p_transpose)) { + return; + } RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose); } void Texture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { + if (GDVIRTUAL_CALL(_draw_rect_region, p_canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_clip_uv)) { + return; + } RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose, p_clip_uv); } @@ -75,6 +113,15 @@ void Texture2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_image"), &Texture2D::get_image); ADD_GROUP("", ""); + + GDVIRTUAL_BIND(_get_width); + GDVIRTUAL_BIND(_get_height); + GDVIRTUAL_BIND(_is_pixel_opaque, "x", "y"); + GDVIRTUAL_BIND(_has_alpha); + + GDVIRTUAL_BIND(_draw, "to_canvas_item", "pos", "modulate", "transpose") + GDVIRTUAL_BIND(_draw_rect, "to_canvas_item", "rect", "tile", "modulate", "transpose") + GDVIRTUAL_BIND(_draw_rect_region, "tp_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"); } Texture2D::Texture2D() { @@ -293,7 +340,7 @@ ImageTexture::~ImageTexture() { ////////////////////////////////////////// -Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit) { +Ref<Image> CompressedTexture2D::load_image_from_file(FileAccess *f, int p_size_limit) { uint32_t data_format = f->get_32(); uint32_t w = f->get_16(); uint32_t h = f->get_16(); @@ -426,7 +473,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit return Ref<Image>(); } -void StreamTexture2D::set_path(const String &p_path, bool p_take_over) { +void CompressedTexture2D::set_path(const String &p_path, bool p_take_over) { if (texture.is_valid()) { RenderingServer::get_singleton()->texture_set_path(texture, p_path); } @@ -434,36 +481,36 @@ void StreamTexture2D::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } -void StreamTexture2D::_requested_3d(void *p_ud) { - StreamTexture2D *st = (StreamTexture2D *)p_ud; - Ref<StreamTexture2D> stex(st); +void CompressedTexture2D::_requested_3d(void *p_ud) { + CompressedTexture2D *ct = (CompressedTexture2D *)p_ud; + Ref<CompressedTexture2D> ctex(ct); ERR_FAIL_COND(!request_3d_callback); - request_3d_callback(stex); + request_3d_callback(ctex); } -void StreamTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) { - StreamTexture2D *st = (StreamTexture2D *)p_ud; - Ref<StreamTexture2D> stex(st); +void CompressedTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) { + CompressedTexture2D *ct = (CompressedTexture2D *)p_ud; + Ref<CompressedTexture2D> ctex(ct); ERR_FAIL_COND(!request_roughness_callback); - request_roughness_callback(stex, p_normal_path, p_roughness_channel); + request_roughness_callback(ctex, p_normal_path, p_roughness_channel); } -void StreamTexture2D::_requested_normal(void *p_ud) { - StreamTexture2D *st = (StreamTexture2D *)p_ud; - Ref<StreamTexture2D> stex(st); +void CompressedTexture2D::_requested_normal(void *p_ud) { + CompressedTexture2D *ct = (CompressedTexture2D *)p_ud; + Ref<CompressedTexture2D> ctex(ct); ERR_FAIL_COND(!request_normal_callback); - request_normal_callback(stex); + request_normal_callback(ctex); } -StreamTexture2D::TextureFormatRequestCallback StreamTexture2D::request_3d_callback = nullptr; -StreamTexture2D::TextureFormatRoughnessRequestCallback StreamTexture2D::request_roughness_callback = nullptr; -StreamTexture2D::TextureFormatRequestCallback StreamTexture2D::request_normal_callback = nullptr; +CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_3d_callback = nullptr; +CompressedTexture2D::TextureFormatRoughnessRequestCallback CompressedTexture2D::request_roughness_callback = nullptr; +CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_normal_callback = nullptr; -Image::Format StreamTexture2D::get_format() const { +Image::Format CompressedTexture2D::get_format() const { return format; } -Error StreamTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) { +Error CompressedTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) { alpha_cache.unref(); ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER); @@ -475,14 +522,14 @@ Error StreamTexture2D::_load_data(const String &p_path, int &r_width, int &r_hei f->get_buffer(header, 4); if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != '2') { memdelete(f); - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is corrupt (Bad header)."); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is corrupt (Bad header)."); } uint32_t version = f->get_32(); if (version > FORMAT_VERSION) { memdelete(f); - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new."); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new."); } r_width = f->get_32(); r_height = f->get_32(); @@ -523,7 +570,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &r_width, int &r_hei return OK; } -Error StreamTexture2D::load(const String &p_path) { +Error CompressedTexture2D::load(const String &p_path) { int lw, lh; Ref<Image> image; image.instantiate(); @@ -590,51 +637,51 @@ Error StreamTexture2D::load(const String &p_path) { return OK; } -String StreamTexture2D::get_load_path() const { +String CompressedTexture2D::get_load_path() const { return path_to_file; } -int StreamTexture2D::get_width() const { +int CompressedTexture2D::get_width() const { return w; } -int StreamTexture2D::get_height() const { +int CompressedTexture2D::get_height() const { return h; } -RID StreamTexture2D::get_rid() const { +RID CompressedTexture2D::get_rid() const { if (!texture.is_valid()) { texture = RS::get_singleton()->texture_2d_placeholder_create(); } return texture; } -void StreamTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { +void CompressedTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose); } -void StreamTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { +void CompressedTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) { return; } RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose); } -void StreamTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { +void CompressedTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const { if ((w | h) == 0) { return; } RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv); } -bool StreamTexture2D::has_alpha() const { +bool CompressedTexture2D::has_alpha() const { return false; } -Ref<Image> StreamTexture2D::get_image() const { +Ref<Image> CompressedTexture2D::get_image() const { if (texture.is_valid()) { return RS::get_singleton()->texture_2d_get(texture); } else { @@ -642,7 +689,7 @@ Ref<Image> StreamTexture2D::get_image() const { } } -bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const { +bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const { if (!alpha_cache.is_valid()) { Ref<Image> img = get_image(); if (img.is_valid()) { @@ -676,7 +723,7 @@ bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const { return true; } -void StreamTexture2D::reload_from_file() { +void CompressedTexture2D::reload_from_file() { String path = get_path(); if (!path.is_resource_file()) { return; @@ -691,26 +738,26 @@ void StreamTexture2D::reload_from_file() { load(path); } -void StreamTexture2D::_validate_property(PropertyInfo &property) const { +void CompressedTexture2D::_validate_property(PropertyInfo &property) const { } -void StreamTexture2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture2D::load); - ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture2D::get_load_path); +void CompressedTexture2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture2D::load); + ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture2D::get_load_path); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path"); } -StreamTexture2D::StreamTexture2D() {} +CompressedTexture2D::CompressedTexture2D() {} -StreamTexture2D::~StreamTexture2D() { +CompressedTexture2D::~CompressedTexture2D() { if (texture.is_valid()) { RS::get_singleton()->free(texture); } } -RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - Ref<StreamTexture2D> st; +RES ResourceFormatLoaderCompressedTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + Ref<CompressedTexture2D> st; st.instantiate(); Error err = st->load(p_path); if (r_error) { @@ -723,24 +770,24 @@ RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String return st; } -void ResourceFormatLoaderStreamTexture2D::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("stex"); +void ResourceFormatLoaderCompressedTexture2D::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("ctex"); } -bool ResourceFormatLoaderStreamTexture2D::handles_type(const String &p_type) const { - return p_type == "StreamTexture2D"; +bool ResourceFormatLoaderCompressedTexture2D::handles_type(const String &p_type) const { + return p_type == "CompressedTexture2D"; } -String ResourceFormatLoaderStreamTexture2D::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "stex") { - return "StreamTexture2D"; +String ResourceFormatLoaderCompressedTexture2D::get_resource_type(const String &p_path) const { + if (p_path.get_extension().to_lower() == "ctex") { + return "CompressedTexture2D"; } return ""; } //////////////////////////////////// -TypedArray<Image> Texture3D::_get_data() const { +TypedArray<Image> Texture3D::_get_datai() const { Vector<Ref<Image>> data = get_data(); TypedArray<Image> ret; @@ -751,13 +798,73 @@ TypedArray<Image> Texture3D::_get_data() const { return ret; } +Image::Format Texture3D::get_format() const { + Image::Format ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_format, ret)) { + return ret; + } + return Image::FORMAT_MAX; +} + +int Texture3D::get_width() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_width, ret)) { + return ret; + } + return 0; +} + +int Texture3D::get_height() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_height, ret)) { + return ret; + } + return 0; +} + +int Texture3D::get_depth() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_depth, ret)) { + return ret; + } + + return 0; +} + +bool Texture3D::has_mipmaps() const { + bool ret; + if (GDVIRTUAL_REQUIRED_CALL(_has_mipmaps, ret)) { + return ret; + } + return 0; +} + +Vector<Ref<Image>> Texture3D::get_data() const { + TypedArray<Image> ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_data, ret)) { + Vector<Ref<Image>> data; + data.resize(ret.size()); + for (int i = 0; i < data.size(); i++) { + data.write[i] = ret[i]; + } + return data; + } + return Vector<Ref<Image>>(); +} void Texture3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_format"), &Texture3D::get_format); ClassDB::bind_method(D_METHOD("get_width"), &Texture3D::get_width); ClassDB::bind_method(D_METHOD("get_height"), &Texture3D::get_height); ClassDB::bind_method(D_METHOD("get_depth"), &Texture3D::get_depth); ClassDB::bind_method(D_METHOD("has_mipmaps"), &Texture3D::has_mipmaps); - ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_data); + ClassDB::bind_method(D_METHOD("get_data"), &Texture3D::_get_datai); + + GDVIRTUAL_BIND(_get_format); + GDVIRTUAL_BIND(_get_width); + GDVIRTUAL_BIND(_get_height); + GDVIRTUAL_BIND(_get_depth); + GDVIRTUAL_BIND(_has_mipmaps); + GDVIRTUAL_BIND(_get_data); } ////////////////////////////////////////// @@ -846,7 +953,7 @@ ImageTexture3D::~ImageTexture3D() { //////////////////////////////////////////// -void StreamTexture3D::set_path(const String &p_path, bool p_take_over) { +void CompressedTexture3D::set_path(const String &p_path, bool p_take_over) { if (texture.is_valid()) { RenderingServer::get_singleton()->texture_set_path(texture, p_path); } @@ -854,11 +961,11 @@ void StreamTexture3D::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } -Image::Format StreamTexture3D::get_format() const { +Image::Format CompressedTexture3D::get_format() const { return format; } -Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) { +Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path)); @@ -866,11 +973,11 @@ Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_da f->get_buffer(header, 4); ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L', ERR_FILE_UNRECOGNIZED); - //stored as stream textures (used for lossless and lossy compression) + //stored as compressed textures (used for lossless and lossy compression) uint32_t version = f->get_32(); if (version > FORMAT_VERSION) { - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new."); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new."); } r_depth = f->get_32(); //depth @@ -887,7 +994,7 @@ Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_da r_data.clear(); for (int i = 0; i < (r_depth + mipmaps); i++) { - Ref<Image> image = StreamTexture2D::load_image_from_file(f, 0); + Ref<Image> image = CompressedTexture2D::load_image_from_file(f, 0); ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN); if (i == 0) { r_format = image->get_format(); @@ -900,7 +1007,7 @@ Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_da return OK; } -Error StreamTexture3D::load(const String &p_path) { +Error CompressedTexture3D::load(const String &p_path) { Vector<Ref<Image>> data; int tw, th, td; @@ -937,34 +1044,34 @@ Error StreamTexture3D::load(const String &p_path) { return OK; } -String StreamTexture3D::get_load_path() const { +String CompressedTexture3D::get_load_path() const { return path_to_file; } -int StreamTexture3D::get_width() const { +int CompressedTexture3D::get_width() const { return w; } -int StreamTexture3D::get_height() const { +int CompressedTexture3D::get_height() const { return h; } -int StreamTexture3D::get_depth() const { +int CompressedTexture3D::get_depth() const { return d; } -bool StreamTexture3D::has_mipmaps() const { +bool CompressedTexture3D::has_mipmaps() const { return mipmaps; } -RID StreamTexture3D::get_rid() const { +RID CompressedTexture3D::get_rid() const { if (!texture.is_valid()) { texture = RS::get_singleton()->texture_3d_placeholder_create(); } return texture; } -Vector<Ref<Image>> StreamTexture3D::get_data() const { +Vector<Ref<Image>> CompressedTexture3D::get_data() const { if (texture.is_valid()) { return RS::get_singleton()->texture_3d_get(texture); } else { @@ -972,7 +1079,7 @@ Vector<Ref<Image>> StreamTexture3D::get_data() const { } } -void StreamTexture3D::reload_from_file() { +void CompressedTexture3D::reload_from_file() { String path = get_path(); if (!path.is_resource_file()) { return; @@ -987,19 +1094,19 @@ void StreamTexture3D::reload_from_file() { load(path); } -void StreamTexture3D::_validate_property(PropertyInfo &property) const { +void CompressedTexture3D::_validate_property(PropertyInfo &property) const { } -void StreamTexture3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture3D::load); - ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture3D::get_load_path); +void CompressedTexture3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture3D::load); + ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture3D::get_load_path); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path"); } -StreamTexture3D::StreamTexture3D() {} +CompressedTexture3D::CompressedTexture3D() {} -StreamTexture3D::~StreamTexture3D() { +CompressedTexture3D::~CompressedTexture3D() { if (texture.is_valid()) { RS::get_singleton()->free(texture); } @@ -1007,8 +1114,8 @@ StreamTexture3D::~StreamTexture3D() { ///////////////////////////// -RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - Ref<StreamTexture3D> st; +RES ResourceFormatLoaderCompressedTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + Ref<CompressedTexture3D> st; st.instantiate(); Error err = st->load(p_path); if (r_error) { @@ -1021,17 +1128,17 @@ RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String return st; } -void ResourceFormatLoaderStreamTexture3D::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("stex3d"); +void ResourceFormatLoaderCompressedTexture3D::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("ctex3d"); } -bool ResourceFormatLoaderStreamTexture3D::handles_type(const String &p_type) const { - return p_type == "StreamTexture3D"; +bool ResourceFormatLoaderCompressedTexture3D::handles_type(const String &p_type) const { + return p_type == "CompressedTexture3D"; } -String ResourceFormatLoaderStreamTexture3D::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "stex3d") { - return "StreamTexture3D"; +String ResourceFormatLoaderCompressedTexture3D::get_resource_type(const String &p_path) const { + if (p_path.get_extension().to_lower() == "ctex3d") { + return "CompressedTexture3D"; } return ""; } @@ -2446,6 +2553,63 @@ AnimatedTexture::~AnimatedTexture() { /////////////////////////////// +Image::Format TextureLayered::get_format() const { + Image::Format ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_format, ret)) { + return ret; + } + return Image::FORMAT_MAX; +} + +TextureLayered::LayeredType TextureLayered::get_layered_type() const { + uint32_t ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_layered_type, ret)) { + return (LayeredType)ret; + } + return LAYERED_TYPE_2D_ARRAY; +} + +int TextureLayered::get_width() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_width, ret)) { + return ret; + } + return 0; +} + +int TextureLayered::get_height() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_height, ret)) { + return ret; + } + return 0; +} + +int TextureLayered::get_layers() const { + int ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_layers, ret)) { + return ret; + } + + return 0; +} + +bool TextureLayered::has_mipmaps() const { + bool ret; + if (GDVIRTUAL_REQUIRED_CALL(_has_mipmaps, ret)) { + return ret; + } + return false; +} + +Ref<Image> TextureLayered::get_layer_data(int p_layer) const { + Ref<Image> ret; + if (GDVIRTUAL_REQUIRED_CALL(_get_layer_data, p_layer, ret)) { + return ret; + } + return Ref<Image>(); +} + void TextureLayered::_bind_methods() { ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format); ClassDB::bind_method(D_METHOD("get_layered_type"), &TextureLayered::get_layered_type); @@ -2458,6 +2622,14 @@ void TextureLayered::_bind_methods() { BIND_ENUM_CONSTANT(LAYERED_TYPE_2D_ARRAY); BIND_ENUM_CONSTANT(LAYERED_TYPE_CUBEMAP); BIND_ENUM_CONSTANT(LAYERED_TYPE_CUBEMAP_ARRAY); + + GDVIRTUAL_BIND(_get_format); + GDVIRTUAL_BIND(_get_layered_type); + GDVIRTUAL_BIND(_get_width); + GDVIRTUAL_BIND(_get_height); + GDVIRTUAL_BIND(_get_layers); + GDVIRTUAL_BIND(_has_mipmaps); + GDVIRTUAL_BIND(_get_layer_data, "layer_index"); } /////////////////////////////// @@ -2599,7 +2771,7 @@ ImageTextureLayered::~ImageTextureLayered() { /////////////////////////////////////////// -void StreamTextureLayered::set_path(const String &p_path, bool p_take_over) { +void CompressedTextureLayered::set_path(const String &p_path, bool p_take_over) { if (texture.is_valid()) { RenderingServer::get_singleton()->texture_set_path(texture, p_path); } @@ -2607,11 +2779,11 @@ void StreamTextureLayered::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } -Image::Format StreamTextureLayered::get_format() const { +Image::Format CompressedTextureLayered::get_format() const { return format; } -Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) { +Error CompressedTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) { ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER); FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); @@ -2620,13 +2792,13 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> uint8_t header[4]; f->get_buffer(header, 4); if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L') { - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture layered file is corrupt (Bad header)."); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture layered file is corrupt (Bad header)."); } uint32_t version = f->get_32(); if (version > FORMAT_VERSION) { - ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new."); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new."); } uint32_t layer_count = f->get_32(); //layer count @@ -2647,7 +2819,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> images.resize(layer_count); for (uint32_t i = 0; i < layer_count; i++) { - Ref<Image> image = StreamTexture2D::load_image_from_file(f, p_size_limit); + Ref<Image> image = CompressedTexture2D::load_image_from_file(f, p_size_limit); ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN); images.write[i] = image; } @@ -2655,7 +2827,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> return OK; } -Error StreamTextureLayered::load(const String &p_path) { +Error CompressedTextureLayered::load(const String &p_path) { Vector<Ref<Image>> images; int mipmap_limit; @@ -2690,38 +2862,38 @@ Error StreamTextureLayered::load(const String &p_path) { return OK; } -String StreamTextureLayered::get_load_path() const { +String CompressedTextureLayered::get_load_path() const { return path_to_file; } -int StreamTextureLayered::get_width() const { +int CompressedTextureLayered::get_width() const { return w; } -int StreamTextureLayered::get_height() const { +int CompressedTextureLayered::get_height() const { return h; } -int StreamTextureLayered::get_layers() const { +int CompressedTextureLayered::get_layers() const { return layers; } -bool StreamTextureLayered::has_mipmaps() const { +bool CompressedTextureLayered::has_mipmaps() const { return mipmaps; } -TextureLayered::LayeredType StreamTextureLayered::get_layered_type() const { +TextureLayered::LayeredType CompressedTextureLayered::get_layered_type() const { return layered_type; } -RID StreamTextureLayered::get_rid() const { +RID CompressedTextureLayered::get_rid() const { if (!texture.is_valid()) { texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type)); } return texture; } -Ref<Image> StreamTextureLayered::get_layer_data(int p_layer) const { +Ref<Image> CompressedTextureLayered::get_layer_data(int p_layer) const { if (texture.is_valid()) { return RS::get_singleton()->texture_2d_layer_get(texture, p_layer); } else { @@ -2729,7 +2901,7 @@ Ref<Image> StreamTextureLayered::get_layer_data(int p_layer) const { } } -void StreamTextureLayered::reload_from_file() { +void CompressedTextureLayered::reload_from_file() { String path = get_path(); if (!path.is_resource_file()) { return; @@ -2744,21 +2916,21 @@ void StreamTextureLayered::reload_from_file() { load(path); } -void StreamTextureLayered::_validate_property(PropertyInfo &property) const { +void CompressedTextureLayered::_validate_property(PropertyInfo &property) const { } -void StreamTextureLayered::_bind_methods() { - ClassDB::bind_method(D_METHOD("load", "path"), &StreamTextureLayered::load); - ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTextureLayered::get_load_path); +void CompressedTextureLayered::_bind_methods() { + ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTextureLayered::load); + ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTextureLayered::get_load_path); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path"); } -StreamTextureLayered::StreamTextureLayered(LayeredType p_type) { +CompressedTextureLayered::CompressedTextureLayered(LayeredType p_type) { layered_type = p_type; } -StreamTextureLayered::~StreamTextureLayered() { +CompressedTextureLayered::~CompressedTextureLayered() { if (texture.is_valid()) { RS::get_singleton()->free(texture); } @@ -2766,27 +2938,27 @@ StreamTextureLayered::~StreamTextureLayered() { ///////////////////////////////////////////////// -RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - Ref<StreamTextureLayered> st; - if (p_path.get_extension().to_lower() == "stexarray") { - Ref<StreamTexture2DArray> s; - s.instantiate(); - st = s; - } else if (p_path.get_extension().to_lower() == "scube") { - Ref<StreamCubemap> s; - s.instantiate(); - st = s; - } else if (p_path.get_extension().to_lower() == "scubearray") { - Ref<StreamCubemapArray> s; - s.instantiate(); - st = s; +RES ResourceFormatLoaderCompressedTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + Ref<CompressedTextureLayered> ct; + if (p_path.get_extension().to_lower() == "ctexarray") { + Ref<CompressedTexture2DArray> c; + c.instantiate(); + ct = c; + } else if (p_path.get_extension().to_lower() == "ccube") { + Ref<CompressedCubemap> c; + c.instantiate(); + ct = c; + } else if (p_path.get_extension().to_lower() == "ccubearray") { + Ref<CompressedCubemapArray> c; + c.instantiate(); + ct = c; } else { if (r_error) { *r_error = ERR_FILE_UNRECOGNIZED; } return RES(); } - Error err = st->load(p_path); + Error err = ct->load(p_path); if (r_error) { *r_error = err; } @@ -2794,28 +2966,28 @@ RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const S return RES(); } - return st; + return ct; } -void ResourceFormatLoaderStreamTextureLayered::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("stexarray"); - p_extensions->push_back("scube"); - p_extensions->push_back("scubearray"); +void ResourceFormatLoaderCompressedTextureLayered::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("ctexarray"); + p_extensions->push_back("ccube"); + p_extensions->push_back("ccubearray"); } -bool ResourceFormatLoaderStreamTextureLayered::handles_type(const String &p_type) const { - return p_type == "StreamTexture2DArray" || p_type == "StreamCubemap" || p_type == "StreamCubemapArray"; +bool ResourceFormatLoaderCompressedTextureLayered::handles_type(const String &p_type) const { + return p_type == "CompressedTexture2DArray" || p_type == "CompressedCubemap" || p_type == "CompressedCubemapArray"; } -String ResourceFormatLoaderStreamTextureLayered::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "stexarray") { - return "StreamTexture2DArray"; +String ResourceFormatLoaderCompressedTextureLayered::get_resource_type(const String &p_path) const { + if (p_path.get_extension().to_lower() == "ctexarray") { + return "CompressedTexture2DArray"; } - if (p_path.get_extension().to_lower() == "scube") { - return "StreamCubemap"; + if (p_path.get_extension().to_lower() == "ccube") { + return "CompressedCubemap"; } - if (p_path.get_extension().to_lower() == "scubearray") { - return "StreamCubemapArray"; + if (p_path.get_extension().to_lower() == "ccubearray") { + return "CompressedCubemapArray"; } return ""; } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 8075497c42..1e07b83547 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -57,14 +57,23 @@ class Texture2D : public Texture { protected: static void _bind_methods(); + GDVIRTUAL0RC(int, _get_width) + GDVIRTUAL0RC(int, _get_height) + GDVIRTUAL2RC(bool, _is_pixel_opaque, int, int) + GDVIRTUAL0RC(bool, _has_alpha) + + GDVIRTUAL4C(_draw, RID, Point2, Color, bool) + GDVIRTUAL5C(_draw_rect, RID, Rect2, bool, Color, bool) + GDVIRTUAL6C(_draw_rect_region, RID, Rect2, Rect2, Color, bool, bool) + public: - virtual int get_width() const = 0; - virtual int get_height() const = 0; + virtual int get_width() const; + virtual int get_height() const; virtual Size2 get_size() const; virtual bool is_pixel_opaque(int p_x, int p_y) const; - virtual bool has_alpha() const = 0; + virtual bool has_alpha() const; virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const; virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) const; @@ -128,8 +137,8 @@ public: ~ImageTexture(); }; -class StreamTexture2D : public Texture2D { - GDCLASS(StreamTexture2D, Texture2D); +class CompressedTexture2D : public Texture2D { + GDCLASS(CompressedTexture2D, Texture2D); public: enum DataFormat { @@ -174,8 +183,8 @@ protected: public: static Ref<Image> load_image_from_file(FileAccess *p_file, int p_size_limit); - typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture2D> &); - typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<StreamTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel); + typedef void (*TextureFormatRequestCallback)(const Ref<CompressedTexture2D> &); + typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<CompressedTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel); static TextureFormatRequestCallback request_3d_callback; static TextureFormatRoughnessRequestCallback request_roughness_callback; @@ -200,11 +209,11 @@ public: virtual Ref<Image> get_image() const override; - StreamTexture2D(); - ~StreamTexture2D(); + CompressedTexture2D(); + ~CompressedTexture2D(); }; -class ResourceFormatLoaderStreamTexture2D : public ResourceFormatLoader { +class ResourceFormatLoaderCompressedTexture2D : public ResourceFormatLoader { public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -300,6 +309,13 @@ class TextureLayered : public Texture { protected: static void _bind_methods(); + GDVIRTUAL0RC(Image::Format, _get_format) + GDVIRTUAL0RC(uint32_t, _get_layered_type) + GDVIRTUAL0RC(int, _get_width) + GDVIRTUAL0RC(int, _get_height) + GDVIRTUAL0RC(int, _get_layers) + GDVIRTUAL0RC(bool, _has_mipmaps) + GDVIRTUAL1RC(Ref<Image>, _get_layer_data, int) public: enum LayeredType { LAYERED_TYPE_2D_ARRAY, @@ -307,13 +323,15 @@ public: LAYERED_TYPE_CUBEMAP_ARRAY }; - virtual Image::Format get_format() const = 0; - virtual LayeredType get_layered_type() const = 0; - virtual int get_width() const = 0; - virtual int get_height() const = 0; - virtual int get_layers() const = 0; - virtual bool has_mipmaps() const = 0; - virtual Ref<Image> get_layer_data(int p_layer) const = 0; + virtual Image::Format get_format() const; + virtual LayeredType get_layered_type() const; + virtual int get_width() const; + virtual int get_height() const; + virtual int get_layers() const; + virtual bool has_mipmaps() const; + virtual Ref<Image> get_layer_data(int p_layer) const; + + TextureLayered() {} }; VARIANT_ENUM_CAST(TextureLayered::LayeredType) @@ -380,8 +398,8 @@ public: ImageTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {} }; -class StreamTextureLayered : public TextureLayered { - GDCLASS(StreamTextureLayered, TextureLayered); +class CompressedTextureLayered : public TextureLayered { + GDCLASS(CompressedTextureLayered, TextureLayered); public: enum DataFormat { @@ -433,34 +451,34 @@ public: virtual Ref<Image> get_layer_data(int p_layer) const override; - StreamTextureLayered(LayeredType p_layered_type); - ~StreamTextureLayered(); + CompressedTextureLayered(LayeredType p_layered_type); + ~CompressedTextureLayered(); }; -class StreamTexture2DArray : public StreamTextureLayered { - GDCLASS(StreamTexture2DArray, StreamTextureLayered) +class CompressedTexture2DArray : public CompressedTextureLayered { + GDCLASS(CompressedTexture2DArray, CompressedTextureLayered) public: - StreamTexture2DArray() : - StreamTextureLayered(LAYERED_TYPE_2D_ARRAY) {} + CompressedTexture2DArray() : + CompressedTextureLayered(LAYERED_TYPE_2D_ARRAY) {} }; -class StreamCubemap : public StreamTextureLayered { - GDCLASS(StreamCubemap, StreamTextureLayered); +class CompressedCubemap : public CompressedTextureLayered { + GDCLASS(CompressedCubemap, CompressedTextureLayered); public: - StreamCubemap() : - StreamTextureLayered(LAYERED_TYPE_CUBEMAP) {} + CompressedCubemap() : + CompressedTextureLayered(LAYERED_TYPE_CUBEMAP) {} }; -class StreamCubemapArray : public StreamTextureLayered { - GDCLASS(StreamCubemapArray, StreamTextureLayered); +class CompressedCubemapArray : public CompressedTextureLayered { + GDCLASS(CompressedCubemapArray, CompressedTextureLayered); public: - StreamCubemapArray() : - StreamTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {} + CompressedCubemapArray() : + CompressedTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {} }; -class ResourceFormatLoaderStreamTextureLayered : public ResourceFormatLoader { +class ResourceFormatLoaderCompressedTextureLayered : public ResourceFormatLoader { public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -474,15 +492,21 @@ class Texture3D : public Texture { protected: static void _bind_methods(); - TypedArray<Image> _get_data() const; - -public: - virtual Image::Format get_format() const = 0; - virtual int get_width() const = 0; - virtual int get_height() const = 0; - virtual int get_depth() const = 0; - virtual bool has_mipmaps() const = 0; - virtual Vector<Ref<Image>> get_data() const = 0; + TypedArray<Image> _get_datai() const; + + GDVIRTUAL0RC(Image::Format, _get_format) + GDVIRTUAL0RC(int, _get_width) + GDVIRTUAL0RC(int, _get_height) + GDVIRTUAL0RC(int, _get_depth) + GDVIRTUAL0RC(bool, _has_mipmaps) + GDVIRTUAL0RC(TypedArray<Image>, _get_data) +public: + virtual Image::Format get_format() const; + virtual int get_width() const; + virtual int get_height() const; + virtual int get_depth() const; + virtual bool has_mipmaps() const; + virtual Vector<Ref<Image>> get_data() const; }; class ImageTexture3D : public Texture3D { @@ -520,8 +544,8 @@ public: ~ImageTexture3D(); }; -class StreamTexture3D : public Texture3D { - GDCLASS(StreamTexture3D, Texture3D); +class CompressedTexture3D : public Texture3D { + GDCLASS(CompressedTexture3D, Texture3D); public: enum DataFormat { @@ -571,11 +595,11 @@ public: virtual Vector<Ref<Image>> get_data() const override; - StreamTexture3D(); - ~StreamTexture3D(); + CompressedTexture3D(); + ~CompressedTexture3D(); }; -class ResourceFormatLoaderStreamTexture3D : public ResourceFormatLoader { +class ResourceFormatLoaderCompressedTexture3D : public ResourceFormatLoader { public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions(List<String> *p_extensions) const; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 1e84947b87..1174117028 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -4432,6 +4432,10 @@ void TileSetAtlasSource::_update_padded_texture() { Ref<Image> src = texture->get_image(); + if (!src.is_valid()) { + return; + } + Ref<Image> image; image.instantiate(); image->create(size.x, size.y, false, src->get_format()); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index dae61c8609..d3e61dbc84 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -455,32 +455,69 @@ String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader:: for (int i = 0; i < get_output_port_count(); i++) { output_vars.push_back(p_output_vars[i]); } - String code = " {\n"; + String _code; GDVIRTUAL_CALL(_get_code, input_vars, output_vars, p_mode, p_type, _code); - bool nend = _code.ends_with("\n"); - _code = _code.insert(0, " "); - _code = _code.replace("\n", "\n "); - code += _code; - if (!nend) { - code += "\n }"; - } else { - code.remove_at(code.size() - 1); - code += "}"; + if (_is_valid_code(_code)) { + String code = " {\n"; + bool nend = _code.ends_with("\n"); + _code = _code.insert(0, " "); + _code = _code.replace("\n", "\n "); + code += _code; + if (!nend) { + code += "\n }"; + } else { + code.remove_at(code.size() - 1); + code += "}"; + } + code += "\n"; + return code; } - code += "\n"; - return code; + return String(); } String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, int p_id) const { - String ret; - if (GDVIRTUAL_CALL(_get_global_code, p_mode, ret)) { - String code = "// " + get_caption() + "\n"; - code += ret; - code += "\n"; - return code; + String _code; + if (GDVIRTUAL_CALL(_get_global_code, p_mode, _code)) { + if (_is_valid_code(_code)) { + String code = "// " + get_caption() + "\n"; + code += _code; + code += "\n"; + return code; + } } - return ""; + return String(); +} + +String VisualShaderNodeCustom::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String _code; + if (GDVIRTUAL_CALL(_get_func_code, p_mode, p_type, _code)) { + if (_is_valid_code(_code)) { + bool nend = _code.ends_with("\n"); + String code = "// " + get_caption() + "\n"; + code += " {\n"; + _code = _code.insert(0, " "); + _code = _code.replace("\n", "\n "); + code += _code; + if (!nend) { + code += "\n }"; + } else { + code.remove_at(code.size() - 1); + code += "}"; + } + code += "\n"; + return code; + } + } + return String(); +} + +bool VisualShaderNodeCustom::is_available(Shader::Mode p_mode, VisualShader::Type p_type) const { + bool ret; + if (GDVIRTUAL_CALL(_is_available, p_mode, p_type, ret)) { + return ret; + } + return true; } void VisualShaderNodeCustom::set_input_port_default_value(int p_port, const Variant &p_value, const Variant &p_prev_value) { @@ -511,6 +548,13 @@ void VisualShaderNodeCustom::_set_input_port_default_value(int p_port, const Var VisualShaderNode::set_input_port_default_value(p_port, p_value); } +bool VisualShaderNodeCustom::_is_valid_code(const String &p_code) const { + if (p_code.is_empty() || p_code == "null") { + return false; + } + return true; +} + bool VisualShaderNodeCustom::_is_initialized() { return is_initialized; } @@ -531,8 +575,10 @@ void VisualShaderNodeCustom::_bind_methods() { GDVIRTUAL_BIND(_get_output_port_type, "port"); GDVIRTUAL_BIND(_get_output_port_name, "port"); GDVIRTUAL_BIND(_get_code, "input_vars", "output_vars", "mode", "type"); + GDVIRTUAL_BIND(_get_func_code, "mode", "type"); GDVIRTUAL_BIND(_get_global_code, "mode"); GDVIRTUAL_BIND(_is_highend); + GDVIRTUAL_BIND(_is_available, "mode", "type"); ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized); ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized); @@ -555,6 +601,72 @@ VisualShader::Type VisualShader::get_shader_type() const { return current_type; } +void VisualShader::add_varying(const String &p_name, VaryingMode p_mode, VaryingType p_type) { + ERR_FAIL_COND(!p_name.is_valid_identifier()); + ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX); + ERR_FAIL_INDEX((int)p_type, (int)VARYING_TYPE_MAX); + ERR_FAIL_COND(varyings.has(p_name)); + Varying var = Varying(p_name, p_mode, p_type); + varyings[p_name] = var; + varyings_list.push_back(var); + _queue_update(); +} + +void VisualShader::remove_varying(const String &p_name) { + ERR_FAIL_COND(!varyings.has(p_name)); + varyings.erase(p_name); + for (List<Varying>::Element *E = varyings_list.front(); E; E = E->next()) { + if (E->get().name == p_name) { + varyings_list.erase(E); + break; + } + } + _queue_update(); +} + +bool VisualShader::has_varying(const String &p_name) const { + return varyings.has(p_name); +} + +int VisualShader::get_varyings_count() const { + return varyings_list.size(); +} + +const VisualShader::Varying *VisualShader::get_varying_by_index(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, varyings_list.size(), nullptr); + return &varyings_list[p_idx]; +} + +void VisualShader::set_varying_mode(const String &p_name, VaryingMode p_mode) { + ERR_FAIL_INDEX((int)p_mode, (int)VARYING_MODE_MAX); + ERR_FAIL_COND(!varyings.has(p_name)); + if (varyings[p_name].mode == p_mode) { + return; + } + varyings[p_name].mode = p_mode; + _queue_update(); +} + +VisualShader::VaryingMode VisualShader::get_varying_mode(const String &p_name) { + ERR_FAIL_COND_V(!varyings.has(p_name), VARYING_MODE_MAX); + return varyings[p_name].mode; +} + +void VisualShader::set_varying_type(const String &p_name, VaryingType p_type) { + ERR_FAIL_INDEX((int)p_type, (int)VARYING_TYPE_MAX); + ERR_FAIL_COND(!varyings.has(p_name)); + if (varyings[p_name].type == p_type) { + return; + } + varyings[p_name].type = p_type; + _queue_update(); +} + +VisualShader::VaryingType VisualShader::get_varying_type(const String &p_name) { + ERR_FAIL_COND_V(!varyings.has(p_name), VARYING_TYPE_MAX); + return varyings[p_name].type; +} + void VisualShader::set_engine_version(const Dictionary &p_engine_version) { ERR_FAIL_COND(!p_engine_version.has("major")); ERR_FAIL_COND(!p_engine_version.has("minor")); @@ -1072,7 +1184,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port code += "\nvoid fragment() {\n"; Set<int> processed; - Error err = _write_node(p_type, global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes); + Error err = _write_node(p_type, &global_code, &global_code_per_node, &global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes); ERR_FAIL_COND_V(err != OK, String()); switch (node->get_output_port_type(p_port)) { @@ -1253,6 +1365,16 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) { } _queue_update(); return true; + } else if (name.begins_with("varyings/")) { + String var_name = name.get_slicec('/', 1); + Varying value = Varying(); + value.name = var_name; + if (value.from_string(p_value) && !varyings.has(var_name)) { + varyings[var_name] = value; + varyings_list.push_back(value); + } + _queue_update(); + return true; } else if (name.begins_with("nodes/")) { String typestr = name.get_slicec('/', 1); Type type = TYPE_VERTEX; @@ -1317,6 +1439,14 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { r_ret = 0; } return true; + } else if (name.begins_with("varyings/")) { + String var_name = name.get_slicec('/', 1); + if (varyings.has(var_name)) { + r_ret = varyings[var_name].to_string(); + } else { + r_ret = String(); + } + return true; } else if (name.begins_with("nodes/")) { String typestr = name.get_slicec('/', 1); Type type = TYPE_VERTEX; @@ -1411,6 +1541,10 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, "flags/" + E->get())); } + for (const KeyValue<String, Varying> &E : varyings) { + p_list->push_back(PropertyInfo(Variant::STRING, "varyings/" + E.key)); + } + for (int i = 0; i < TYPE_MAX; i++) { for (const KeyValue<int, Node> &E : graph[i].nodes) { String prop_name = "nodes/"; @@ -1435,7 +1569,7 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { } } -Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const { +Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBuilder *global_code_per_node, Map<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const { const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node; if (vsnode->is_disabled()) { @@ -1477,7 +1611,9 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui if (!skip_global) { Ref<VisualShaderNodeUniform> uniform = vsnode; if (!uniform.is_valid() || !uniform->is_global_code_generated()) { - global_code += vsnode->generate_global(get_mode(), type, node); + if (global_code) { + *global_code += vsnode->generate_global(get_mode(), type, node); + } } String class_name = vsnode->get_class_name(); @@ -1485,9 +1621,13 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui class_name = vsnode->get_script_instance()->get_script()->get_path(); } if (!r_classes.has(class_name)) { - global_code_per_node += vsnode->generate_global_per_node(get_mode(), node); + if (global_code_per_node) { + *global_code_per_node += vsnode->generate_global_per_node(get_mode(), node); + } for (int i = 0; i < TYPE_MAX; i++) { - global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node); + if (global_code_per_func) { + (*global_code_per_func)[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node); + } } r_classes.insert(class_name); } @@ -1940,6 +2080,7 @@ void VisualShader::_update_shader() const { Set<String> used_uniform_names; List<VisualShaderNodeUniform *> uniforms; Map<int, List<int>> emitters; + Map<int, List<int>> varying_setters; for (int i = 0, index = 0; i < TYPE_MAX; i++) { if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { @@ -1964,18 +2105,19 @@ void VisualShader::_update_shader() const { if (uniform.is_valid()) { uniforms.push_back(uniform.ptr()); } + Ref<VisualShaderNodeVaryingSetter> varying_setter = Object::cast_to<VisualShaderNodeVaryingSetter>(E->get().node.ptr()); + if (varying_setter.is_valid() && varying_setter->is_input_port_connected(0)) { + if (!varying_setters.has(i)) { + varying_setters.insert(i, List<int>()); + } + varying_setters[i].push_back(E->key()); + } Ref<VisualShaderNodeParticleEmit> emit_particle = Object::cast_to<VisualShaderNodeParticleEmit>(E->get().node.ptr()); if (emit_particle.is_valid()) { if (!emitters.has(i)) { emitters.insert(i, List<int>()); } - - for (const KeyValue<int, Node> &M : graph[i].nodes) { - if (M.value.node == emit_particle.ptr()) { - emitters[i].push_back(M.key); - break; - } - } + emitters[i].push_back(E->key()); } } } @@ -1990,6 +2132,36 @@ void VisualShader::_update_shader() const { } } + if (!varyings.is_empty()) { + global_code += "\n// Varyings\n"; + + for (const KeyValue<String, Varying> &E : varyings) { + global_code += "varying "; + switch (E.value.type) { + case VaryingType::VARYING_TYPE_FLOAT: + global_code += "float "; + break; + case VaryingType::VARYING_TYPE_VECTOR_2D: + global_code += "vec2 "; + break; + case VaryingType::VARYING_TYPE_VECTOR_3D: + global_code += "vec3 "; + break; + case VaryingType::VARYING_TYPE_COLOR: + global_code += "vec4 "; + break; + case VaryingType::VARYING_TYPE_TRANSFORM: + global_code += "mat4 "; + break; + default: + break; + } + global_code += E.key + ";\n"; + } + + global_code += "\n"; + } + Map<int, String> code_map; Set<int> empty_funcs; @@ -2003,12 +2175,54 @@ void VisualShader::_update_shader() const { VMap<ConnectionKey, const List<Connection>::Element *> output_connections; StringBuilder func_code; + Set<int> processed; bool is_empty_func = false; if (shader_mode != Shader::MODE_PARTICLES && shader_mode != Shader::MODE_SKY && shader_mode != Shader::MODE_FOG) { is_empty_func = true; } + String varying_code; + if (shader_mode == Shader::MODE_SPATIAL || shader_mode == Shader::MODE_CANVAS_ITEM) { + for (const KeyValue<String, Varying> &E : varyings) { + if ((E.value.mode == VARYING_MODE_VERTEX_TO_FRAG_LIGHT && i == TYPE_VERTEX) || (E.value.mode == VARYING_MODE_FRAG_TO_LIGHT && i == TYPE_FRAGMENT)) { + bool found = false; + for (int key : varying_setters[i]) { + Ref<VisualShaderNodeVaryingSetter> setter = Object::cast_to<VisualShaderNodeVaryingSetter>(const_cast<VisualShaderNode *>(graph[i].nodes[key].node.ptr())); + if (setter.is_valid() && E.value.name == setter->get_varying_name()) { + found = true; + break; + } + } + + if (!found) { + String code2; + switch (E.value.type) { + case VaryingType::VARYING_TYPE_FLOAT: + code2 += "0.0"; + break; + case VaryingType::VARYING_TYPE_VECTOR_2D: + code2 += "vec2(0.0)"; + break; + case VaryingType::VARYING_TYPE_VECTOR_3D: + code2 += "vec3(0.0)"; + break; + case VaryingType::VARYING_TYPE_COLOR: + code2 += "vec4(0.0)"; + break; + case VaryingType::VARYING_TYPE_TRANSFORM: + code2 += "mat4(1.0)"; + break; + default: + break; + } + varying_code += vformat(" %s = %s;\n", E.key, code2); + } + is_empty_func = false; + } + } + } + for (const List<Connection>::Element *E = graph[i].connections.front(); E; E = E->next()) { ConnectionKey from_key; from_key.node = E->get().from_node; @@ -2037,13 +2251,19 @@ void VisualShader::_update_shader() const { } insertion_pos.insert(i, code.get_string_length() + func_code.get_string_length()); - Set<int> processed; - Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes); + Error err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes); ERR_FAIL_COND(err != OK); + if (varying_setters.has(i)) { + for (int &E : varying_setters[i]) { + err = _write_node(Type(i), nullptr, nullptr, nullptr, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes); + ERR_FAIL_COND(err != OK); + } + } + if (emitters.has(i)) { for (int &E : emitters[i]) { - err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes); + err = _write_node(Type(i), &global_code, &global_code_per_node, &global_code_per_func, func_code, default_tex_params, input_connections, output_connections, E, processed, false, classes); ERR_FAIL_COND(err != OK); } } @@ -2051,6 +2271,7 @@ void VisualShader::_update_shader() const { if (shader_mode == Shader::MODE_PARTICLES) { code_map.insert(i, func_code); } else { + func_code += varying_code; func_code += "}\n"; code += func_code; } @@ -2276,6 +2497,10 @@ void VisualShader::_bind_methods() { ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &VisualShader::set_graph_offset); ClassDB::bind_method(D_METHOD("get_graph_offset"), &VisualShader::get_graph_offset); + ClassDB::bind_method(D_METHOD("add_varying", "name", "mode", "type"), &VisualShader::add_varying); + ClassDB::bind_method(D_METHOD("remove_varying", "name"), &VisualShader::remove_varying); + ClassDB::bind_method(D_METHOD("has_varying", "name"), &VisualShader::has_varying); + ClassDB::bind_method(D_METHOD("_update_shader"), &VisualShader::_update_shader); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset"); @@ -2295,6 +2520,17 @@ void VisualShader::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_FOG); BIND_ENUM_CONSTANT(TYPE_MAX); + BIND_ENUM_CONSTANT(VARYING_MODE_VERTEX_TO_FRAG_LIGHT); + BIND_ENUM_CONSTANT(VARYING_MODE_FRAG_TO_LIGHT); + BIND_ENUM_CONSTANT(VARYING_MODE_MAX); + + BIND_ENUM_CONSTANT(VARYING_TYPE_FLOAT); + BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(VARYING_TYPE_COLOR); + BIND_ENUM_CONSTANT(VARYING_TYPE_TRANSFORM); + BIND_ENUM_CONSTANT(VARYING_TYPE_MAX); + BIND_CONSTANT(NODE_ID_INVALID); BIND_CONSTANT(NODE_ID_OUTPUT); } @@ -2327,6 +2563,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { // Node3D, Vertex { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "vertex_id", "VERTEX_ID" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" }, @@ -2348,6 +2585,9 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" }, + { 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" }, // Node3D, Fragment { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" }, @@ -2374,6 +2614,9 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_roughness_texture", "NORMAL_ROUGHNESS_TEXTURE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" }, + { 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" }, // Node3D, Light { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" }, @@ -2384,6 +2627,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light", "LIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_color", "LIGHT_COLOR" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "attenuation", "ATTENUATION" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "shadow_attenuation", "SHADOW_ATTENUATION" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "diffuse", "DIFFUSE_LIGHT" }, @@ -2415,6 +2659,8 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "instance_custom", "INSTANCE_CUSTOM.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "instance_custom_alpha", "INSTANCE_CUSTOM.a" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "instance_id", "INSTANCE_ID" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "vertex_id", "VERTEX_ID" }, // Canvas Item, Fragment { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "fragcoord", "FRAGCOORD.xyz" }, @@ -3144,6 +3390,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR.rgb" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_view_matrix", "MODELVIEW_MATRIX" }, //////////////////////////////////////////////////////////////////////// // Node3D, Fragment. @@ -3155,6 +3402,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular", "SPECULAR" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" }, @@ -3163,14 +3411,17 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat", "CLEARCOAT" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_gloss", "CLEARCOAT_GLOSS" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_roughness", "CLEARCOAT_ROUGHNESS" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "anisotropy_flow", "ANISOTROPY_FLOW" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor_threshold", "ALPHA_SCISSOR_THRESHOLD" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_hash_scale", "ALPHA_HASH_SCALE" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_aa_edge", "ALPHA_ANTIALIASING_EDGE" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "alpha_uv", "ALPHA_TEXTURE_COORDINATE" }, + //////////////////////////////////////////////////////////////////////// // Node3D, Light. //////////////////////////////////////////////////////////////////////// @@ -3294,7 +3545,7 @@ bool VisualShaderNodeOutput::is_port_separator(int p_index) const { } if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) { String name = get_input_port_name(p_index); - return bool(name == "Normal" || name == "Rim" || name == "Alpha Scissor Threshold"); + return bool(name == "Ao" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold"); } return false; } @@ -4199,3 +4450,299 @@ String VisualShaderNodeGlobalExpression::generate_global(Shader::Mode p_mode, Vi VisualShaderNodeGlobalExpression::VisualShaderNodeGlobalExpression() { set_editable(false); } + +////////////// Varying + +List<VisualShaderNodeVarying::Varying> varyings; + +void VisualShaderNodeVarying::add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) { // static + varyings.push_back({ p_name, p_mode, p_type }); +} + +void VisualShaderNodeVarying::clear_varyings() { // static + varyings.clear(); +} + +bool VisualShaderNodeVarying::has_varying(const String &p_name) { // static + for (const VisualShaderNodeVarying::Varying &E : varyings) { + if (E.name == p_name) { + return true; + } + } + return false; +} + +int VisualShaderNodeVarying::get_varyings_count() const { + return varyings.size(); +} + +String VisualShaderNodeVarying::get_varying_name_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < varyings.size()) { + return varyings[p_idx].name; + } + return ""; +} + +VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_name(const String &p_name) const { + for (int i = 0; i < varyings.size(); i++) { + if (varyings[i].name == p_name) { + return varyings[i].type; + } + } + return VisualShader::VARYING_TYPE_FLOAT; +} + +VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < varyings.size()) { + return varyings[p_idx].type; + } + return VisualShader::VARYING_TYPE_FLOAT; +} + +VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_name(const String &p_name) const { + for (int i = 0; i < varyings.size(); i++) { + if (varyings[i].name == p_name) { + return varyings[i].mode; + } + } + return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT; +} + +VisualShader::VaryingMode VisualShaderNodeVarying::get_varying_mode_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < varyings.size()) { + return varyings[p_idx].mode; + } + return VisualShader::VARYING_MODE_VERTEX_TO_FRAG_LIGHT; +} + +VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < varyings.size()) { + return get_port_type(varyings[p_idx].type, 0); + } + return PORT_TYPE_SCALAR; +} + +////////////// + +void VisualShaderNodeVarying::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_varying_name", "name"), &VisualShaderNodeVarying::set_varying_name); + ClassDB::bind_method(D_METHOD("get_varying_name"), &VisualShaderNodeVarying::get_varying_name); + + ClassDB::bind_method(D_METHOD("set_varying_type", "type"), &VisualShaderNodeVarying::set_varying_type); + ClassDB::bind_method(D_METHOD("get_varying_type"), &VisualShaderNodeVarying::get_varying_type); + + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "varying_name"), "set_varying_name", "get_varying_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Vector,Transform"), "set_varying_type", "get_varying_type"); +} + +String VisualShaderNodeVarying::get_type_str() const { + switch (varying_type) { + case VisualShader::VARYING_TYPE_FLOAT: + return "float"; + case VisualShader::VARYING_TYPE_VECTOR_2D: + return "vec2"; + case VisualShader::VARYING_TYPE_VECTOR_3D: + return "vec3"; + case VisualShader::VARYING_TYPE_COLOR: + return "vec4"; + case VisualShader::VARYING_TYPE_TRANSFORM: + return "mat4"; + default: + break; + } + return ""; +} + +VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type(VisualShader::VaryingType p_type, int p_port) const { + switch (p_type) { + case VisualShader::VARYING_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case VisualShader::VARYING_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case VisualShader::VARYING_TYPE_COLOR: + if (p_port == 1) { + break; // scalar + } + return PORT_TYPE_VECTOR_3D; + case VisualShader::VARYING_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + default: + break; + } + return PORT_TYPE_SCALAR; +} + +void VisualShaderNodeVarying::set_varying_name(String p_varying_name) { + if (varying_name == p_varying_name) { + return; + } + varying_name = p_varying_name; + emit_changed(); +} + +String VisualShaderNodeVarying::get_varying_name() const { + return varying_name; +} + +void VisualShaderNodeVarying::set_varying_type(VisualShader::VaryingType p_varying_type) { + ERR_FAIL_INDEX(p_varying_type, VisualShader::VARYING_TYPE_MAX); + if (varying_type == p_varying_type) { + return; + } + varying_type = p_varying_type; + emit_changed(); +} + +VisualShader::VaryingType VisualShaderNodeVarying::get_varying_type() const { + return varying_type; +} + +VisualShaderNodeVarying::VisualShaderNodeVarying() { +} + +////////////// Varying Setter + +String VisualShaderNodeVaryingSetter::get_caption() const { + return vformat("VaryingSetter"); +} + +int VisualShaderNodeVaryingSetter::get_input_port_count() const { + if (varying_type == VisualShader::VARYING_TYPE_COLOR) { + return 2; + } + return 1; +} + +VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_input_port_type(int p_port) const { + return get_port_type(varying_type, p_port); +} + +String VisualShaderNodeVaryingSetter::get_input_port_name(int p_port) const { + if (varying_type == VisualShader::VARYING_TYPE_COLOR) { + if (p_port == 0) { + return "color"; + } else { + return "alpha"; + } + } + return ""; +} + +int VisualShaderNodeVaryingSetter::get_output_port_count() const { + return 0; +} + +VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeVaryingSetter::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeVaryingSetter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return vformat("varying %s %s;\n", get_type_str(), varying_name); +} + +String VisualShaderNodeVaryingSetter::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 { + String code; + if (varying_name == "[None]") { + return code; + } + if (varying_type == VisualShader::VARYING_TYPE_COLOR) { + code += vformat(" %s = vec4(%s, %s);\n", varying_name, p_input_vars[0], p_input_vars[1]); + } else { + code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]); + } + return code; +} + +VisualShaderNodeVaryingSetter::VisualShaderNodeVaryingSetter() { +} + +////////////// Varying Getter + +String VisualShaderNodeVaryingGetter::get_caption() const { + return vformat("VaryingGetter"); +} + +int VisualShaderNodeVaryingGetter::get_input_port_count() const { + return 0; +} + +VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeVaryingGetter::get_input_port_name(int p_port) const { + return ""; +} + +int VisualShaderNodeVaryingGetter::get_output_port_count() const { + if (varying_type == VisualShader::VARYING_TYPE_COLOR) { + return 2; + } + return 1; +} + +VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_output_port_type(int p_port) const { + return get_port_type(varying_type, p_port); +} + +String VisualShaderNodeVaryingGetter::get_output_port_name(int p_port) const { + if (varying_type == VisualShader::VARYING_TYPE_COLOR) { + if (p_port == 0) { + return "color"; + } else { + return "alpha"; + } + } + return ""; +} + +bool VisualShaderNodeVaryingGetter::has_output_port_preview(int p_port) const { + return false; +} + +String VisualShaderNodeVaryingGetter::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 { + String from = varying_name; + String from2; + + if (varying_name == "[None]") { + switch (varying_type) { + case VisualShader::VARYING_TYPE_FLOAT: + from = "0.0"; + break; + case VisualShader::VARYING_TYPE_VECTOR_2D: + from = "vec2(0.0)"; + break; + case VisualShader::VARYING_TYPE_VECTOR_3D: + from = "vec3(0.0)"; + break; + case VisualShader::VARYING_TYPE_COLOR: + from = "vec3(0.0)"; + from2 = "0.0"; + break; + case VisualShader::VARYING_TYPE_TRANSFORM: + from = "mat4(1.0)"; + break; + default: + break; + } + } else if (varying_type == VisualShader::VARYING_TYPE_COLOR) { + from = varying_name + ".rgb"; + from2 = varying_name + ".a"; + } + + if (varying_type == VisualShader::VARYING_TYPE_COLOR) { + String code; + code += vformat(" %s = %s;\n", p_output_vars[0], from); + code += vformat(" %s = %s;\n", p_output_vars[1], from2); + return code; + } + return vformat(" %s = %s;\n", p_output_vars[0], from); +} + +VisualShaderNodeVaryingGetter::VisualShaderNodeVaryingGetter() { + varying_name = "[None]"; +} diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index d3b5365893..2d4b2852e9 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -73,6 +73,49 @@ public: List<Ref<Texture2D>> params; }; + enum VaryingMode { + VARYING_MODE_VERTEX_TO_FRAG_LIGHT, + VARYING_MODE_FRAG_TO_LIGHT, + VARYING_MODE_MAX, + }; + + enum VaryingType { + VARYING_TYPE_FLOAT, + VARYING_TYPE_VECTOR_2D, + VARYING_TYPE_VECTOR_3D, + VARYING_TYPE_COLOR, + VARYING_TYPE_TRANSFORM, + VARYING_TYPE_MAX, + }; + + struct Varying { + String name; + VaryingMode mode; + VaryingType type; + + Varying() { + } + + Varying(String p_name, VaryingMode p_mode, VaryingType p_type) : + name(p_name), mode(p_mode), type(p_type) {} + + bool from_string(const String &p_str) { + Vector<String> arr = p_str.split(","); + if (arr.size() != 2) { + return false; + } + + mode = (VaryingMode)arr[0].to_int(); + type = (VaryingType)arr[1].to_int(); + + return true; + } + + String to_string() const { + return vformat("%s,%s", itos((int)mode), itos((int)type)); + } + }; + private: Type current_type; @@ -94,14 +137,12 @@ private: Vector2 graph_offset; - struct RenderModeEnums { - Shader::Mode mode = Shader::Mode::MODE_MAX; - const char *string; - }; - HashMap<String, int> modes; Set<StringName> flags; + Map<String, Varying> varyings; + List<Varying> varyings_list; + mutable SafeFlag dirty; void _queue_update(); @@ -116,7 +157,7 @@ private: } }; - Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const; + Error _write_node(Type p_type, StringBuilder *global_code, StringBuilder *global_code_per_node, Map<Type, StringBuilder> *global_code_per_func, StringBuilder &code, Vector<DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const; void _input_type_changed(Type p_type, int p_id); bool has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const; @@ -151,6 +192,18 @@ public: void add_node(Type p_type, const Ref<VisualShaderNode> &p_node, const Vector2 &p_position, int p_id); void set_node_position(Type p_type, int p_id, const Vector2 &p_position); + void add_varying(const String &p_name, VaryingMode p_mode, VaryingType p_type); + void remove_varying(const String &p_name); + bool has_varying(const String &p_name) const; + int get_varyings_count() const; + const Varying *get_varying_by_index(int p_idx) const; + + void set_varying_mode(const String &p_name, VaryingMode p_mode); + VaryingMode get_varying_mode(const String &p_name); + + void set_varying_type(const String &p_name, VaryingType p_type); + VaryingType get_varying_type(const String &p_name); + Vector2 get_node_position(Type p_type, int p_id) const; Ref<VisualShaderNode> get_node(Type p_type, int p_id) const; @@ -190,6 +243,8 @@ public: }; VARIANT_ENUM_CAST(VisualShader::Type) +VARIANT_ENUM_CAST(VisualShader::VaryingMode) +VARIANT_ENUM_CAST(VisualShader::VaryingType) /// /// /// @@ -328,14 +383,20 @@ protected: GDVIRTUAL1RC(int, _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) GDVIRTUAL1RC(String, _get_global_code, Shader::Mode) GDVIRTUAL0RC(bool, _is_highend) + GDVIRTUAL2RC(bool, _is_available, Shader::Mode, VisualShader::Type) + + bool _is_valid_code(const String &p_code) const; protected: void _set_input_port_default_value(int p_port, const Variant &p_value); + bool is_available(Shader::Mode p_mode, VisualShader::Type p_type) const; virtual String 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 = false) const override; virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override; + virtual String generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; static void _bind_methods(); @@ -697,6 +758,103 @@ public: VisualShaderNodeGlobalExpression(); }; +class VisualShaderNodeVarying : public VisualShaderNode { + GDCLASS(VisualShaderNodeVarying, VisualShaderNode); + +public: + struct Varying { + String name; + VisualShader::VaryingMode mode; + VisualShader::VaryingType type; + bool assigned = false; + }; + +protected: + VisualShader::VaryingType varying_type = VisualShader::VARYING_TYPE_FLOAT; + String varying_name = "[None]"; + +public: // internal + static void add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type); + static void clear_varyings(); + static bool has_varying(const String &p_name); + + int get_varyings_count() const; + String get_varying_name_by_index(int p_idx) const; + VisualShader::VaryingMode get_varying_mode_by_name(const String &p_name) const; + VisualShader::VaryingMode get_varying_mode_by_index(int p_idx) const; + VisualShader::VaryingType get_varying_type_by_name(const String &p_name) const; + VisualShader::VaryingType get_varying_type_by_index(int p_idx) const; + PortType get_port_type_by_index(int p_idx) const; + +protected: + static void _bind_methods(); + +protected: + String get_type_str() const; + PortType get_port_type(VisualShader::VaryingType p_type, int p_port) const; + +public: + virtual String get_caption() const override = 0; + + virtual int get_input_port_count() const override = 0; + virtual PortType get_input_port_type(int p_port) const override = 0; + virtual String get_input_port_name(int p_port) const override = 0; + + virtual int get_output_port_count() const override = 0; + virtual PortType get_output_port_type(int p_port) const override = 0; + virtual String get_output_port_name(int p_port) const override = 0; + + virtual String 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 = false) const override = 0; + + void set_varying_name(String p_varying_name); + String get_varying_name() const; + + void set_varying_type(VisualShader::VaryingType p_varying_type); + VisualShader::VaryingType get_varying_type() const; + + VisualShaderNodeVarying(); +}; + +class VisualShaderNodeVaryingSetter : public VisualShaderNodeVarying { + GDCLASS(VisualShaderNodeVaryingSetter, VisualShaderNodeVarying); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String 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 = false) const override; + + VisualShaderNodeVaryingSetter(); +}; + +class VisualShaderNodeVaryingGetter : public VisualShaderNodeVarying { + GDCLASS(VisualShaderNodeVaryingGetter, VisualShaderNodeVarying); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; + + virtual String 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 = false) const override; + + VisualShaderNodeVaryingGetter(); +}; + extern String make_unique_id(VisualShader::Type p_type, int p_id, const String &p_name); #endif // VISUAL_SHADER_H diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index f2479199ee..7b4d7e66d4 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2843,8 +2843,7 @@ String VisualShaderNodeColorFunc::generate_code(Shader::Mode p_mode, VisualShade code += " vec3 c = " + p_input_vars[0] + ";\n"; code += " float max1 = max(c.r, c.g);\n"; code += " float max2 = max(max1, c.b);\n"; - code += " float max3 = max(max1, max2);\n"; - code += " " + p_output_vars[0] + " = vec3(max3, max3, max3);\n"; + code += " " + p_output_vars[0] + " = vec3(max2, max2, max2);\n"; code += " }\n"; break; case FUNC_SEPIA: @@ -5697,7 +5696,7 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port) String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const { String code; - code += "// TRIPLANAR FUNCTION GLOBAL CODE\n"; + code += "// " + get_caption() + "\n"; code += " vec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n"; code += " vec4 samp = vec4(0.0);\n"; code += " samp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n"; @@ -5720,11 +5719,13 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader: String code; if (p_type == VisualShader::TYPE_VERTEX) { - code += " // TRIPLANAR FUNCTION VERTEX CODE\n"; + code += "// " + get_caption() + "\n"; + code += " {\n"; code += " triplanar_power_normal = pow(abs(NORMAL), vec3(triplanar_sharpness));\n"; code += " triplanar_power_normal /= dot(triplanar_power_normal, vec3(1.0));\n"; code += " triplanar_pos = VERTEX * triplanar_scale + triplanar_offset;\n"; code += " triplanar_pos *= vec3(1.0, -1.0, 1.0);\n"; + code += " }\n"; } return code; diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index 1885211d57..398c33c452 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -1318,7 +1318,7 @@ String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, Visual code += tab + "TRANSFORM = " + p_input_vars[5] + ";\n"; } } else { - if (!p_input_vars[0].is_empty()) { // active (begin) + if (!p_input_vars[0].is_empty()) { // Active (begin). code += tab + "ACTIVE = " + p_input_vars[0] + ";\n"; code += tab + "if(ACTIVE) {\n"; tab += " "; @@ -1381,7 +1381,7 @@ String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, Visual code += tab + "TRANSFORM " + op + " mat4(vec4(" + p_input_vars[scale] + ", 0, 0, 0), vec4(0, " + p_input_vars[scale] + ", 0, 0), vec4(0, 0, " + p_input_vars[scale] + ", 0), vec4(0, 0, 0, 1));\n"; } } - if (!p_input_vars[0].is_empty()) { // active (end) + if (!p_input_vars[0].is_empty()) { // Active (end). code += " }\n"; } } |