diff options
Diffstat (limited to 'scene')
228 files changed, 8395 insertions, 5932 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 4565462247..7fe464d2f4 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -108,6 +108,7 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const { if (!frames.is_valid()) { return; } + if (p_property.name == "animation") { p_property.hint = PROPERTY_HINT_ENUM; List<StringName> names; @@ -137,9 +138,15 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const { p_property.hint_string = String(animation) + "," + p_property.hint_string; } } + return; } if (p_property.name == "frame") { + if (playing) { + p_property.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY; + return; + } + p_property.hint = PROPERTY_HINT_RANGE; if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) { p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; @@ -175,37 +182,42 @@ void AnimatedSprite2D::_notification(int p_what) { if (timeout <= 0) { timeout = _get_frame_duration(); - int fc = frames->get_frame_count(animation); - if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) { - if (frames->get_animation_loop(animation)) { - if (backwards) { - frame = fc - 1; - } else { - frame = 0; - } - - emit_signal(SceneStringNames::get_singleton()->animation_finished); - } else { - if (backwards) { + int last_frame = frames->get_frame_count(animation) - 1; + if (!backwards) { + // Forward. + if (frame >= last_frame) { + if (frames->get_animation_loop(animation)) { frame = 0; - } else { - frame = fc - 1; - } - - if (!is_over) { - is_over = true; emit_signal(SceneStringNames::get_singleton()->animation_finished); + } else { + frame = last_frame; + if (!is_over) { + is_over = true; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } } + } else { + frame++; } } else { - if (backwards) { - frame--; + // Reversed. + if (frame <= 0) { + if (frames->get_animation_loop(animation)) { + frame = last_frame; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } else { + frame = 0; + if (!is_over) { + is_over = true; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } + } } else { - frame++; + frame--; } } - update(); + queue_redraw(); emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -259,14 +271,15 @@ void AnimatedSprite2D::_notification(int p_what) { void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { if (frames.is_valid()) { - frames->disconnect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed)); + frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed)); } + frames = p_frames; if (frames.is_valid()) { - frames->connect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed)); + frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed)); } - if (!frames.is_valid()) { + if (frames.is_null()) { frame = 0; } else { set_frame(frame); @@ -274,7 +287,7 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { notify_property_list_changed(); _reset_timeout(); - update(); + queue_redraw(); update_configuration_warnings(); } @@ -283,7 +296,7 @@ Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const { } void AnimatedSprite2D::set_frame(int p_frame) { - if (!frames.is_valid()) { + if (frames.is_null()) { return; } @@ -304,7 +317,7 @@ void AnimatedSprite2D::set_frame(int p_frame) { frame = p_frame; _reset_timeout(); - update(); + queue_redraw(); emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -318,7 +331,7 @@ void AnimatedSprite2D::set_speed_scale(double p_speed_scale) { speed_scale = MAX(p_speed_scale, 0.0f); - // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed + // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed. _reset_timeout(); timeout -= elapsed; } @@ -329,7 +342,7 @@ double AnimatedSprite2D::get_speed_scale() const { void AnimatedSprite2D::set_centered(bool p_center) { centered = p_center; - update(); + queue_redraw(); item_rect_changed(); } @@ -339,7 +352,7 @@ bool AnimatedSprite2D::is_centered() const { void AnimatedSprite2D::set_offset(const Point2 &p_offset) { offset = p_offset; - update(); + queue_redraw(); item_rect_changed(); } @@ -349,7 +362,7 @@ Point2 AnimatedSprite2D::get_offset() const { void AnimatedSprite2D::set_flip_h(bool p_flip) { hflip = p_flip; - update(); + queue_redraw(); } bool AnimatedSprite2D::is_flipped_h() const { @@ -358,7 +371,7 @@ bool AnimatedSprite2D::is_flipped_h() const { void AnimatedSprite2D::set_flip_v(bool p_flip) { vflip = p_flip; - update(); + queue_redraw(); } bool AnimatedSprite2D::is_flipped_v() const { @@ -368,7 +381,7 @@ bool AnimatedSprite2D::is_flipped_v() const { void AnimatedSprite2D::_res_changed() { set_frame(frame); - update(); + queue_redraw(); } void AnimatedSprite2D::set_playing(bool p_playing) { @@ -378,6 +391,7 @@ void AnimatedSprite2D::set_playing(bool p_playing) { playing = p_playing; _reset_timeout(); set_process_internal(playing); + notify_property_list_changed(); } bool AnimatedSprite2D::is_playing() const { @@ -433,7 +447,7 @@ void AnimatedSprite2D::set_animation(const StringName &p_animation) { _reset_timeout(); set_frame(0); notify_property_list_changed(); - update(); + queue_redraw(); } StringName AnimatedSprite2D::get_animation() const { diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 75f1497edc..b3f80b5e43 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -426,39 +426,49 @@ bool Area2D::is_monitorable() const { } TypedArray<Node2D> Area2D::get_overlapping_bodies() const { - ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off."); TypedArray<Node2D> ret; + ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping bodies when monitoring is off."); ret.resize(body_map.size()); int idx = 0; for (const KeyValue<ObjectID, BodyState> &E : body_map) { Object *obj = ObjectDB::get_instance(E.key); - if (!obj) { - ret.resize(ret.size() - 1); //ops - } else { - ret[idx++] = obj; + if (obj) { + ret[idx] = obj; + idx++; } } + ret.resize(idx); return ret; } TypedArray<Area2D> Area2D::get_overlapping_areas() const { - ERR_FAIL_COND_V_MSG(!monitoring, Array(), "Can't find overlapping bodies when monitoring is off."); TypedArray<Area2D> ret; + ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping areas when monitoring is off."); ret.resize(area_map.size()); int idx = 0; for (const KeyValue<ObjectID, AreaState> &E : area_map) { Object *obj = ObjectDB::get_instance(E.key); - if (!obj) { - ret.resize(ret.size() - 1); //ops - } else { - ret[idx++] = obj; + if (obj) { + ret[idx] = obj; + idx++; } } + ret.resize(idx); return ret; } +bool Area2D::has_overlapping_bodies() const { + ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping bodies when monitoring is off."); + return !body_map.is_empty(); +} + +bool Area2D::has_overlapping_areas() const { + ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping areas when monitoring is off."); + return !area_map.is_empty(); +} + bool Area2D::overlaps_area(Node *p_area) const { ERR_FAIL_NULL_V(p_area, false); HashMap<ObjectID, AreaState>::ConstIterator E = area_map.find(p_area->get_instance_id()); @@ -578,6 +588,9 @@ void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_overlapping_bodies"), &Area2D::get_overlapping_bodies); ClassDB::bind_method(D_METHOD("get_overlapping_areas"), &Area2D::get_overlapping_areas); + ClassDB::bind_method(D_METHOD("has_overlapping_bodies"), &Area2D::has_overlapping_bodies); + ClassDB::bind_method(D_METHOD("has_overlapping_areas"), &Area2D::has_overlapping_areas); + ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area2D::overlaps_body); ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area2D::overlaps_area); @@ -607,7 +620,7 @@ void Area2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:px"), "set_gravity_point_center", "get_gravity_point_center"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_direction"), "set_gravity_direction", "get_gravity_direction"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_lesser,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-4096,4096,0.001,or_less,or_greater,suffix:px/s\u00B2"), "set_gravity", "get_gravity"); ADD_GROUP("Linear Damp", "linear_damp_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode"); diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index 3d8d77eabb..f70f1dfc3d 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -180,6 +180,9 @@ public: TypedArray<Node2D> get_overlapping_bodies() const; //function for script TypedArray<Area2D> get_overlapping_areas() const; //function for script + bool has_overlapping_bodies() const; + bool has_overlapping_areas() const; + bool overlaps_area(Node *p_area) const; bool overlaps_body(Node *p_body) const; diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index fc019b6cf9..85ec745aee 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -43,13 +43,18 @@ void AudioStreamPlayer2D::_notification(int p_what) { if (autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } + set_stream_paused(false); } break; case NOTIFICATION_EXIT_TREE: { - stop(); + set_stream_paused(true); AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); } break; + case NOTIFICATION_PREDELETE: { + stop(); + } break; + case NOTIFICATION_PAUSED: { if (!can_process()) { // Node can't process so we start fading out to silence. diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 88f9c2a4a6..a11b2b66bf 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -39,7 +39,7 @@ void Camera2D::_update_scroll() { } if (Engine::get_singleton()->is_editor_hint()) { - update(); //will just be drawn + queue_redraw(); //will just be drawn return; } @@ -392,7 +392,7 @@ void Camera2D::_make_current(Object *p_which) { current = true; if (is_inside_tree()) { get_viewport()->_camera_2d_set(this); - update(); + queue_redraw(); } } else { current = false; @@ -400,7 +400,7 @@ void Camera2D::_make_current(Object *p_which) { if (get_viewport()->get_camera_2d() == this) { get_viewport()->_camera_2d_set(nullptr); } - update(); + queue_redraw(); } } } @@ -461,7 +461,7 @@ bool Camera2D::is_limit_smoothing_enabled() const { void Camera2D::set_drag_margin(Side p_side, real_t p_drag_margin) { ERR_FAIL_INDEX((int)p_side, 4); drag_margin[p_side] = p_drag_margin; - update(); + queue_redraw(); } real_t Camera2D::get_drag_margin(Side p_side) const { @@ -625,7 +625,7 @@ Node *Camera2D::get_custom_viewport() const { void Camera2D::set_screen_drawing_enabled(bool enable) { screen_drawing_enabled = enable; #ifdef TOOLS_ENABLED - update(); + queue_redraw(); #endif } @@ -636,7 +636,7 @@ bool Camera2D::is_screen_drawing_enabled() const { void Camera2D::set_limit_drawing_enabled(bool enable) { limit_drawing_enabled = enable; #ifdef TOOLS_ENABLED - update(); + queue_redraw(); #endif } @@ -647,7 +647,7 @@ bool Camera2D::is_limit_drawing_enabled() const { void Camera2D::set_margin_drawing_enabled(bool enable) { margin_drawing_enabled = enable; #ifdef TOOLS_ENABLED - update(); + queue_redraw(); #endif } @@ -701,8 +701,8 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_drag_margin", "margin", "drag_margin"), &Camera2D::set_drag_margin); ClassDB::bind_method(D_METHOD("get_drag_margin", "margin"), &Camera2D::get_drag_margin); - ClassDB::bind_method(D_METHOD("get_camera_position"), &Camera2D::get_camera_position); - ClassDB::bind_method(D_METHOD("get_camera_screen_center"), &Camera2D::get_camera_screen_center); + ClassDB::bind_method(D_METHOD("get_target_position"), &Camera2D::get_camera_position); + ClassDB::bind_method(D_METHOD("get_screen_center_position"), &Camera2D::get_camera_screen_center); ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &Camera2D::set_zoom); ClassDB::bind_method(D_METHOD("get_zoom"), &Camera2D::get_zoom); diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp index bbf3fff0ad..d4182f85a7 100644 --- a/scene/2d/canvas_group.cpp +++ b/scene/2d/canvas_group.cpp @@ -36,7 +36,7 @@ void CanvasGroup::set_fit_margin(real_t p_fit_margin) { fit_margin = p_fit_margin; RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, fit_margin, use_mipmaps); - update(); + queue_redraw(); } real_t CanvasGroup::get_fit_margin() const { @@ -49,7 +49,7 @@ void CanvasGroup::set_clear_margin(real_t p_clear_margin) { clear_margin = p_clear_margin; RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_TRANSPARENT, clear_margin, true, clear_margin, use_mipmaps); - update(); + queue_redraw(); } real_t CanvasGroup::get_clear_margin() const { diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 04cd999982..b69b19d30d 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -198,7 +198,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) { _build_polygon(); _update_in_shape_owner(); } - update(); + queue_redraw(); update_configuration_warnings(); } @@ -213,7 +213,7 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) { _build_polygon(); _update_in_shape_owner(); } - update(); + queue_redraw(); update_configuration_warnings(); } @@ -264,7 +264,7 @@ TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const { void CollisionPolygon2D::set_disabled(bool p_disabled) { disabled = p_disabled; - update(); + queue_redraw(); if (parent) { parent->shape_owner_set_disabled(owner_id, p_disabled); } @@ -276,7 +276,7 @@ bool CollisionPolygon2D::is_disabled() const { void CollisionPolygon2D::set_one_way_collision(bool p_enable) { one_way_collision = p_enable; - update(); + queue_redraw(); if (parent) { parent->shape_owner_set_one_way_collision(owner_id, p_enable); } diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index cbecf28877..039bfee451 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -36,7 +36,7 @@ #include "scene/resources/convex_polygon_shape_2d.h" void CollisionShape2D::_shape_changed() { - update(); + queue_redraw(); } void CollisionShape2D::_update_in_shape_owner(bool p_xform_only) { @@ -140,7 +140,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) { shape->disconnect("changed", callable_mp(this, &CollisionShape2D::_shape_changed)); } shape = p_shape; - update(); + queue_redraw(); if (parent) { parent->shape_owner_clear_shapes(owner_id); if (shape.is_valid()) { @@ -192,7 +192,7 @@ TypedArray<String> CollisionShape2D::get_configuration_warnings() const { void CollisionShape2D::set_disabled(bool p_disabled) { disabled = p_disabled; - update(); + queue_redraw(); if (parent) { parent->shape_owner_set_disabled(owner_id, p_disabled); } @@ -204,7 +204,7 @@ bool CollisionShape2D::is_disabled() const { void CollisionShape2D::set_one_way_collision(bool p_enable) { one_way_collision = p_enable; - update(); + queue_redraw(); if (parent) { parent->shape_owner_set_one_way_collision(owner_id, p_enable); } diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 1929475c8f..4523e5dfe9 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -211,13 +211,13 @@ void CPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) { texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &CPUParticles2D::_texture_changed)); } - update(); + queue_redraw(); _update_mesh_texture(); } void CPUParticles2D::_texture_changed() { if (texture.is_valid()) { - update(); + queue_redraw(); _update_mesh_texture(); } } @@ -556,7 +556,7 @@ static real_t rand_from_seed(uint32_t &seed) { void CPUParticles2D::_update_internal() { if (particles.size() == 0 || !is_visible_in_tree()) { - _set_redraw(false); + _set_do_redraw(false); return; } @@ -567,7 +567,7 @@ void CPUParticles2D::_update_internal() { inactive_time += delta; if (inactive_time > lifetime * 1.2) { set_process_internal(false); - _set_redraw(false); + _set_do_redraw(false); //reset variables time = 0; @@ -577,7 +577,7 @@ void CPUParticles2D::_update_internal() { return; } } - _set_redraw(true); + _set_do_redraw(true); if (time == 0 && pre_process_time > 0.0) { double frame_time; @@ -719,17 +719,17 @@ void CPUParticles2D::_particles_process(double p_delta) { /*real_t tex_linear_velocity = 0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0); + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0); }*/ real_t tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); + tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv); } real_t tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv); + tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv); } p.seed = Math::rand(); @@ -825,51 +825,51 @@ void CPUParticles2D::_particles_process(double p_delta) { real_t tex_linear_velocity = 1.0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv); + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(tv); } real_t tex_orbit_velocity = 1.0; if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv); + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->sample(tv); } real_t tex_angular_velocity = 1.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv); + tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->sample(tv); } real_t tex_linear_accel = 1.0; if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv); + tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->sample(tv); } real_t tex_tangential_accel = 1.0; if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv); + tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->sample(tv); } real_t tex_radial_accel = 1.0; if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv); + tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->sample(tv); } real_t tex_damping = 1.0; if (curve_parameters[PARAM_DAMPING].is_valid()) { - tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv); + tex_damping = curve_parameters[PARAM_DAMPING]->sample(tv); } real_t tex_angle = 1.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); + tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv); } real_t tex_anim_speed = 1.0; if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) { - tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv); + tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->sample(tv); } real_t tex_anim_offset = 1.0; if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv); + tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->sample(tv); } Vector2 force = gravity; @@ -921,18 +921,18 @@ void CPUParticles2D::_particles_process(double p_delta) { Vector2 tex_scale = Vector2(1.0, 1.0); if (split_scale) { if (scale_curve_x.is_valid()) { - tex_scale.x = scale_curve_x->interpolate(tv); + tex_scale.x = scale_curve_x->sample(tv); } else { tex_scale.x = 1.0; } if (scale_curve_y.is_valid()) { - tex_scale.y = scale_curve_y->interpolate(tv); + tex_scale.y = scale_curve_y->sample(tv); } else { tex_scale.y = 1.0; } } else { if (curve_parameters[PARAM_SCALE].is_valid()) { - real_t tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv); + real_t tmp_scale = curve_parameters[PARAM_SCALE]->sample(tv); tex_scale.x = tmp_scale; tex_scale.y = tmp_scale; } @@ -940,7 +940,7 @@ void CPUParticles2D::_particles_process(double p_delta) { real_t tex_hue_variation = 0.0; if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) { - tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv); + tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->sample(tv); } real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand); @@ -1062,16 +1062,16 @@ void CPUParticles2D::_update_particle_data_buffer() { } } -void CPUParticles2D::_set_redraw(bool p_redraw) { - if (redraw == p_redraw) { +void CPUParticles2D::_set_do_redraw(bool p_do_redraw) { + if (do_redraw == p_do_redraw) { return; } - redraw = p_redraw; + do_redraw = p_do_redraw; { MutexLock lock(update_mutex); - if (redraw) { + if (do_redraw) { RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &CPUParticles2D::_update_render_thread)); RS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); @@ -1086,7 +1086,7 @@ void CPUParticles2D::_set_redraw(bool p_redraw) { } } - update(); // redraw to update render list + queue_redraw(); // redraw to update render list } void CPUParticles2D::_update_render_thread() { @@ -1102,7 +1102,7 @@ void CPUParticles2D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { - _set_redraw(false); + _set_do_redraw(false); } break; case NOTIFICATION_DRAW: { @@ -1111,7 +1111,7 @@ void CPUParticles2D::_notification(int p_what) { _update_internal(); } - if (!redraw) { + if (!do_redraw) { return; // don't add to render list } @@ -1383,32 +1383,32 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater,suffix:px/s"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY); ADD_GROUP("Angular Velocity", "angular_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); ADD_GROUP("Orbit Velocity", "orbit_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); ADD_GROUP("Linear Accel", "linear_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL); ADD_GROUP("Radial Accel", "radial_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL); ADD_GROUP("Tangential Accel", "tangential_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL); ADD_GROUP("Damping", ""); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE); ADD_GROUP("Scale", ""); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE); @@ -1428,8 +1428,8 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION); ADD_GROUP("Animation", "anim_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 8f1671d280..3fd1c7fd0f 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -102,7 +102,7 @@ private: double inactive_time = 0.0; double frame_remainder = 0.0; int cycle = 0; - bool redraw = false; + bool do_redraw = false; RID mesh; RID multimesh; @@ -186,7 +186,7 @@ private: void _update_mesh_texture(); - void _set_redraw(bool p_redraw); + void _set_do_redraw(bool p_do_redraw); void _texture_changed(); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 65ead7afbc..bed68b4ee0 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -30,6 +30,7 @@ #include "gpu_particles_2d.h" +#include "core/core_string_names.h" #include "scene/resources/particle_process_material.h" #ifdef TOOLS_ENABLED @@ -99,7 +100,7 @@ void GPUParticles2D::set_visibility_rect(const Rect2 &p_visibility_rect) { RS::get_singleton()->particles_set_custom_aabb(particles, aabb); - update(); + queue_redraw(); } void GPUParticles2D::set_use_local_coordinates(bool p_enable) { @@ -141,7 +142,7 @@ void GPUParticles2D::set_process_material(const Ref<Material> &p_material) { void GPUParticles2D::set_trail_enabled(bool p_enabled) { trail_enabled = p_enabled; RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); - update(); + queue_redraw(); RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED); } @@ -150,7 +151,7 @@ void GPUParticles2D::set_trail_length(double p_seconds) { ERR_FAIL_COND(p_seconds < 0.001); trail_length = p_seconds; RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); - update(); + queue_redraw(); } void GPUParticles2D::set_trail_sections(int p_sections) { @@ -158,7 +159,7 @@ void GPUParticles2D::set_trail_sections(int p_sections) { ERR_FAIL_COND(p_sections > 128); trail_sections = p_sections; - update(); + queue_redraw(); } void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) { @@ -166,13 +167,13 @@ void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) { ERR_FAIL_COND(p_subdivisions > 1024); trail_section_subdivisions = p_subdivisions; - update(); + queue_redraw(); } #ifdef TOOLS_ENABLED void GPUParticles2D::set_show_visibility_rect(bool p_show_visibility_rect) { show_visibility_rect = p_show_visibility_rect; - update(); + queue_redraw(); } #endif @@ -331,9 +332,17 @@ Rect2 GPUParticles2D::capture_rect() const { } void GPUParticles2D::set_texture(const Ref<Texture2D> &p_texture) { + if (texture.is_valid()) { + texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed)); + } + texture = p_texture; + + if (texture.is_valid()) { + texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &GPUParticles2D::_texture_changed)); + } _update_collision_size(); - update(); + queue_redraw(); } Ref<Texture2D> GPUParticles2D::get_texture() const { @@ -363,6 +372,14 @@ void GPUParticles2D::_attach_sub_emitter() { } } +void GPUParticles2D::_texture_changed() { + // Changes to the texture need to trigger an update to make + // the editor redraw the sprite with the updated texture. + if (texture.is_valid()) { + queue_redraw(); + } +} + void GPUParticles2D::set_sub_emitter(const NodePath &p_path) { if (is_inside_tree()) { RS::get_singleton()->particles_set_subemitter(particles, RID()); @@ -480,12 +497,21 @@ void GPUParticles2D::_notification(int p_what) { 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; + AtlasTexture *atlas_texure = Object::cast_to<AtlasTexture>(*texture); + if (atlas_texure && atlas_texure->get_atlas().is_valid()) { + Rect2 region_rect = atlas_texure->get_region(); + Size2 atlas_size = atlas_texure->get_atlas()->get_size(); + uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, region_rect.position.y / atlas_size.y)); + uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, region_rect.position.y / atlas_size.y)); + uvs.push_back(Vector2((region_rect.position.x + region_rect.size.x) / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); + uvs.push_back(Vector2(region_rect.position.x / atlas_size.x, (region_rect.position.y + region_rect.size.y) / atlas_size.y)); + } else { + uvs.push_back(Vector2(0, 0)); + uvs.push_back(Vector2(1, 0)); + uvs.push_back(Vector2(1, 1)); + uvs.push_back(Vector2(0, 1)); + } Vector<int> indices = { 0, 1, 2, 0, 2, 3 }; diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 7eece32898..10ae91775f 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -82,6 +82,8 @@ private: void _attach_sub_emitter(); + void _texture_changed(); + protected: static void _bind_methods(); void _validate_property(PropertyInfo &p_property) const; diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp index 7b9f7e14ca..89b6f3f9da 100644 --- a/scene/2d/joint_2d.cpp +++ b/scene/2d/joint_2d.cpp @@ -267,7 +267,7 @@ void PinJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBod void PinJoint2D::set_softness(real_t p_softness) { softness = p_softness; - update(); + queue_redraw(); if (is_configured()) { PhysicsServer2D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness); } @@ -321,7 +321,7 @@ void GrooveJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, Physics void GrooveJoint2D::set_length(real_t p_length) { length = p_length; - update(); + queue_redraw(); } real_t GrooveJoint2D::get_length() const { @@ -330,7 +330,7 @@ real_t GrooveJoint2D::get_length() const { void GrooveJoint2D::set_initial_offset(real_t p_initial_offset) { initial_offset = p_initial_offset; - update(); + queue_redraw(); } real_t GrooveJoint2D::get_initial_offset() const { @@ -387,7 +387,7 @@ void DampedSpringJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, P void DampedSpringJoint2D::set_length(real_t p_length) { length = p_length; - update(); + queue_redraw(); } real_t DampedSpringJoint2D::get_length() const { @@ -396,7 +396,7 @@ real_t DampedSpringJoint2D::get_length() const { void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) { rest_length = p_rest_length; - update(); + queue_redraw(); if (is_configured()) { PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length); } @@ -408,7 +408,7 @@ real_t DampedSpringJoint2D::get_rest_length() const { void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) { stiffness = p_stiffness; - update(); + queue_redraw(); if (is_configured()) { PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness); } @@ -420,7 +420,7 @@ real_t DampedSpringJoint2D::get_stiffness() const { void DampedSpringJoint2D::set_damping(real_t p_damping) { damping = p_damping; - update(); + queue_redraw(); if (is_configured()) { PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping); } diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 14188d7120..6c171383ca 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -153,7 +153,7 @@ OccluderPolygon2D::~OccluderPolygon2D() { void LightOccluder2D::_poly_changed() { #ifdef DEBUG_ENABLED - update(); + queue_redraw(); #endif } @@ -229,7 +229,7 @@ void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polyg if (occluder_polygon.is_valid()) { occluder_polygon->connect("changed", callable_mp(this, &LightOccluder2D::_poly_changed)); } - update(); + queue_redraw(); #endif } diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 837f3061f1..6a72280f3d 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -76,7 +76,7 @@ bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc void Line2D::set_points(const Vector<Vector2> &p_points) { _points = p_points; - update(); + queue_redraw(); } void Line2D::set_width(float p_width) { @@ -84,7 +84,7 @@ void Line2D::set_width(float p_width) { p_width = 0.0; } _width = p_width; - update(); + queue_redraw(); } float Line2D::get_width() const { @@ -104,7 +104,7 @@ void Line2D::set_curve(const Ref<Curve> &p_curve) { _curve->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_curve_changed)); } - update(); + queue_redraw(); } Ref<Curve> Line2D::get_curve() const { @@ -118,7 +118,7 @@ Vector<Vector2> Line2D::get_points() const { void Line2D::set_point_position(int i, Vector2 p_pos) { ERR_FAIL_INDEX(i, _points.size()); _points.set(i, p_pos); - update(); + queue_redraw(); } Vector2 Line2D::get_point_position(int i) const { @@ -134,7 +134,7 @@ void Line2D::clear_points() { int count = _points.size(); if (count > 0) { _points.clear(); - update(); + queue_redraw(); } } @@ -144,17 +144,17 @@ void Line2D::add_point(Vector2 p_pos, int p_atpos) { } else { _points.insert(p_atpos, p_pos); } - update(); + queue_redraw(); } void Line2D::remove_point(int i) { _points.remove_at(i); - update(); + queue_redraw(); } void Line2D::set_default_color(Color p_color) { _default_color = p_color; - update(); + queue_redraw(); } Color Line2D::get_default_color() const { @@ -174,7 +174,7 @@ void Line2D::set_gradient(const Ref<Gradient> &p_gradient) { _gradient->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Line2D::_gradient_changed)); } - update(); + queue_redraw(); } Ref<Gradient> Line2D::get_gradient() const { @@ -183,7 +183,7 @@ Ref<Gradient> Line2D::get_gradient() const { void Line2D::set_texture(const Ref<Texture2D> &p_texture) { _texture = p_texture; - update(); + queue_redraw(); } Ref<Texture2D> Line2D::get_texture() const { @@ -192,7 +192,7 @@ Ref<Texture2D> Line2D::get_texture() const { void Line2D::set_texture_mode(const LineTextureMode p_mode) { _texture_mode = p_mode; - update(); + queue_redraw(); } Line2D::LineTextureMode Line2D::get_texture_mode() const { @@ -201,7 +201,7 @@ Line2D::LineTextureMode Line2D::get_texture_mode() const { void Line2D::set_joint_mode(LineJointMode p_mode) { _joint_mode = p_mode; - update(); + queue_redraw(); } Line2D::LineJointMode Line2D::get_joint_mode() const { @@ -210,7 +210,7 @@ Line2D::LineJointMode Line2D::get_joint_mode() const { void Line2D::set_begin_cap_mode(LineCapMode p_mode) { _begin_cap_mode = p_mode; - update(); + queue_redraw(); } Line2D::LineCapMode Line2D::get_begin_cap_mode() const { @@ -219,7 +219,7 @@ Line2D::LineCapMode Line2D::get_begin_cap_mode() const { void Line2D::set_end_cap_mode(LineCapMode p_mode) { _end_cap_mode = p_mode; - update(); + queue_redraw(); } Line2D::LineCapMode Line2D::get_end_cap_mode() const { @@ -239,7 +239,7 @@ void Line2D::set_sharp_limit(float p_limit) { p_limit = 0.f; } _sharp_limit = p_limit; - update(); + queue_redraw(); } float Line2D::get_sharp_limit() const { @@ -248,7 +248,7 @@ float Line2D::get_sharp_limit() const { void Line2D::set_round_precision(int p_precision) { _round_precision = MAX(1, p_precision); - update(); + queue_redraw(); } int Line2D::get_round_precision() const { @@ -257,7 +257,7 @@ int Line2D::get_round_precision() const { void Line2D::set_antialiased(bool p_antialiased) { _antialiased = p_antialiased; - update(); + queue_redraw(); } bool Line2D::get_antialiased() const { @@ -334,11 +334,11 @@ void Line2D::_draw() { } void Line2D::_gradient_changed() { - update(); + queue_redraw(); } void Line2D::_curve_changed() { - update(); + queue_redraw(); } // static diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index 25eb9b9851..2bbe88b0e0 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -137,14 +137,14 @@ void LineBuilder::build() { // The line's outer length will be a little higher due to begin and end caps if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) { if (retrieve_curve) { - total_distance += width * curve->interpolate_baked(0.f) * 0.5f; + total_distance += width * curve->sample_baked(0.f) * 0.5f; } else { total_distance += width * 0.5f; } } if (end_cap_mode == Line2D::LINE_CAP_BOX || end_cap_mode == Line2D::LINE_CAP_ROUND) { if (retrieve_curve) { - total_distance += width * curve->interpolate_baked(1.f) * 0.5f; + total_distance += width * curve->sample_baked(1.f) * 0.5f; } else { total_distance += width * 0.5f; } @@ -160,7 +160,7 @@ void LineBuilder::build() { float uvx1 = 0.f; if (retrieve_curve) { - width_factor = curve->interpolate_baked(0.f); + width_factor = curve->sample_baked(0.f); } pos_up0 += u0 * hw * width_factor; @@ -219,7 +219,7 @@ void LineBuilder::build() { color1 = gradient->get_color_at_offset(current_distance1 / total_distance); } if (retrieve_curve) { - width_factor = curve->interpolate_baked(current_distance1 / total_distance); + width_factor = curve->sample_baked(current_distance1 / total_distance); } Vector2 inner_normal0, inner_normal1; @@ -383,7 +383,7 @@ void LineBuilder::build() { color1 = gradient->get_color(gradient->get_points_count() - 1); } if (retrieve_curve) { - width_factor = curve->interpolate_baked(1.f); + width_factor = curve->sample_baked(1.f); } Vector2 pos_up1 = pos1 + u0 * hw * width_factor; diff --git a/scene/2d/marker_2d.cpp b/scene/2d/marker_2d.cpp index ba1d2ffbfd..d203c58ffd 100644 --- a/scene/2d/marker_2d.cpp +++ b/scene/2d/marker_2d.cpp @@ -86,7 +86,7 @@ bool Marker2D::_edit_use_rect() const { void Marker2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - update(); + queue_redraw(); } break; case NOTIFICATION_DRAW: { @@ -102,7 +102,7 @@ void Marker2D::_notification(int p_what) { void Marker2D::set_gizmo_extents(real_t p_extents) { gizmo_extents = p_extents; - update(); + queue_redraw(); } real_t Marker2D::get_gizmo_extents() const { diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index 178addd62d..56099205d4 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -61,7 +61,7 @@ void MeshInstance2D::_bind_methods() { void MeshInstance2D::set_mesh(const Ref<Mesh> &p_mesh) { mesh = p_mesh; - update(); + queue_redraw(); } Ref<Mesh> MeshInstance2D::get_mesh() const { @@ -73,13 +73,13 @@ void MeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) { return; } texture = p_texture; - update(); + queue_redraw(); emit_signal(SceneStringNames::get_singleton()->texture_changed); } void MeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) { normal_map = p_texture; - update(); + queue_redraw(); } Ref<Texture2D> MeshInstance2D::get_normal_map() const { diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp index 8f72ff1757..68d529fd32 100644 --- a/scene/2d/multimesh_instance_2d.cpp +++ b/scene/2d/multimesh_instance_2d.cpp @@ -61,7 +61,7 @@ void MultiMeshInstance2D::_bind_methods() { void MultiMeshInstance2D::set_multimesh(const Ref<MultiMesh> &p_multimesh) { multimesh = p_multimesh; - update(); + queue_redraw(); } Ref<MultiMesh> MultiMeshInstance2D::get_multimesh() const { @@ -73,7 +73,7 @@ void MultiMeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) { return; } texture = p_texture; - update(); + queue_redraw(); emit_signal(SceneStringNames::get_singleton()->texture_changed); } @@ -83,7 +83,7 @@ Ref<Texture2D> MultiMeshInstance2D::get_texture() const { void MultiMeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) { normal_map = p_texture; - update(); + queue_redraw(); } Ref<Texture2D> MultiMeshInstance2D::get_normal_map() const { diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp new file mode 100644 index 0000000000..8ba51482ee --- /dev/null +++ b/scene/2d/navigation_link_2d.cpp @@ -0,0 +1,288 @@ +/*************************************************************************/ +/* navigation_link_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "navigation_link_2d.h" + +#include "core/math/geometry_2d.h" +#include "scene/resources/world_2d.h" +#include "servers/navigation_server_2d.h" +#include "servers/navigation_server_3d.h" + +void NavigationLink2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink2D::set_enabled); + ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink2D::is_enabled); + + ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink2D::set_bidirectional); + ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink2D::is_bidirectional); + + ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationLink2D::set_navigation_layers); + ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationLink2D::get_navigation_layers); + + ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink2D::set_navigation_layer_value); + ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink2D::get_navigation_layer_value); + + ClassDB::bind_method(D_METHOD("set_start_location", "location"), &NavigationLink2D::set_start_location); + ClassDB::bind_method(D_METHOD("get_start_location"), &NavigationLink2D::get_start_location); + + ClassDB::bind_method(D_METHOD("set_end_location", "location"), &NavigationLink2D::set_end_location); + ClassDB::bind_method(D_METHOD("get_end_location"), &NavigationLink2D::get_end_location); + + ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink2D::set_enter_cost); + ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink2D::get_enter_cost); + + ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationLink2D::set_travel_cost); + ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationLink2D::get_travel_cost); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "start_location"), "set_start_location", "get_start_location"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "end_location"), "set_end_location", "get_end_location"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); +} + +void NavigationLink2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (enabled) { + NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map()); + + // Update global positions for the link. + Transform2D gt = get_global_transform(); + NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); + NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + } + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + // Update global positions for the link. + Transform2D gt = get_global_transform(); + NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); + NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + } break; + case NOTIFICATION_EXIT_TREE: { + NavigationServer2D::get_singleton()->link_set_map(link, RID()); + } break; + case NOTIFICATION_DRAW: { +#ifdef DEBUG_ENABLED + if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled())) { + Color color; + if (enabled) { + color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_color(); + } else { + color = NavigationServer2D::get_singleton()->get_debug_navigation_link_connection_disabled_color(); + } + + real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map()); + + draw_line(get_start_location(), get_end_location(), color); + draw_arc(get_start_location(), radius, 0, Math_TAU, 10, color); + draw_arc(get_end_location(), radius, 0, Math_TAU, 10, color); + } +#endif // DEBUG_ENABLED + } break; + } +} + +#ifdef TOOLS_ENABLED +Rect2 NavigationLink2D::_edit_get_rect() const { + if (!is_inside_tree()) { + return Rect2(); + } + + real_t radius = NavigationServer2D::get_singleton()->map_get_link_connection_radius(get_world_2d()->get_navigation_map()); + + Rect2 rect(get_start_location(), Size2()); + rect.expand_to(get_end_location()); + rect.grow_by(radius); + return rect; +} + +bool NavigationLink2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { + Point2 segment[2] = { get_start_location(), get_end_location() }; + + Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, segment); + return p_point.distance_to(closest_point) < p_tolerance; +} +#endif // TOOLS_ENABLED + +void NavigationLink2D::set_enabled(bool p_enabled) { + if (enabled == p_enabled) { + return; + } + + enabled = p_enabled; + + if (!is_inside_tree()) { + return; + } + + if (!enabled) { + NavigationServer2D::get_singleton()->link_set_map(link, RID()); + } else { + NavigationServer2D::get_singleton()->link_set_map(link, get_world_2d()->get_navigation_map()); + } + +#ifdef DEBUG_ENABLED + if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) { + queue_redraw(); + } +#endif // DEBUG_ENABLED +} + +void NavigationLink2D::set_bidirectional(bool p_bidirectional) { + if (bidirectional == p_bidirectional) { + return; + } + + bidirectional = p_bidirectional; + + NavigationServer2D::get_singleton()->link_set_bidirectional(link, bidirectional); +} + +void NavigationLink2D::set_navigation_layers(uint32_t p_navigation_layers) { + if (navigation_layers == p_navigation_layers) { + return; + } + + navigation_layers = p_navigation_layers; + + NavigationServer2D::get_singleton()->link_set_navigation_layers(link, navigation_layers); +} + +void NavigationLink2D::set_navigation_layer_value(int p_layer_number, bool p_value) { + ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); + + uint32_t _navigation_layers = get_navigation_layers(); + + if (p_value) { + _navigation_layers |= 1 << (p_layer_number - 1); + } else { + _navigation_layers &= ~(1 << (p_layer_number - 1)); + } + + set_navigation_layers(_navigation_layers); +} + +bool NavigationLink2D::get_navigation_layer_value(int p_layer_number) const { + ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); + + return get_navigation_layers() & (1 << (p_layer_number - 1)); +} + +void NavigationLink2D::set_start_location(Vector2 p_location) { + if (start_location.is_equal_approx(p_location)) { + return; + } + + start_location = p_location; + + if (!is_inside_tree()) { + return; + } + + Transform2D gt = get_global_transform(); + NavigationServer2D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); + + update_configuration_warnings(); + +#ifdef DEBUG_ENABLED + if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) { + queue_redraw(); + } +#endif // DEBUG_ENABLED +} + +void NavigationLink2D::set_end_location(Vector2 p_location) { + if (end_location.is_equal_approx(p_location)) { + return; + } + + end_location = p_location; + + if (!is_inside_tree()) { + return; + } + + Transform2D gt = get_global_transform(); + NavigationServer2D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + + update_configuration_warnings(); + +#ifdef DEBUG_ENABLED + if (Engine::get_singleton()->is_editor_hint() || NavigationServer2D::get_singleton()->get_debug_enabled()) { + queue_redraw(); + } +#endif // DEBUG_ENABLED +} + +void NavigationLink2D::set_enter_cost(real_t p_enter_cost) { + ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); + if (Math::is_equal_approx(enter_cost, p_enter_cost)) { + return; + } + + enter_cost = p_enter_cost; + + NavigationServer2D::get_singleton()->link_set_enter_cost(link, enter_cost); +} + +void NavigationLink2D::set_travel_cost(real_t p_travel_cost) { + ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); + if (Math::is_equal_approx(travel_cost, p_travel_cost)) { + return; + } + + travel_cost = p_travel_cost; + + NavigationServer2D::get_singleton()->link_set_travel_cost(link, travel_cost); +} + +TypedArray<String> NavigationLink2D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + + if (start_location.is_equal_approx(end_location)) { + warnings.push_back(RTR("NavigationLink2D start location should be different than the end location to be useful.")); + } + + return warnings; +} + +NavigationLink2D::NavigationLink2D() { + link = NavigationServer2D::get_singleton()->link_create(); + set_notify_transform(true); +} + +NavigationLink2D::~NavigationLink2D() { + NavigationServer2D::get_singleton()->free(link); + link = RID(); +} diff --git a/scene/resources/camera_effects.h b/scene/2d/navigation_link_2d.h index 7353931d16..5990ea082c 100644 --- a/scene/resources/camera_effects.h +++ b/scene/2d/navigation_link_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* camera_effects.h */ +/* navigation_link_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,68 +28,61 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CAMERA_EFFECTS_H -#define CAMERA_EFFECTS_H +#ifndef NAVIGATION_LINK_2D_H +#define NAVIGATION_LINK_2D_H -#include "core/io/resource.h" -#include "core/templates/rid.h" +#include "scene/2d/node_2d.h" -class CameraEffects : public Resource { - GDCLASS(CameraEffects, Resource); +class NavigationLink2D : public Node2D { + GDCLASS(NavigationLink2D, Node2D); -private: - RID camera_effects; + bool enabled = true; + RID link = RID(); + bool bidirectional = true; + uint32_t navigation_layers = 1; + Vector2 end_location = Vector2(); + Vector2 start_location = Vector2(); + real_t enter_cost = 0.0; + real_t travel_cost = 1.0; - // DOF blur - bool dof_blur_far_enabled = false; - float dof_blur_far_distance = 10.0; - float dof_blur_far_transition = 5.0; +protected: + static void _bind_methods(); + void _notification(int p_what); - bool dof_blur_near_enabled = false; - float dof_blur_near_distance = 2.0; - float dof_blur_near_transition = 1.0; +public: +#ifdef TOOLS_ENABLED + virtual Rect2 _edit_get_rect() const override; + virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const override; +#endif - float dof_blur_amount = 0.1; - void _update_dof_blur(); + void set_enabled(bool p_enabled); + bool is_enabled() const { return enabled; } - // Override exposure - bool override_exposure_enabled = false; - float override_exposure = 1.0; - void _update_override_exposure(); + void set_bidirectional(bool p_bidirectional); + bool is_bidirectional() const { return bidirectional; } -protected: - static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const; + void set_navigation_layers(uint32_t p_navigation_layers); + uint32_t get_navigation_layers() const { return navigation_layers; } -public: - virtual RID get_rid() const override; - - // DOF blur - void set_dof_blur_far_enabled(bool p_enabled); - bool is_dof_blur_far_enabled() const; - void set_dof_blur_far_distance(float p_distance); - float get_dof_blur_far_distance() const; - void set_dof_blur_far_transition(float p_distance); - float get_dof_blur_far_transition() const; - - void set_dof_blur_near_enabled(bool p_enabled); - bool is_dof_blur_near_enabled() const; - void set_dof_blur_near_distance(float p_distance); - float get_dof_blur_near_distance() const; - void set_dof_blur_near_transition(float p_distance); - float get_dof_blur_near_transition() const; - - void set_dof_blur_amount(float p_amount); - float get_dof_blur_amount() const; - - // Override exposure - void set_override_exposure_enabled(bool p_enabled); - bool is_override_exposure_enabled() const; - void set_override_exposure(float p_exposure); - float get_override_exposure() const; - - CameraEffects(); - ~CameraEffects(); + void set_navigation_layer_value(int p_layer_number, bool p_value); + bool get_navigation_layer_value(int p_layer_number) const; + + void set_start_location(Vector2 p_location); + Vector2 get_start_location() const { return start_location; } + + void set_end_location(Vector2 p_location); + Vector2 get_end_location() const { return end_location; } + + void set_enter_cost(real_t p_enter_cost); + real_t get_enter_cost() const { return enter_cost; } + + void set_travel_cost(real_t p_travel_cost); + real_t get_travel_cost() const { return travel_cost; } + + TypedArray<String> get_configuration_warnings() const override; + + NavigationLink2D(); + ~NavigationLink2D(); }; -#endif // CAMERA_EFFECTS_H +#endif // NAVIGATION_LINK_2D_H diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index a592d20cba..1850e00ecd 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -38,6 +38,9 @@ void NavigationObstacle2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle2D::get_rid); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle2D::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle2D::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle2D::set_estimate_radius); ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle2D::is_radius_estimated); ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle2D::set_radius); @@ -57,28 +60,26 @@ void NavigationObstacle2D::_validate_property(PropertyInfo &p_property) const { void NavigationObstacle2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - parent_node2d = Object::cast_to<Node2D>(get_parent()); - reevaluate_agent_radius(); - if (parent_node2d != nullptr) { - // place agent on navigation map first or else the RVO agent callback creation fails silently later - NavigationServer2D::get_singleton()->agent_set_map(get_rid(), parent_node2d->get_world_2d()->get_navigation_map()); - } + case NOTIFICATION_POST_ENTER_TREE: { + set_agent_parent(get_parent()); set_physics_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { - parent_node2d = nullptr; + set_agent_parent(nullptr); set_physics_process_internal(false); } break; case NOTIFICATION_PARENTED: { - parent_node2d = Object::cast_to<Node2D>(get_parent()); - reevaluate_agent_radius(); + if (is_inside_tree() && (get_parent() != parent_node2d)) { + set_agent_parent(get_parent()); + set_physics_process_internal(true); + } } break; case NOTIFICATION_UNPARENTED: { - parent_node2d = nullptr; + set_agent_parent(nullptr); + set_physics_process_internal(false); } break; case NOTIFICATION_PAUSED: { @@ -182,6 +183,35 @@ real_t NavigationObstacle2D::estimate_agent_radius() const { return 1.0; // Never a 0 radius } +void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) { + if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) { + parent_node2d = Object::cast_to<Node2D>(p_agent_parent); + if (map_override.is_valid()) { + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_override); + } else { + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), parent_node2d->get_world_2d()->get_navigation_map()); + } + reevaluate_agent_radius(); + } else { + parent_node2d = nullptr; + NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID()); + } +} + +void NavigationObstacle2D::set_navigation_map(RID p_navigation_map) { + map_override = p_navigation_map; + NavigationServer2D::get_singleton()->agent_set_map(agent, map_override); +} + +RID NavigationObstacle2D::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (parent_node2d != nullptr) { + return parent_node2d->get_world_2d()->get_navigation_map(); + } + return RID(); +} + void NavigationObstacle2D::set_estimate_radius(bool p_estimate_radius) { estimate_radius = p_estimate_radius; notify_property_list_changed(); diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index 5795c6c94f..6eff95adec 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -38,8 +38,10 @@ class NavigationObstacle2D : public Node { GDCLASS(NavigationObstacle2D, Node); Node2D *parent_node2d = nullptr; + RID agent; RID map_before_pause; + RID map_override; bool estimate_radius = true; real_t radius = 1.0; @@ -57,6 +59,11 @@ public: return agent; } + void set_agent_parent(Node *p_agent_parent); + + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_estimate_radius(bool p_estimate_radius); bool is_radius_estimated() const { return estimate_radius; diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 00aa4b0b59..ffccb95a22 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -374,7 +374,7 @@ void NavigationRegion2D::set_enabled(bool p_enabled) { #ifdef DEBUG_ENABLED if (Engine::get_singleton()->is_editor_hint() || NavigationServer3D::get_singleton()->get_debug_enabled()) { - update(); + queue_redraw(); } #endif // DEBUG_ENABLED } @@ -551,7 +551,7 @@ Ref<NavigationPolygon> NavigationRegion2D::get_navigation_polygon() const { void NavigationRegion2D::_navpoly_changed() { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) { - update(); + queue_redraw(); } if (navpoly.is_valid()) { NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); @@ -561,7 +561,7 @@ void NavigationRegion2D::_navpoly_changed() { void NavigationRegion2D::_map_changed(RID p_map) { #ifdef DEBUG_ENABLED if (is_inside_tree() && get_world_2d()->get_navigation_map() == p_map) { - update(); + queue_redraw(); } #endif // DEBUG_ENABLED } diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 4599785ce4..7765533016 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -437,8 +437,8 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,no_slider,suffix:px"), "set_position", "get_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, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_less,or_greater,no_slider,suffix:px"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_NONE), "set_transform", "get_transform"); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index bbc326a4b4..90b2e3d460 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -47,7 +47,7 @@ Rect2 Path2D::_edit_get_rect() const { for (int i = 0; i < curve->get_point_count(); i++) { for (int j = 0; j <= 8; j++) { real_t frac = j / 8.0; - Vector2 p = curve->interpolate(i, frac); + Vector2 p = curve->sample(i, frac); aabb.expand_to(p); } } @@ -70,7 +70,7 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc for (int j = 1; j <= 8; j++) { real_t frac = j / 8.0; - s[1] = curve->interpolate(i, frac); + s[1] = curve->sample(i, frac); Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, s); if (p.distance_to(p_point) <= p_tolerance) { @@ -112,7 +112,7 @@ void Path2D::_notification(int p_what) { 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); + Vector2 p = curve->sample(i, frac); _cached_draw_pts.set(count++, p); } } @@ -131,7 +131,7 @@ void Path2D::_curve_changed() { return; } - update(); + queue_redraw(); } void Path2D::set_curve(const Ref<Curve2D> &p_curve) { @@ -175,7 +175,7 @@ void PathFollow2D::_update_transform() { if (path_length == 0) { return; } - Vector2 pos = c->interpolate_baked(progress, cubic); + Vector2 pos = c->sample_baked(progress, cubic); if (rotates) { real_t ahead = progress + lookahead; @@ -195,14 +195,14 @@ void PathFollow2D::_update_transform() { } } - Vector2 ahead_pos = c->interpolate_baked(ahead, cubic); + Vector2 ahead_pos = c->sample_baked(ahead, cubic); Vector2 tangent_to_curve; if (ahead_pos == pos) { // This will happen at the end of non-looping or non-closed paths. // We'll try a look behind instead, in order to get a meaningful angle. tangent_to_curve = - (pos - c->interpolate_baked(progress - lookahead, cubic)).normalized(); + (pos - c->sample_baked(progress - lookahead, cubic)).normalized(); } else { tangent_to_curve = (ahead_pos - pos).normalized(); } @@ -252,7 +252,7 @@ void PathFollow2D::_validate_property(PropertyInfo &p_property) const { max = path->get_curve()->get_baked_length(); } - p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; + p_property.hint_string = "0," + rtos(max) + ",0.01,or_less,or_greater"; } } @@ -293,8 +293,8 @@ void PathFollow2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead); ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_progress", "get_progress"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_less,or_greater,suffix:px"), "set_progress", "get_progress"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating"); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 43158344b4..714d196779 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1024,7 +1024,7 @@ void RigidBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5px\u00B2"), "set_inertia", "get_inertia"); ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:px"), "set_center_of_mass", "get_center_of_mass"); ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); @@ -1142,7 +1142,7 @@ bool CharacterBody2D::move_and_slide() { on_ceiling = false; on_wall = false; - if (!current_platform_velocity.is_equal_approx(Vector2())) { + if (!current_platform_velocity.is_zero_approx()) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. parameters.exclude_bodies.insert(platform_rid); @@ -1241,7 +1241,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo break; } - if (result.remainder.is_equal_approx(Vector2())) { + if (result.remainder.is_zero_approx()) { motion = Vector2(); break; } @@ -1325,7 +1325,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo sliding_enabled = true; first_slide = false; - if (!collided || motion.is_equal_approx(Vector2())) { + if (!collided || motion.is_zero_approx()) { break; } } @@ -1371,7 +1371,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) { motion_results.push_back(result); _set_collision_direction(result); - if (result.remainder.is_equal_approx(Vector2())) { + if (result.remainder.is_zero_approx()) { motion = Vector2(); break; } @@ -1390,7 +1390,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) { } } - if (!collided || motion.is_equal_approx(Vector2())) { + if (!collided || motion.is_zero_approx()) { break; } diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 8161fb5bd9..5e77902977 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -97,7 +97,7 @@ void Polygon2D::_validate_property(PropertyInfo &p_property) const { } void Polygon2D::_skeleton_bone_setup_changed() { - update(); + queue_redraw(); } void Polygon2D::_notification(int p_what) { @@ -375,7 +375,7 @@ void Polygon2D::_notification(int p_what) { void Polygon2D::set_polygon(const Vector<Vector2> &p_polygon) { polygon = p_polygon; rect_cache_dirty = true; - update(); + queue_redraw(); } Vector<Vector2> Polygon2D::get_polygon() const { @@ -392,7 +392,7 @@ int Polygon2D::get_internal_vertex_count() const { void Polygon2D::set_uv(const Vector<Vector2> &p_uv) { uv = p_uv; - update(); + queue_redraw(); } Vector<Vector2> Polygon2D::get_uv() const { @@ -401,7 +401,7 @@ Vector<Vector2> Polygon2D::get_uv() const { void Polygon2D::set_polygons(const Array &p_polygons) { polygons = p_polygons; - update(); + queue_redraw(); } Array Polygon2D::get_polygons() const { @@ -410,7 +410,7 @@ Array Polygon2D::get_polygons() const { void Polygon2D::set_color(const Color &p_color) { color = p_color; - update(); + queue_redraw(); } Color Polygon2D::get_color() const { @@ -419,7 +419,7 @@ Color Polygon2D::get_color() const { void Polygon2D::set_vertex_colors(const Vector<Color> &p_colors) { vertex_colors = p_colors; - update(); + queue_redraw(); } Vector<Color> Polygon2D::get_vertex_colors() const { @@ -428,7 +428,7 @@ Vector<Color> Polygon2D::get_vertex_colors() const { void Polygon2D::set_texture(const Ref<Texture2D> &p_texture) { texture = p_texture; - update(); + queue_redraw(); } Ref<Texture2D> Polygon2D::get_texture() const { @@ -437,7 +437,7 @@ Ref<Texture2D> Polygon2D::get_texture() const { void Polygon2D::set_texture_offset(const Vector2 &p_offset) { tex_ofs = p_offset; - update(); + queue_redraw(); } Vector2 Polygon2D::get_texture_offset() const { @@ -446,7 +446,7 @@ Vector2 Polygon2D::get_texture_offset() const { void Polygon2D::set_texture_rotation(real_t p_rot) { tex_rot = p_rot; - update(); + queue_redraw(); } real_t Polygon2D::get_texture_rotation() const { @@ -455,7 +455,7 @@ real_t Polygon2D::get_texture_rotation() const { void Polygon2D::set_texture_scale(const Size2 &p_scale) { tex_scale = p_scale; - update(); + queue_redraw(); } Size2 Polygon2D::get_texture_scale() const { @@ -464,7 +464,7 @@ Size2 Polygon2D::get_texture_scale() const { void Polygon2D::set_invert(bool p_invert) { invert = p_invert; - update(); + queue_redraw(); notify_property_list_changed(); } @@ -474,7 +474,7 @@ bool Polygon2D::get_invert() const { void Polygon2D::set_antialiased(bool p_antialiased) { antialiased = p_antialiased; - update(); + queue_redraw(); } bool Polygon2D::get_antialiased() const { @@ -483,7 +483,7 @@ bool Polygon2D::get_antialiased() const { void Polygon2D::set_invert_border(real_t p_invert_border) { invert_border = p_invert_border; - update(); + queue_redraw(); } real_t Polygon2D::get_invert_border() const { @@ -493,7 +493,7 @@ real_t Polygon2D::get_invert_border() const { void Polygon2D::set_offset(const Vector2 &p_offset) { offset = p_offset; rect_cache_dirty = true; - update(); + queue_redraw(); } Vector2 Polygon2D::get_offset() const { @@ -533,13 +533,13 @@ void Polygon2D::clear_bones() { void Polygon2D::set_bone_weights(int p_index, const Vector<float> &p_weights) { ERR_FAIL_INDEX(p_index, bone_weights.size()); bone_weights.write[p_index].weights = p_weights; - update(); + queue_redraw(); } void Polygon2D::set_bone_path(int p_index, const NodePath &p_path) { ERR_FAIL_INDEX(p_index, bone_weights.size()); bone_weights.write[p_index].path = p_path; - update(); + queue_redraw(); } Array Polygon2D::_get_bones() const { @@ -567,7 +567,7 @@ void Polygon2D::set_skeleton(const NodePath &p_skeleton) { return; } skeleton = p_skeleton; - update(); + queue_redraw(); } NodePath Polygon2D::get_skeleton() const { @@ -640,7 +640,7 @@ void Polygon2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_texture_offset", "get_texture_offset"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale", PROPERTY_HINT_LINK), "set_texture_scale", "get_texture_scale"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_texture_rotation", "get_texture_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_texture_rotation", "get_texture_rotation"); ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index c4036faa79..2c8a2e715a 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -36,7 +36,7 @@ void RayCast2D::set_target_position(const Vector2 &p_point) { target_position = p_point; if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) { - update(); + queue_redraw(); } } @@ -100,7 +100,7 @@ Vector2 RayCast2D::get_collision_normal() const { void RayCast2D::set_enabled(bool p_enabled) { enabled = p_enabled; - update(); + queue_redraw(); if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) { set_physics_process_internal(p_enabled); } @@ -219,7 +219,7 @@ void RayCast2D::_update_raycast_state() { } if (prev_collision_state != collided) { - update(); + queue_redraw(); } } diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp index 316988d298..a25d5934ee 100644 --- a/scene/2d/shape_cast_2d.cpp +++ b/scene/2d/shape_cast_2d.cpp @@ -40,7 +40,7 @@ void ShapeCast2D::set_target_position(const Vector2 &p_point) { target_position = p_point; if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) { - update(); + queue_redraw(); } } @@ -132,7 +132,7 @@ real_t ShapeCast2D::get_closest_collision_unsafe_fraction() const { void ShapeCast2D::set_enabled(bool p_enabled) { enabled = p_enabled; - update(); + queue_redraw(); if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint()) { set_physics_process_internal(p_enabled); } @@ -152,7 +152,7 @@ void ShapeCast2D::set_shape(const Ref<Shape2D> &p_shape) { shape_rid = shape->get_rid(); } update_configuration_warnings(); - update(); + queue_redraw(); } Ref<Shape2D> ShapeCast2D::get_shape() const { @@ -182,7 +182,7 @@ bool ShapeCast2D::get_exclude_parent_body() const { } void ShapeCast2D::_redraw_shape() { - update(); + queue_redraw(); } void ShapeCast2D::_notification(int p_what) { @@ -325,7 +325,7 @@ void ShapeCast2D::_update_shapecast_state() { collided = !result.is_empty(); if (prev_collision_state != collided) { - update(); + queue_redraw(); } } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 13a32fbfd4..8f0bf22617 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -126,7 +126,7 @@ void Bone2D::_notification(int p_what) { return; } - update(); + queue_redraw(); #endif // TOOLS_ENABLED } break; @@ -143,12 +143,12 @@ void Bone2D::_notification(int p_what) { return; } - update(); + queue_redraw(); if (get_parent()) { Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent()); if (parent_bone) { - parent_bone->update(); + parent_bone->queue_redraw(); } } #endif // TOOLS_ENABLED @@ -365,7 +365,7 @@ bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p void Bone2D::_editor_set_show_bone_gizmo(bool p_show_gizmo) { _editor_show_bone_gizmo = p_show_gizmo; - update(); + queue_redraw(); } bool Bone2D::_editor_get_show_bone_gizmo() const { @@ -493,7 +493,7 @@ void Bone2D::set_length(real_t p_length) { length = p_length; #ifdef TOOLS_ENABLED - update(); + queue_redraw(); #endif // TOOLS_ENABLED } @@ -505,7 +505,7 @@ void Bone2D::set_bone_angle(real_t p_angle) { bone_angle = p_angle; #ifdef TOOLS_ENABLED - update(); + queue_redraw(); #endif // TOOLS_ENABLED } diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index e1983f9cb9..0ecf8333a0 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -146,7 +146,7 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) { texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite2D::_texture_changed)); } - update(); + queue_redraw(); emit_signal(SceneStringNames::get_singleton()->texture_changed); item_rect_changed(); } @@ -157,7 +157,7 @@ Ref<Texture2D> Sprite2D::get_texture() const { void Sprite2D::set_centered(bool p_center) { centered = p_center; - update(); + queue_redraw(); item_rect_changed(); } @@ -167,7 +167,7 @@ bool Sprite2D::is_centered() const { void Sprite2D::set_offset(const Point2 &p_offset) { offset = p_offset; - update(); + queue_redraw(); item_rect_changed(); } @@ -177,7 +177,7 @@ Point2 Sprite2D::get_offset() const { void Sprite2D::set_flip_h(bool p_flip) { hflip = p_flip; - update(); + queue_redraw(); } bool Sprite2D::is_flipped_h() const { @@ -186,7 +186,7 @@ bool Sprite2D::is_flipped_h() const { void Sprite2D::set_flip_v(bool p_flip) { vflip = p_flip; - update(); + queue_redraw(); } bool Sprite2D::is_flipped_v() const { @@ -199,7 +199,7 @@ void Sprite2D::set_region_enabled(bool p_region_enabled) { } region_enabled = p_region_enabled; - update(); + queue_redraw(); notify_property_list_changed(); } @@ -225,7 +225,7 @@ Rect2 Sprite2D::get_region_rect() const { void Sprite2D::set_region_filter_clip_enabled(bool p_region_filter_clip_enabled) { region_filter_clip_enabled = p_region_filter_clip_enabled; - update(); + queue_redraw(); } bool Sprite2D::is_region_filter_clip_enabled() const { @@ -262,7 +262,7 @@ Vector2i Sprite2D::get_frame_coords() const { void Sprite2D::set_vframes(int p_amount) { ERR_FAIL_COND_MSG(p_amount < 1, "Amount of vframes cannot be smaller than 1."); vframes = p_amount; - update(); + queue_redraw(); item_rect_changed(); notify_property_list_changed(); } @@ -274,7 +274,7 @@ int Sprite2D::get_vframes() const { void Sprite2D::set_hframes(int p_amount) { ERR_FAIL_COND_MSG(p_amount < 1, "Amount of hframes cannot be smaller than 1."); hframes = p_amount; - update(); + queue_redraw(); item_rect_changed(); notify_property_list_changed(); } @@ -388,7 +388,7 @@ void Sprite2D::_texture_changed() { // Changes to the texture need to trigger an update to make // the editor redraw the sprite with the updated texture. if (texture.is_valid()) { - update(); + queue_redraw(); } } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 129cce93fa..5de6d547d7 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -34,6 +34,10 @@ #include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" +#ifdef DEBUG_ENABLED +#include "servers/navigation_server_3d.h" +#endif // DEBUG_ENABLED + HashMap<Vector2i, TileSet::CellNeighbor> TileMap::TerrainConstraint::get_overlapping_coords_and_peering_bits() const { HashMap<Vector2i, TileSet::CellNeighbor> output; @@ -828,13 +832,13 @@ void TileMap::_update_dirty_quadrants() { // Update the coords cache. for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) { - q->self()->map_to_world.clear(); - q->self()->world_to_map.clear(); + q->self()->map_to_local.clear(); + q->self()->local_to_map.clear(); for (const Vector2i &E : q->self()->cells) { Vector2i pk = E; - Vector2i pk_world_coords = map_to_world(pk); - q->self()->map_to_world[pk] = pk_world_coords; - q->self()->world_to_map[pk_world_coords] = pk; + Vector2i pk_local_coords = map_to_local(pk); + q->self()->map_to_local[pk] = pk_local_coords; + q->self()->local_to_map[pk_local_coords] = pk; } } @@ -852,7 +856,7 @@ void TileMap::_update_dirty_quadrants() { for (SelfList<TileMapQuadrant> *q = dirty_quadrant_list.first(); q; q = q->next()) { rs->canvas_item_clear(q->self()->debug_canvas_item); Transform2D xform; - xform.set_origin(map_to_world(q->self()->coords * get_effective_quadrant_size(layer))); + xform.set_origin(map_to_local(q->self()->coords * get_effective_quadrant_size(layer))); rs->canvas_item_set_transform(q->self()->debug_canvas_item, xform); _rendering_draw_quadrant_debug(q->self()); @@ -978,10 +982,10 @@ void TileMap::_recompute_rect_cache() { for (unsigned int layer = 0; layer < layers.size(); layer++) { for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) { Rect2 r; - r.position = map_to_world(E.key * get_effective_quadrant_size(layer)); - r.expand_to(map_to_world((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer))); - r.expand_to(map_to_world((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer))); - r.expand_to(map_to_world((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer))); + r.position = map_to_local(E.key * get_effective_quadrant_size(layer)); + r.expand_to(map_to_local((E.key + Vector2i(1, 0)) * get_effective_quadrant_size(layer))); + r.expand_to(map_to_local((E.key + Vector2i(1, 1)) * get_effective_quadrant_size(layer))); + r.expand_to(map_to_local((E.key + Vector2i(0, 1)) * get_effective_quadrant_size(layer))); if (first) { r_total = r; first = false; @@ -1010,7 +1014,7 @@ void TileMap::_rendering_notification(int p_what) { TileMapQuadrant &q = E_quadrant.value; // Update occluders transform. - for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) { + for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) { Transform2D xform; xform.set_origin(E_cell.key); for (const RID &occluder : q.occluders) { @@ -1030,7 +1034,7 @@ void TileMap::_rendering_notification(int p_what) { TileMapQuadrant &q = E_quadrant.value; // Update occluders transform. - for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) { + for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) { Transform2D xform; xform.set_origin(E_cell.key); for (const RID &occluder : q.occluders) { @@ -1126,7 +1130,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List } // Iterate over the cells of the quadrant. - for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) { + for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) { TileMapCell c = get_cell(q.layer, E_cell.value, true); TileSetSource *source; @@ -1151,7 +1155,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List int z_index = tile_data->get_z_index(); // Quandrant pos. - Vector2 position = map_to_world(q.coords * get_effective_quadrant_size(q.layer)); + Vector2 position = map_to_local(q.coords * get_effective_quadrant_size(q.layer)); if (is_y_sort_enabled() && layers[q.layer].y_sort_enabled) { // When Y-sorting, the quandrant size is sure to be 1, we can thus offset the CanvasItem. position.y += layers[q.layer].y_sort_origin + tile_data->get_y_sort_origin(); @@ -1223,14 +1227,14 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List int index = -(int64_t)0x80000000; //always must be drawn below children. for (int layer = 0; layer < (int)layers.size(); layer++) { - // Sort the quadrants coords per world coordinates - RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> world_to_map; + // Sort the quadrants coords per local coordinates. + RBMap<Vector2i, Vector2i, TileMapQuadrant::CoordsWorldComparator> local_to_map; for (const KeyValue<Vector2i, TileMapQuadrant> &E : layers[layer].quadrant_map) { - world_to_map[map_to_world(E.key)] = E.key; + local_to_map[map_to_local(E.key)] = E.key; } - // Sort the quadrants - for (const KeyValue<Vector2i, Vector2i> &E : world_to_map) { + // Sort the quadrants. + for (const KeyValue<Vector2i, Vector2i> &E : local_to_map) { TileMapQuadrant &q = layers[layer].quadrant_map[E.value]; for (const RID &ci : q.canvas_items) { RS::get_singleton()->canvas_item_set_draw_index(ci, index++); @@ -1270,7 +1274,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { // Draw a placeholder for scenes needing one. RenderingServer *rs = RenderingServer::get_singleton(); - Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); + Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); for (const Vector2i &E_cell : p_quadrant->cells) { const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true); @@ -1302,7 +1306,7 @@ void TileMap::_rendering_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { // Draw a placeholder tile. Transform2D xform; - xform.set_origin(map_to_world(E_cell) - quadrant_pos); + xform.set_origin(map_to_local(E_cell) - quadrant_pos); rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform); rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); } @@ -1423,7 +1427,7 @@ void TileMap::_physics_notification(int p_what) { for (RID body : q.bodies) { Transform2D xform; - xform.set_origin(map_to_world(bodies_coords[body])); + xform.set_origin(map_to_local(bodies_coords[body])); xform = global_transform * xform; PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); } @@ -1446,7 +1450,7 @@ void TileMap::_physics_notification(int p_what) { for (RID body : q.bodies) { Transform2D xform; - xform.set_origin(map_to_world(bodies_coords[body])); + xform.set_origin(map_to_local(bodies_coords[body])); xform = new_transform * xform; PhysicsServer2D::get_singleton()->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); @@ -1516,7 +1520,7 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r ps->body_set_space(body, space); Transform2D xform; - xform.set_origin(map_to_world(E_cell)); + xform.set_origin(map_to_local(E_cell)); xform = global_transform * xform; ps->body_set_state(body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); @@ -1602,7 +1606,7 @@ void TileMap::_physics_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { Vector<Color> color; color.push_back(debug_collision_color); - Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); + Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); Transform2D qudrant_xform; qudrant_xform.set_origin(quadrant_pos); Transform2D global_transform_inv = (get_global_transform() * qudrant_xform).affine_inverse(); @@ -1641,7 +1645,7 @@ void TileMap::_navigation_notification(int p_what) { continue; } Transform2D tile_transform; - tile_transform.set_origin(map_to_world(E_region.key)); + tile_transform.set_origin(map_to_local(E_region.key)); NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform); } } @@ -1656,14 +1660,6 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND(!tile_set.is_valid()); - // Get colors for debug. - SceneTree *st = SceneTree::get_singleton(); - Color debug_navigation_color; - bool debug_navigation = st && st->is_debugging_navigation_hint(); - if (debug_navigation) { - debug_navigation_color = st->get_debug_navigation_color(); - } - Transform2D tilemap_xform = get_global_transform(); SelfList<TileMapQuadrant> *q_list_element = r_dirty_quadrant_list.first(); while (q_list_element) { @@ -1709,7 +1705,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List if (navpoly.is_valid()) { Transform2D tile_transform; - tile_transform.set_origin(map_to_world(E_cell)); + tile_transform.set_origin(map_to_local(E_cell)); RID region = NavigationServer2D::get_singleton()->region_create(); NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); @@ -1766,10 +1762,13 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { RenderingServer *rs = RenderingServer::get_singleton(); - Color color = get_tree()->get_debug_navigation_color(); + Color color = Color(0.5, 1.0, 1.0, 1.0); +#ifdef DEBUG_ENABLED + color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(); +#endif // DEBUG_ENABLED RandomPCG rand; - Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); + Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); for (const Vector2i &E_cell : p_quadrant->cells) { TileMapCell c = get_cell(p_quadrant->layer, E_cell, true); @@ -1792,7 +1791,7 @@ void TileMap::_navigation_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { } Transform2D xform; - xform.set_origin(map_to_world(E_cell) - quadrant_pos); + xform.set_origin(map_to_local(E_cell) - quadrant_pos); rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform); for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) { @@ -1866,10 +1865,10 @@ void TileMap::_scenes_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r_ Control *scene_as_control = Object::cast_to<Control>(scene); Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene); if (scene_as_control) { - scene_as_control->set_position(map_to_world(E_cell) + scene_as_control->get_position()); + scene_as_control->set_position(map_to_local(E_cell) + scene_as_control->get_position()); } else if (scene_as_node2d) { Transform2D xform; - xform.set_origin(map_to_world(E_cell)); + xform.set_origin(map_to_local(E_cell)); scene_as_node2d->set_transform(xform * scene_as_node2d->get_transform()); } q.scenes[E_cell] = scene->get_name(); @@ -1903,7 +1902,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { // Draw a placeholder for scenes needing one. RenderingServer *rs = RenderingServer::get_singleton(); - Vector2 quadrant_pos = map_to_world(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); + Vector2 quadrant_pos = map_to_local(p_quadrant->coords * get_effective_quadrant_size(p_quadrant->layer)); for (const Vector2i &E_cell : p_quadrant->cells) { const TileMapCell &c = get_cell(p_quadrant->layer, E_cell, true); @@ -1933,7 +1932,7 @@ void TileMap::_scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant) { // Draw a placeholder tile. Transform2D xform; - xform.set_origin(map_to_world(E_cell) - quadrant_pos); + xform.set_origin(map_to_local(E_cell) - quadrant_pos); rs->canvas_item_add_set_transform(p_quadrant->debug_canvas_item, xform); rs->canvas_item_add_circle(p_quadrant->debug_canvas_item, Vector2(), MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 4.0, color); } @@ -2822,7 +2821,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r while (q_list_element) { TileMapQuadrant &q = *q_list_element->self(); // Iterate over the cells of the quadrant. - for (const KeyValue<Vector2i, Vector2i> &E_cell : q.world_to_map) { + for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) { TileMapCell c = get_cell(q.layer, E_cell.value, true); TileSetSource *source; @@ -2981,7 +2980,7 @@ void TileMap::_get_property_list(List<PropertyInfo> *p_list) const { } } -Vector2 TileMap::map_to_world(const Vector2i &p_pos) const { +Vector2 TileMap::map_to_local(const Vector2i &p_pos) const { // SHOULD RETURN THE CENTER OF THE CELL ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2()); @@ -3058,10 +3057,10 @@ Vector2 TileMap::map_to_world(const Vector2i &p_pos) const { return (ret + Vector2(0.5, 0.5)) * tile_set->get_tile_size(); } -Vector2i TileMap::world_to_map(const Vector2 &p_pos) const { +Vector2i TileMap::local_to_map(const Vector2 &p_local_position) const { ERR_FAIL_COND_V(!tile_set.is_valid(), Vector2i()); - Vector2 ret = p_pos; + Vector2 ret = p_local_position; ret /= tile_set->get_tile_size(); TileSet::TileShape tile_shape = tile_set->get_tile_shape(); @@ -3086,7 +3085,7 @@ Vector2i TileMap::world_to_map(const Vector2 &p_pos) const { ret.x /= overlapping_ratio; } - // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the world position accordingly. + // For each half-offset shape, we check if we are in the corner of the tile, and thus should correct the local position accordingly. if (tile_shape == TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE || tile_shape == TileSet::TILE_SHAPE_HEXAGON || tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { // Technically, those 3 shapes are equivalent, as they are basically half-offset, but with different levels or overlap. // square = no overlap, hexagon = 0.25 overlap, isometric = 0.5 overlap @@ -3771,7 +3770,7 @@ void TileMap::draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Co TileSet::TileShape shape = tile_set->get_tile_shape(); for (const Vector2i &E : p_cells) { - Vector2 center = map_to_world(E); + Vector2 center = map_to_local(E); #define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \ if (!p_cells.has(get_neighbor_cell(E, side))) { \ @@ -3901,8 +3900,8 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells); ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect); - ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &TileMap::map_to_world); - ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &TileMap::world_to_map); + ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMap::map_to_local); + ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &TileMap::local_to_map); ClassDB::bind_method(D_METHOD("get_neighbor_cell", "coords", "neighbor"), &TileMap::get_neighbor_cell); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index ecc6ee1d59..a819eeab71 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -40,7 +40,7 @@ class TileSetAtlasSource; struct TileMapQuadrant { struct CoordsWorldComparator { _ALWAYS_INLINE_ bool operator()(const Vector2i &p_a, const Vector2i &p_b) const { - // We sort the cells by their world coords, as it is needed by rendering. + // We sort the cells by their local coords, as it is needed by rendering. if (p_a.y == p_b.y) { return p_a.x > p_b.x; } else { @@ -49,7 +49,7 @@ struct TileMapQuadrant { } }; - // Dirty list element + // Dirty list element. SelfList<TileMapQuadrant> dirty_list_element; // Quadrant layer and coords. @@ -58,10 +58,10 @@ struct TileMapQuadrant { // TileMapCells RBSet<Vector2i> cells; - // We need those two maps to sort by world position for rendering + // We need those two maps to sort by local position for rendering // This is kind of workaround, it would be better to sort the cells directly in the "cells" set instead. - RBMap<Vector2i, Vector2i> map_to_world; - RBMap<Vector2i, Vector2i, CoordsWorldComparator> world_to_map; + RBMap<Vector2i, Vector2i> map_to_local; + RBMap<Vector2i, Vector2i, CoordsWorldComparator> local_to_map; // Debug. RID debug_canvas_item; @@ -368,8 +368,8 @@ public: virtual void set_y_sort_enabled(bool p_enable) override; - Vector2 map_to_world(const Vector2i &p_pos) const; - Vector2i world_to_map(const Vector2 &p_pos) const; + Vector2 map_to_local(const Vector2i &p_pos) const; + Vector2i local_to_map(const Vector2 &p_pos) const; bool is_existing_neighbor(TileSet::CellNeighbor p_cell_neighbor) const; Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const; diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index 9dea69cd64..a02f322ef1 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -34,7 +34,7 @@ void TouchScreenButton::set_texture_normal(const Ref<Texture2D> &p_texture) { texture_normal = p_texture; - update(); + queue_redraw(); } Ref<Texture2D> TouchScreenButton::get_texture_normal() const { @@ -43,7 +43,7 @@ Ref<Texture2D> TouchScreenButton::get_texture_normal() const { void TouchScreenButton::set_texture_pressed(const Ref<Texture2D> &p_texture_pressed) { texture_pressed = p_texture_pressed; - update(); + queue_redraw(); } Ref<Texture2D> TouchScreenButton::get_texture_pressed() const { @@ -60,16 +60,16 @@ Ref<BitMap> TouchScreenButton::get_bitmask() const { void TouchScreenButton::set_shape(const Ref<Shape2D> &p_shape) { if (shape.is_valid()) { - shape->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); + shape->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); } shape = p_shape; if (shape.is_valid()) { - shape->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); + shape->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); } - update(); + queue_redraw(); } Ref<Shape2D> TouchScreenButton::get_shape() const { @@ -78,7 +78,7 @@ Ref<Shape2D> TouchScreenButton::get_shape() const { void TouchScreenButton::set_shape_centered(bool p_shape_centered) { shape_centered = p_shape_centered; - update(); + queue_redraw(); } bool TouchScreenButton::is_shape_visible() const { @@ -87,7 +87,7 @@ bool TouchScreenButton::is_shape_visible() const { void TouchScreenButton::set_shape_visible(bool p_shape_visible) { shape_visible = p_shape_visible; - update(); + queue_redraw(); } bool TouchScreenButton::is_shape_centered() const { @@ -140,7 +140,7 @@ void TouchScreenButton::_notification(int p_what) { 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; } - update(); + queue_redraw(); if (!Engine::get_singleton()->is_editor_hint()) { set_process_input(is_visible_in_tree()); @@ -264,7 +264,7 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { if (bitmask.is_valid()) { check_rect = false; if (!touched && Rect2(Point2(), bitmask->get_size()).has_point(coord)) { - if (bitmask->get_bit(coord)) { + if (bitmask->get_bitv(coord)) { touched = true; } } @@ -292,7 +292,7 @@ void TouchScreenButton::_press(int p_finger_pressed) { } emit_signal(SNAME("pressed")); - update(); + queue_redraw(); } void TouchScreenButton::_release(bool p_exiting_tree) { @@ -311,7 +311,7 @@ void TouchScreenButton::_release(bool p_exiting_tree) { if (!p_exiting_tree) { emit_signal(SNAME("released")); - update(); + queue_redraw(); } } @@ -339,7 +339,7 @@ Rect2 TouchScreenButton::get_anchorable_rect() const { void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) { visibility = p_mode; - update(); + queue_redraw(); } TouchScreenButton::VisibilityMode TouchScreenButton::get_visibility_mode() const { diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp index 1971dc1240..263c3a12a2 100644 --- a/scene/2d/visible_on_screen_notifier_2d.cpp +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -66,7 +66,7 @@ void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) { if (is_inside_tree()) { 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)); } - update(); + queue_redraw(); } Rect2 VisibleOnScreenNotifier2D::get_rect() const { diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index db7c3233f6..cefa9eceff 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -473,22 +473,27 @@ bool Area3D::is_monitoring() const { } TypedArray<Node3D> Area3D::get_overlapping_bodies() const { - ERR_FAIL_COND_V(!monitoring, Array()); - Array ret; + TypedArray<Node3D> ret; + ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping bodies when monitoring is off."); ret.resize(body_map.size()); int idx = 0; for (const KeyValue<ObjectID, BodyState> &E : body_map) { Object *obj = ObjectDB::get_instance(E.key); - if (!obj) { - ret.resize(ret.size() - 1); //ops - } else { - ret[idx++] = obj; + if (obj) { + ret[idx] = obj; + idx++; } } + ret.resize(idx); return ret; } +bool Area3D::has_overlapping_bodies() const { + ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping bodies when monitoring is off."); + return !body_map.is_empty(); +} + void Area3D::set_monitorable(bool p_enable) { ERR_FAIL_COND_MSG(locked || (is_inside_tree() && PhysicsServer3D::get_singleton()->is_flushing_queries()), "Function blocked during in/out signal. Use set_deferred(\"monitorable\", true/false)."); @@ -506,22 +511,26 @@ bool Area3D::is_monitorable() const { } TypedArray<Area3D> Area3D::get_overlapping_areas() const { - ERR_FAIL_COND_V(!monitoring, Array()); - Array ret; + TypedArray<Area3D> ret; + ERR_FAIL_COND_V_MSG(!monitoring, ret, "Can't find overlapping areas when monitoring is off."); ret.resize(area_map.size()); int idx = 0; for (const KeyValue<ObjectID, AreaState> &E : area_map) { Object *obj = ObjectDB::get_instance(E.key); - if (!obj) { - ret.resize(ret.size() - 1); //ops - } else { - ret[idx++] = obj; + if (obj) { + ret[idx] = obj; + idx++; } } - + ret.resize(idx); return ret; } +bool Area3D::has_overlapping_areas() const { + ERR_FAIL_COND_V_MSG(!monitoring, false, "Can't find overlapping areas when monitoring is off."); + return !area_map.is_empty(); +} + bool Area3D::overlaps_area(Node *p_area) const { ERR_FAIL_NULL_V(p_area, false); HashMap<ObjectID, AreaState>::ConstIterator E = area_map.find(p_area->get_instance_id()); @@ -687,6 +696,9 @@ void Area3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_overlapping_bodies"), &Area3D::get_overlapping_bodies); ClassDB::bind_method(D_METHOD("get_overlapping_areas"), &Area3D::get_overlapping_areas); + ClassDB::bind_method(D_METHOD("has_overlapping_bodies"), &Area3D::has_overlapping_bodies); + ClassDB::bind_method(D_METHOD("has_overlapping_areas"), &Area3D::has_overlapping_areas); + ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area3D::overlaps_body); ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area3D::overlaps_area); @@ -728,7 +740,7 @@ void Area3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_point_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_point_distance_scale", "get_gravity_point_distance_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_point_center", PROPERTY_HINT_NONE, "suffix:m"), "set_gravity_point_center", "get_gravity_point_center"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_direction"), "set_gravity_direction", "get_gravity_direction"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_lesser,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, U"-32,32,0.001,or_less,or_greater,suffix:m/s\u00B2"), "set_gravity", "get_gravity"); ADD_GROUP("Linear Damp", "linear_damp_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_linear_damp_space_override_mode", "get_linear_damp_space_override_mode"); diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h index 48364739b7..0f0bcc7ce0 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/area_3d.h @@ -201,6 +201,9 @@ public: TypedArray<Node3D> get_overlapping_bodies() const; TypedArray<Area3D> get_overlapping_areas() const; //function for script + bool has_overlapping_bodies() const; + bool has_overlapping_areas() const; + bool overlaps_area(Node *p_area) const; bool overlaps_body(Node *p_body) const; diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 0e7b71f74a..21cf3bdb3b 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -247,13 +247,18 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } + set_stream_paused(false); } break; case NOTIFICATION_EXIT_TREE: { - stop(); + set_stream_paused(true); AudioServer::get_singleton()->remove_listener_changed_callback(_listener_changed_cb, this); } break; + case NOTIFICATION_PREDELETE: { + stop(); + } break; + case NOTIFICATION_PAUSED: { if (!can_process()) { // Node can't process so we start fading out to silence. diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index b8b6296c45..304e56326d 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -31,6 +31,7 @@ #include "camera_3d.h" #include "collision_object_3d.h" +#include "core/core_string_names.h" #include "core/math/projection.h" #include "scene/main/viewport.h" @@ -71,6 +72,17 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } + + if (attributes.is_valid()) { + const CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + if (physical_attributes) { + if (p_property.name == "near" || p_property.name == "far" || p_property.name == "fov" || p_property.name == "keep_aspect") { + p_property.usage = PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR; + } + } + } + + Node3D::_validate_property(p_property); } void Camera3D::_update_camera() { @@ -400,18 +412,44 @@ Ref<Environment> Camera3D::get_environment() const { return environment; } -void Camera3D::set_effects(const Ref<CameraEffects> &p_effects) { - effects = p_effects; - if (effects.is_valid()) { - RS::get_singleton()->camera_set_camera_effects(camera, effects->get_rid()); +void Camera3D::set_attributes(const Ref<CameraAttributes> &p_attributes) { + if (attributes.is_valid()) { + CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + if (physical_attributes) { + attributes->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed)); + } + } + + attributes = p_attributes; + + if (attributes.is_valid()) { + CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + if (physical_attributes) { + attributes->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Camera3D::_attributes_changed)); + _attributes_changed(); + } + + RS::get_singleton()->camera_set_camera_attributes(camera, attributes->get_rid()); } else { - RS::get_singleton()->camera_set_camera_effects(camera, RID()); + RS::get_singleton()->camera_set_camera_attributes(camera, RID()); } - _update_camera_mode(); + + notify_property_list_changed(); } -Ref<CameraEffects> Camera3D::get_effects() const { - return effects; +Ref<CameraAttributes> Camera3D::get_attributes() const { + return attributes; +} + +void Camera3D::_attributes_changed() { + CameraAttributesPhysical *physical_attributes = Object::cast_to<CameraAttributesPhysical>(attributes.ptr()); + ERR_FAIL_COND(!physical_attributes); + + fov = physical_attributes->get_fov(); + near = physical_attributes->get_near(); + far = physical_attributes->get_far(); + keep_aspect = KEEP_HEIGHT; + _update_camera_mode(); } void Camera3D::set_keep_aspect_mode(KeepAspect p_aspect) { @@ -479,8 +517,8 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_cull_mask"), &Camera3D::get_cull_mask); ClassDB::bind_method(D_METHOD("set_environment", "env"), &Camera3D::set_environment); ClassDB::bind_method(D_METHOD("get_environment"), &Camera3D::get_environment); - ClassDB::bind_method(D_METHOD("set_effects", "env"), &Camera3D::set_effects); - ClassDB::bind_method(D_METHOD("get_effects"), &Camera3D::get_effects); + ClassDB::bind_method(D_METHOD("set_attributes", "env"), &Camera3D::set_attributes); + ClassDB::bind_method(D_METHOD("get_attributes"), &Camera3D::get_attributes); ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera3D::set_keep_aspect_mode); ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera3D::get_keep_aspect_mode); ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera3D::set_doppler_tracking); @@ -498,7 +536,7 @@ void Camera3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_effects", "get_effects"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_attributes", "get_attributes"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index bba9b7d1e4..f150a23e27 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -33,7 +33,7 @@ #include "scene/3d/node_3d.h" #include "scene/3d/velocity_tracker_3d.h" -#include "scene/resources/camera_effects.h" +#include "scene/resources/camera_attributes.h" #include "scene/resources/environment.h" class Camera3D : public Node3D { @@ -64,11 +64,11 @@ private: ProjectionType mode = PROJECTION_PERSPECTIVE; - real_t fov = 0.0; + real_t fov = 75.0; real_t size = 1.0; Vector2 frustum_offset; - real_t near = 0.0; - real_t far = 0.0; + real_t near = 0.05; + real_t far = 4000.0; real_t v_offset = 0.0; real_t h_offset = 0.0; KeepAspect keep_aspect = KEEP_HEIGHT; @@ -81,7 +81,8 @@ private: uint32_t layers = 0xfffff; Ref<Environment> environment; - Ref<CameraEffects> effects; + Ref<CameraAttributes> attributes; + void _attributes_changed(); // void _camera_make_current(Node *p_camera); friend class Viewport; @@ -159,8 +160,8 @@ public: void set_environment(const Ref<Environment> &p_environment); Ref<Environment> get_environment() const; - void set_effects(const Ref<CameraEffects> &p_effects); - Ref<CameraEffects> get_effects() const; + void set_attributes(const Ref<CameraAttributes> &p_effects); + Ref<CameraAttributes> get_attributes() const; void set_keep_aspect_mode(KeepAspect p_aspect); KeepAspect get_keep_aspect_mode() const; diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 9dc61b35af..d7bf76a6f6 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -739,17 +739,17 @@ void CPUParticles3D::_particles_process(double p_delta) { /*real_t tex_linear_velocity = 0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0); + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(0); }*/ real_t tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); + tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv); } real_t tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv); + tex_anim_offset = curve_parameters[PARAM_ANGLE]->sample(tv); } p.seed = Math::rand(); @@ -907,53 +907,53 @@ void CPUParticles3D::_particles_process(double p_delta) { real_t tex_linear_velocity = 1.0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv); + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->sample(tv); } real_t tex_orbit_velocity = 1.0; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv); + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->sample(tv); } } real_t tex_angular_velocity = 1.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv); + tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->sample(tv); } real_t tex_linear_accel = 1.0; if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv); + tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->sample(tv); } real_t tex_tangential_accel = 1.0; if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv); + tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->sample(tv); } real_t tex_radial_accel = 1.0; if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv); + tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->sample(tv); } real_t tex_damping = 1.0; if (curve_parameters[PARAM_DAMPING].is_valid()) { - tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv); + tex_damping = curve_parameters[PARAM_DAMPING]->sample(tv); } real_t tex_angle = 1.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); + tex_angle = curve_parameters[PARAM_ANGLE]->sample(tv); } real_t tex_anim_speed = 1.0; if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) { - tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv); + tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->sample(tv); } real_t tex_anim_offset = 1.0; if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv); + tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->sample(tv); } Vector3 force = gravity; @@ -1016,23 +1016,23 @@ void CPUParticles3D::_particles_process(double p_delta) { Vector3 tex_scale = Vector3(1.0, 1.0, 1.0); if (split_scale) { if (scale_curve_x.is_valid()) { - tex_scale.x = scale_curve_x->interpolate(tv); + tex_scale.x = scale_curve_x->sample(tv); } else { tex_scale.x = 1.0; } if (scale_curve_y.is_valid()) { - tex_scale.y = scale_curve_y->interpolate(tv); + tex_scale.y = scale_curve_y->sample(tv); } else { tex_scale.y = 1.0; } if (scale_curve_z.is_valid()) { - tex_scale.z = scale_curve_z->interpolate(tv); + tex_scale.z = scale_curve_z->sample(tv); } else { tex_scale.z = 1.0; } } else { if (curve_parameters[PARAM_SCALE].is_valid()) { - float tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv); + float tmp_scale = curve_parameters[PARAM_SCALE]->sample(tv); tex_scale.x = tmp_scale; tex_scale.y = tmp_scale; tex_scale.z = tmp_scale; @@ -1041,7 +1041,7 @@ void CPUParticles3D::_particles_process(double p_delta) { real_t tex_hue_variation = 0.0; if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) { - tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv); + tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->sample(tv); } real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand); @@ -1568,32 +1568,32 @@ void CPUParticles3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY); ADD_GROUP("Angular Velocity", "angular_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY); ADD_GROUP("Orbit Velocity", "orbit_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY); ADD_GROUP("Linear Accel", "linear_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL); ADD_GROUP("Radial Accel", "radial_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL); ADD_GROUP("Tangential Accel", "tangential_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL); ADD_GROUP("Damping", ""); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE); ADD_GROUP("Scale", ""); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE); @@ -1613,8 +1613,8 @@ void CPUParticles3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION); ADD_GROUP("Animation", "anim_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_less"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET); diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index 319129603e..cfee7028d4 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "fog_volume.h" +#include "scene/resources/environment.h" /////////////////////////// diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 1cfd889272..24bfa7b6de 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -807,7 +807,7 @@ void GPUParticlesAttractor3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_directionality", "amount"), &GPUParticlesAttractor3D::set_directionality); ClassDB::bind_method(D_METHOD("get_directionality"), &GPUParticlesAttractor3D::get_directionality); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_lesser"), "set_strength", "get_strength"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "-128,128,0.01,or_greater,or_less"), "set_strength", "get_strength"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "0,8,0.01"), "set_attenuation", "get_attenuation"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "directionality", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_directionality", "get_directionality"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp index d5cab6728a..7dc094062b 100644 --- a/scene/3d/joint_3d.cpp +++ b/scene/3d/joint_3d.cpp @@ -309,7 +309,7 @@ void HingeJoint3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "motor/enable"), "set_flag", "get_flag", FLAG_ENABLE_MOTOR); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_lesser,suffix:m/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/target_velocity", PROPERTY_HINT_RANGE, "-200,200,0.01,or_greater,or_less,suffix:m/s"), "set_param", "get_param", PARAM_MOTOR_TARGET_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "motor/max_impulse", PROPERTY_HINT_RANGE, "0.01,1024,0.01"), "set_param", "get_param", PARAM_MOTOR_MAX_IMPULSE); BIND_ENUM_CONSTANT(PARAM_BIAS); diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index e4a7cf6ee5..d977874911 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -486,8 +486,9 @@ void Label3D::_shape() { case TextServer::AUTOWRAP_OFF: break; } - PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags); + autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES; + PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags); float max_line_w = 0.0; for (int i = 0; i < line_breaks.size(); i = i + 2) { RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]); diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 8d96d13f0c..e51f06e083 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "core/config/project_settings.h" + #include "light_3d.h" void Light3D::set_param(Param p_param, real_t p_value) { @@ -122,7 +124,14 @@ uint32_t Light3D::get_cull_mask() const { void Light3D::set_color(const Color &p_color) { color = p_color; - RS::get_singleton()->light_set_color(light, p_color); + + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + Color combined = color.srgb_to_linear(); + combined *= correlated_color.srgb_to_linear(); + RS::get_singleton()->light_set_color(light, combined.linear_to_srgb()); + } else { + RS::get_singleton()->light_set_color(light, color); + } // The gizmo color depends on the light color, so update it. update_gizmos(); } @@ -181,6 +190,56 @@ void Light3D::owner_changed_notify() { _update_visibility(); } +// Temperature expressed in Kelvins. Valid range 1000 - 15000 +// First converts to CIE 1960 then to sRGB +// As explained in the Filament documentation: https://google.github.io/filament/Filament.md.html#lighting/directlighting/lightsparameterization +Color _color_from_temperature(float p_temperature) { + float T2 = p_temperature * p_temperature; + float u = (0.860117757f + 1.54118254e-4f * p_temperature + 1.28641212e-7f * T2) / + (1.0f + 8.42420235e-4f * p_temperature + 7.08145163e-7f * T2); + float v = (0.317398726f + 4.22806245e-5f * p_temperature + 4.20481691e-8f * T2) / + (1.0f - 2.89741816e-5f * p_temperature + 1.61456053e-7f * T2); + + // Convert to xyY space. + float d = 1.0f / (2.0f * u - 8.0f * v + 4.0f); + float x = 3.0f * u * d; + float y = 2.0f * v * d; + + // Convert to XYZ space + const float a = 1.0 / MAX(y, 1e-5f); + Vector3 xyz = Vector3(x * a, 1.0, (1.0f - x - y) * a); + + // Convert from XYZ to sRGB(linear) + Vector3 linear = Vector3(3.2404542f * xyz.x - 1.5371385f * xyz.y - 0.4985314f * xyz.z, + -0.9692660f * xyz.x + 1.8760108f * xyz.y + 0.0415560f * xyz.z, + 0.0556434f * xyz.x - 0.2040259f * xyz.y + 1.0572252f * xyz.z); + linear /= MAX(1e-5f, linear[linear.max_axis_index()]); + // Normalize, clamp, and convert to sRGB. + return Color(linear.x, linear.y, linear.z).clamp().linear_to_srgb(); +} + +void Light3D::set_temperature(const float p_temperature) { + temperature = p_temperature; + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + return; + } + correlated_color = _color_from_temperature(temperature); + + Color combined = color.srgb_to_linear() * correlated_color.srgb_to_linear(); + + RS::get_singleton()->light_set_color(light, combined.linear_to_srgb()); + // The gizmo color depends on the light color, so update it. + update_gizmos(); +} + +Color Light3D::get_correlated_color() const { + return correlated_color; +} + +float Light3D::get_temperature() const { + return temperature; +} + void Light3D::_update_visibility() { if (!is_inside_tree()) { return; @@ -224,12 +283,18 @@ bool Light3D::is_editor_only() const { } void Light3D::_validate_property(PropertyInfo &p_property) const { - if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_fog_fade" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) { + if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } - if (get_light_type() != RS::LIGHT_DIRECTIONAL && p_property.name == "light_angular_distance") { - // Angular distance is only used in DirectionalLight3D. + if (get_light_type() != RS::LIGHT_DIRECTIONAL && (p_property.name == "light_angular_distance" || p_property.name == "light_intensity_lux")) { + // Angular distance and Light Intensity Lux are only used in DirectionalLight3D. + p_property.usage = PROPERTY_USAGE_NONE; + } else if (get_light_type() == RS::LIGHT_DIRECTIONAL && p_property.name == "light_intensity_lumens") { + p_property.usage = PROPERTY_USAGE_NONE; + } + + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && (p_property.name == "light_intensity_lumens" || p_property.name == "light_intensity_lux" || p_property.name == "light_temperature")) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -278,10 +343,18 @@ void Light3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_projector", "projector"), &Light3D::set_projector); ClassDB::bind_method(D_METHOD("get_projector"), &Light3D::get_projector); + ClassDB::bind_method(D_METHOD("set_temperature", "temperature"), &Light3D::set_temperature); + ClassDB::bind_method(D_METHOD("get_temperature"), &Light3D::get_temperature); + ClassDB::bind_method(D_METHOD("get_correlated_color"), &Light3D::get_correlated_color); + ADD_GROUP("Light", "light_"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_intensity_lumens", PROPERTY_HINT_RANGE, "0,100000.0,0.01,or_greater,suffix:lm"), "set_param", "get_param", PARAM_INTENSITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_intensity_lux", PROPERTY_HINT_RANGE, "0,150000.0,0.01,or_greater,suffix:lx"), "set_param", "get_param", PARAM_INTENSITY); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "light_temperature", PROPERTY_HINT_RANGE, "1000,15000.0,1.0,suffix:k"), "set_temperature", "get_temperature"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_ENERGY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_volumetric_fog_energy", PROPERTY_HINT_RANGE, "0,16,0.001,or_greater"), "set_param", "get_param", PARAM_VOLUMETRIC_FOG_ENERGY); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_projector", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_projector", "get_projector"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:m"), "set_param", "get_param", PARAM_SIZE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01,degrees"), "set_param", "get_param", PARAM_SIZE); @@ -296,7 +369,6 @@ void Light3D::_bind_methods() { 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.001"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_OPACITY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BLUR); @@ -313,6 +385,7 @@ void Light3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_ENERGY); BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY); + BIND_ENUM_CONSTANT(PARAM_VOLUMETRIC_FOG_ENERGY); BIND_ENUM_CONSTANT(PARAM_SPECULAR); BIND_ENUM_CONSTANT(PARAM_RANGE); BIND_ENUM_CONSTANT(PARAM_SIZE); @@ -329,8 +402,8 @@ void Light3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE); BIND_ENUM_CONSTANT(PARAM_SHADOW_OPACITY); BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR); - BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE); BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS); + BIND_ENUM_CONSTANT(PARAM_INTENSITY); BIND_ENUM_CONSTANT(PARAM_MAX); BIND_ENUM_CONSTANT(BAKE_DISABLED); @@ -363,6 +436,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) { set_param(PARAM_ENERGY, 1); set_param(PARAM_INDIRECT_ENERGY, 1); + set_param(PARAM_VOLUMETRIC_FOG_ENERGY, 1); set_param(PARAM_SPECULAR, 0.5); set_param(PARAM_RANGE, 5); set_param(PARAM_SIZE, 0); @@ -380,8 +454,10 @@ Light3D::Light3D(RenderingServer::LightType p_type) { set_param(PARAM_SHADOW_BIAS, 0.03); set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0); set_param(PARAM_TRANSMITTANCE_BIAS, 0.05); - set_param(PARAM_SHADOW_VOLUMETRIC_FOG_FADE, 0.1); set_param(PARAM_SHADOW_FADE_START, 1); + // For OmniLight3D and SpotLight3D, specified in Lumens. + set_param(PARAM_INTENSITY, 1000.0); + set_temperature(6500.0); // Nearly white. set_disable_scale(true); } @@ -487,6 +563,7 @@ DirectionalLight3D::DirectionalLight3D() : set_param(PARAM_SHADOW_FADE_START, 0.8); // Increase the default shadow bias to better suit most scenes. set_param(PARAM_SHADOW_BIAS, 0.1); + set_param(PARAM_INTENSITY, 100000.0); // Specified in Lux, approximate mid-day sun. set_shadow_mode(SHADOW_PARALLEL_4_SPLITS); blend_splits = false; set_sky_mode(SKY_MODE_LIGHT_AND_SKY); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 035ba50e42..e43d6f0419 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -40,6 +40,7 @@ public: enum Param { PARAM_ENERGY = RS::LIGHT_PARAM_ENERGY, PARAM_INDIRECT_ENERGY = RS::LIGHT_PARAM_INDIRECT_ENERGY, + PARAM_VOLUMETRIC_FOG_ENERGY = RS::LIGHT_PARAM_VOLUMETRIC_FOG_ENERGY, PARAM_SPECULAR = RS::LIGHT_PARAM_SPECULAR, PARAM_RANGE = RS::LIGHT_PARAM_RANGE, PARAM_SIZE = RS::LIGHT_PARAM_SIZE, @@ -56,8 +57,8 @@ public: PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE, PARAM_SHADOW_OPACITY = RS::LIGHT_PARAM_SHADOW_OPACITY, PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR, - PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE, PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS, + PARAM_INTENSITY = RS::LIGHT_PARAM_INTENSITY, PARAM_MAX = RS::LIGHT_PARAM_MAX }; @@ -83,6 +84,8 @@ private: void _update_visibility(); BakeMode bake_mode = BAKE_DYNAMIC; Ref<Texture2D> projector; + Color correlated_color = Color(1.0, 1.0, 1.0); + float temperature = 6500.0; // bind helpers @@ -139,6 +142,10 @@ public: void set_projector(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_projector() const; + void set_temperature(const float p_temperature); + float get_temperature() const; + Color get_correlated_color() const; + virtual AABB get_aabb() const override; Light3D(); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 7efda6db32..b0bccc4571 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -30,10 +30,14 @@ #include "lightmap_gi.h" +#include "core/config/project_settings.h" #include "core/io/config_file.h" #include "core/math/delaunay_3d.h" #include "lightmap_probe.h" #include "scene/3d/mesh_instance_3d.h" +#include "scene/resources/camera_attributes.h" +#include "scene/resources/environment.h" +#include "scene/resources/sky.h" void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) { User user; @@ -101,6 +105,7 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) { Vector<Ref<Image>> images; for (int i = 0; i < p_data.size(); i++) { Ref<TextureLayered> texture = p_data[i]; + ERR_FAIL_COND_MSG(texture.is_null(), vformat("Invalid TextureLayered at index %d.", i)); for (int j = 0; j < texture->get_layers(); j++) { images.push_back(texture->get_layer_data(j)); } @@ -207,7 +212,7 @@ bool LightmapGIData::is_using_spherical_harmonics() const { return uses_spherical_harmonics; } -void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { +void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure) { if (p_points.size()) { int pc = p_points.size(); ERR_FAIL_COND(pc * 9 != p_point_sh.size()); @@ -221,6 +226,8 @@ void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, con RS::get_singleton()->lightmap_set_probe_bounds(lightmap, AABB()); RS::get_singleton()->lightmap_set_probe_interior(lightmap, false); } + RS::get_singleton()->lightmap_set_baked_exposure_normalization(lightmap, p_baked_exposure); + baked_exposure = p_baked_exposure; interior = p_interior; bounds = p_bounds; } @@ -249,6 +256,10 @@ bool LightmapGIData::is_interior() const { return interior; } +float LightmapGIData::get_baked_exposure() const { + return baked_exposure; +} + void LightmapGIData::_set_probe_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bounds")); ERR_FAIL_COND(!p_data.has("points")); @@ -256,7 +267,8 @@ void LightmapGIData::_set_probe_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bsp")); ERR_FAIL_COND(!p_data.has("sh")); ERR_FAIL_COND(!p_data.has("interior")); - set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"]); + ERR_FAIL_COND(!p_data.has("baked_exposure")); + set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"], p_data["baked_exposure"]); } Dictionary LightmapGIData::_get_probe_data() const { @@ -267,6 +279,7 @@ Dictionary LightmapGIData::_get_probe_data() const { d["bsp"] = get_capture_bsp_tree(); d["sh"] = get_capture_sh(); d["interior"] = is_interior(); + d["baked_exposure"] = get_baked_exposure(); return d; } @@ -753,11 +766,11 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa MeshesFound &mf = meshes_found.write[m_i]; Size2i lightmap_size = mf.mesh->get_lightmap_size_hint() * mf.lightmap_scale; - Vector<RID> overrides; + TypedArray<RID> overrides; overrides.resize(mf.overrides.size()); for (int i = 0; i < mf.overrides.size(); i++) { if (mf.overrides[i].is_valid()) { - overrides.write[i] = mf.overrides[i]->get_rid(); + overrides[i] = mf.overrides[i]->get_rid(); } } TypedArray<Image> images = RS::get_singleton()->bake_render_uv2(mf.mesh->get_rid(), overrides, lightmap_size); @@ -977,15 +990,21 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa Transform3D xf = lights_found[i].xform; Color linear_color = light->get_color().srgb_to_linear(); + float energy = light->get_param(Light3D::PARAM_ENERGY); + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + energy *= light->get_param(Light3D::PARAM_INTENSITY); + linear_color *= light->get_correlated_color().srgb_to_linear(); + } + if (Object::cast_to<DirectionalLight3D>(light)) { DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light); - lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); + lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy, l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<OmniLight3D>(light)) { OmniLight3D *l = Object::cast_to<OmniLight3D>(light); - lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); + lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, energy * (1.0 / (Math_PI * 4.0)), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<SpotLight3D>(light)) { SpotLight3D *l = Object::cast_to<SpotLight3D>(light); - lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); + lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, energy * (1.0 / Math_PI), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } } for (int i = 0; i < probes_found.size(); i++) { @@ -1040,7 +1059,12 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } } - Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud); + float exposure_normalization = 1.0; + if (camera_attributes.is_valid()) { + exposure_normalization = camera_attributes->calculate_exposure_normalization() * camera_attributes->get_exposure_multiplier(); + } + + Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization); if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) { return BAKE_ERROR_MESHES_INVALID; @@ -1214,7 +1238,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa /* Obtain the colors from the images, they will be re-created as cubemaps on the server, depending on the driver */ - data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array); + data->set_capture_data(bounds, interior, points, sh, tetrahedrons, bsp_array, exposure_normalization); /* Compute a BSP tree of the simplices, so it's easy to find the exact one */ } @@ -1410,6 +1434,14 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const { return gen_probes; } +void LightmapGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + camera_attributes = p_camera_attributes; +} + +Ref<CameraAttributes> LightmapGI::get_camera_attributes() const { + return camera_attributes; +} + void LightmapGI::_validate_property(PropertyInfo &p_property) const { if (p_property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { p_property.usage = PROPERTY_USAGE_NONE; @@ -1462,6 +1494,9 @@ void LightmapGI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional); ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &LightmapGI::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &LightmapGI::get_camera_attributes); + // ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant())); ADD_GROUP("Tweaks", ""); @@ -1477,6 +1512,7 @@ void LightmapGI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "environment_custom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_environment_custom_color", "get_environment_custom_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "environment_custom_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_environment_custom_energy", "get_environment_custom_energy"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); ADD_GROUP("Gen Probes", "generate_probes_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes"); ADD_GROUP("Data", ""); diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h index 87add9facc..0062a4a093 100644 --- a/scene/3d/lightmap_gi.h +++ b/scene/3d/lightmap_gi.h @@ -36,6 +36,9 @@ #include "scene/3d/lightmapper.h" #include "scene/3d/visual_instance_3d.h" +class Sky; +class CameraAttributes; + class LightmapGIData : public Resource { GDCLASS(LightmapGIData, Resource); RES_BASE_EXTENSION("lmbake") @@ -47,6 +50,7 @@ class LightmapGIData : public Resource { RID lightmap; AABB bounds; + float baked_exposure = 1.0; struct User { NodePath path; @@ -83,8 +87,9 @@ public: bool is_using_spherical_harmonics() const; bool is_interior() const; + float get_baked_exposure() const; - void set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree); + void set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree, float p_baked_exposure); PackedVector3Array get_capture_points() const; PackedColorArray get_capture_sh() const; PackedInt32Array get_capture_tetrahedra() const; @@ -147,6 +152,7 @@ private: float environment_custom_energy = 1.0; bool directional = false; GenerateProbes gen_probes = GENERATE_PROBES_DISABLED; + Ref<CameraAttributes> camera_attributes; Ref<LightmapGIData> light_data; @@ -260,6 +266,9 @@ public: void set_generate_probes(GenerateProbes p_generate_probes); GenerateProbes get_generate_probes() const; + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; + AABB get_aabb() const override; BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr); diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h index 9b973fd6bc..5b5c6cf53a 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -180,7 +180,7 @@ public: virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0; virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0; virtual void add_probe(const Vector3 &p_position) = 0; - virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr) = 0; + virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, float p_exposure_normalization = 1.0) = 0; virtual int get_bake_texture_count() const = 0; virtual Ref<Image> get_bake_texture(int p_index) const = 0; diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index 31993f898d..a76f4dd0d5 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -115,8 +115,8 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) { if (mesh.is_valid()) { mesh->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed)); - _mesh_changed(); set_base(mesh->get_rid()); + _mesh_changed(); } else { blend_shape_tracks.clear(); blend_shape_properties.clear(); @@ -380,6 +380,13 @@ void MeshInstance3D::_mesh_changed() { } } + int surface_count = mesh->get_surface_count(); + for (int surface_index = 0; surface_index < surface_count; ++surface_index) { + if (surface_override_materials[surface_index].is_valid()) { + RS::get_singleton()->instance_set_surface_override_material(get_instance(), surface_index, surface_override_materials[surface_index]->get_rid()); + } + } + update_gizmos(); } diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp new file mode 100644 index 0000000000..47b602c966 --- /dev/null +++ b/scene/3d/navigation_link_3d.cpp @@ -0,0 +1,389 @@ +/*************************************************************************/ +/* navigation_link_3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "navigation_link_3d.h" + +#include "mesh_instance_3d.h" +#include "servers/navigation_server_3d.h" + +#ifdef DEBUG_ENABLED +void NavigationLink3D::_update_debug_mesh() { + if (!is_inside_tree()) { + return; + } + + if (Engine::get_singleton()->is_editor_hint()) { + // don't update inside Editor as node 3d gizmo takes care of this + // as collisions and selections for Editor Viewport need to be updated + return; + } + + if (!NavigationServer3D::get_singleton()->get_debug_enabled()) { + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + } + return; + } + + if (!debug_instance.is_valid()) { + debug_instance = RenderingServer::get_singleton()->instance_create(); + } + + if (!debug_mesh.is_valid()) { + debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + } + + RID nav_map = get_world_3d()->get_navigation_map(); + real_t search_radius = NavigationServer3D::get_singleton()->map_get_link_connection_radius(nav_map); + Vector3 up_vector = NavigationServer3D::get_singleton()->map_get_up(nav_map); + Vector3::Axis up_axis = up_vector.max_axis_index(); + + debug_mesh->clear_surfaces(); + + Vector<Vector3> lines; + + // Draw line between the points. + lines.push_back(start_location); + lines.push_back(end_location); + + // Draw start location search radius + for (int i = 0; i < 30; i++) { + // Create a circle + const float ra = Math::deg_to_rad((float)(i * 12)); + const float rb = Math::deg_to_rad((float)((i + 1) * 12)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius; + + // Draw axis-aligned circle + switch (up_axis) { + case Vector3::AXIS_X: + lines.append(start_location + Vector3(0, a.x, a.y)); + lines.append(start_location + Vector3(0, b.x, b.y)); + break; + case Vector3::AXIS_Y: + lines.append(start_location + Vector3(a.x, 0, a.y)); + lines.append(start_location + Vector3(b.x, 0, b.y)); + break; + case Vector3::AXIS_Z: + lines.append(start_location + Vector3(a.x, a.y, 0)); + lines.append(start_location + Vector3(b.x, b.y, 0)); + break; + } + } + + // Draw end location search radius + for (int i = 0; i < 30; i++) { + // Create a circle + const float ra = Math::deg_to_rad((float)(i * 12)); + const float rb = Math::deg_to_rad((float)((i + 1) * 12)); + const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * search_radius; + const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * search_radius; + + // Draw axis-aligned circle + switch (up_axis) { + case Vector3::AXIS_X: + lines.append(end_location + Vector3(0, a.x, a.y)); + lines.append(end_location + Vector3(0, b.x, b.y)); + break; + case Vector3::AXIS_Y: + lines.append(end_location + Vector3(a.x, 0, a.y)); + lines.append(end_location + Vector3(b.x, 0, b.y)); + break; + case Vector3::AXIS_Z: + lines.append(end_location + Vector3(a.x, a.y, 0)); + lines.append(end_location + Vector3(b.x, b.y, 0)); + break; + } + } + + Array mesh_array; + mesh_array.resize(Mesh::ARRAY_MAX); + mesh_array[Mesh::ARRAY_VERTEX] = lines; + + debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, mesh_array); + + RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid()); + RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario()); + RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree()); + + Ref<StandardMaterial3D> link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_material(); + Ref<StandardMaterial3D> disabled_link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_disabled_material(); + + if (enabled) { + RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, link_material->get_rid()); + } else { + RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, disabled_link_material->get_rid()); + } +} +#endif // DEBUG_ENABLED + +void NavigationLink3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationLink3D::set_enabled); + ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationLink3D::is_enabled); + + ClassDB::bind_method(D_METHOD("set_bidirectional", "bidirectional"), &NavigationLink3D::set_bidirectional); + ClassDB::bind_method(D_METHOD("is_bidirectional"), &NavigationLink3D::is_bidirectional); + + ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationLink3D::set_navigation_layers); + ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationLink3D::get_navigation_layers); + + ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationLink3D::set_navigation_layer_value); + ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationLink3D::get_navigation_layer_value); + + ClassDB::bind_method(D_METHOD("set_start_location", "location"), &NavigationLink3D::set_start_location); + ClassDB::bind_method(D_METHOD("get_start_location"), &NavigationLink3D::get_start_location); + + ClassDB::bind_method(D_METHOD("set_end_location", "location"), &NavigationLink3D::set_end_location); + ClassDB::bind_method(D_METHOD("get_end_location"), &NavigationLink3D::get_end_location); + + ClassDB::bind_method(D_METHOD("set_enter_cost", "enter_cost"), &NavigationLink3D::set_enter_cost); + ClassDB::bind_method(D_METHOD("get_enter_cost"), &NavigationLink3D::get_enter_cost); + + ClassDB::bind_method(D_METHOD("set_travel_cost", "travel_cost"), &NavigationLink3D::set_travel_cost); + ClassDB::bind_method(D_METHOD("get_travel_cost"), &NavigationLink3D::get_travel_cost); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bidirectional"), "set_bidirectional", "is_bidirectional"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_location"), "set_start_location", "get_start_location"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "end_location"), "set_end_location", "get_end_location"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "enter_cost"), "set_enter_cost", "get_enter_cost"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "travel_cost"), "set_travel_cost", "get_travel_cost"); +} + +void NavigationLink3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (enabled) { + NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map()); + + // Update global positions for the link. + Transform3D gt = get_global_transform(); + NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); + NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + } + +#ifdef DEBUG_ENABLED + _update_debug_mesh(); +#endif // DEBUG_ENABLED + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + // Update global positions for the link. + Transform3D gt = get_global_transform(); + NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); + NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + +#ifdef DEBUG_ENABLED + if (is_inside_tree() && debug_instance.is_valid()) { + RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform()); + } +#endif // DEBUG_ENABLED + } break; + case NOTIFICATION_EXIT_TREE: { + NavigationServer3D::get_singleton()->link_set_map(link, RID()); + +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_scenario(debug_instance, RID()); + RS::get_singleton()->instance_set_visible(debug_instance, false); + } +#endif // DEBUG_ENABLED + } break; + } +} + +NavigationLink3D::NavigationLink3D() { + link = NavigationServer3D::get_singleton()->link_create(); + set_notify_transform(true); +} + +NavigationLink3D::~NavigationLink3D() { + NavigationServer3D::get_singleton()->free(link); + link = RID(); + +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid()) { + RenderingServer::get_singleton()->free(debug_instance); + } + if (debug_mesh.is_valid()) { + RenderingServer::get_singleton()->free(debug_mesh->get_rid()); + } +#endif // DEBUG_ENABLED +} + +void NavigationLink3D::set_enabled(bool p_enabled) { + if (enabled == p_enabled) { + return; + } + + enabled = p_enabled; + + if (!is_inside_tree()) { + return; + } + + if (enabled) { + NavigationServer3D::get_singleton()->link_set_map(link, get_world_3d()->get_navigation_map()); + } else { + NavigationServer3D::get_singleton()->link_set_map(link, RID()); + } + +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid() && debug_mesh.is_valid()) { + if (enabled) { + Ref<StandardMaterial3D> link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_material(); + RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, link_material->get_rid()); + } else { + Ref<StandardMaterial3D> disabled_link_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_link_connections_disabled_material(); + RS::get_singleton()->instance_set_surface_override_material(debug_instance, 0, disabled_link_material->get_rid()); + } + } +#endif // DEBUG_ENABLED + + update_gizmos(); +} + +void NavigationLink3D::set_bidirectional(bool p_bidirectional) { + if (bidirectional == p_bidirectional) { + return; + } + + bidirectional = p_bidirectional; + + NavigationServer3D::get_singleton()->link_set_bidirectional(link, bidirectional); +} + +void NavigationLink3D::set_navigation_layers(uint32_t p_navigation_layers) { + if (navigation_layers == p_navigation_layers) { + return; + } + + navigation_layers = p_navigation_layers; + + NavigationServer3D::get_singleton()->link_set_navigation_layers(link, navigation_layers); +} + +void NavigationLink3D::set_navigation_layer_value(int p_layer_number, bool p_value) { + ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive."); + + uint32_t _navigation_layers = get_navigation_layers(); + + if (p_value) { + _navigation_layers |= 1 << (p_layer_number - 1); + } else { + _navigation_layers &= ~(1 << (p_layer_number - 1)); + } + + set_navigation_layers(_navigation_layers); +} + +bool NavigationLink3D::get_navigation_layer_value(int p_layer_number) const { + ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive."); + ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive."); + + return get_navigation_layers() & (1 << (p_layer_number - 1)); +} + +void NavigationLink3D::set_start_location(Vector3 p_location) { + if (start_location.is_equal_approx(p_location)) { + return; + } + + start_location = p_location; + + if (!is_inside_tree()) { + return; + } + + Transform3D gt = get_global_transform(); + NavigationServer3D::get_singleton()->link_set_start_location(link, gt.xform(start_location)); + +#ifdef DEBUG_ENABLED + _update_debug_mesh(); +#endif // DEBUG_ENABLED + + update_gizmos(); + update_configuration_warnings(); +} + +void NavigationLink3D::set_end_location(Vector3 p_location) { + if (end_location.is_equal_approx(p_location)) { + return; + } + + end_location = p_location; + + if (!is_inside_tree()) { + return; + } + + Transform3D gt = get_global_transform(); + NavigationServer3D::get_singleton()->link_set_end_location(link, gt.xform(end_location)); + +#ifdef DEBUG_ENABLED + _update_debug_mesh(); +#endif // DEBUG_ENABLED + + update_gizmos(); + update_configuration_warnings(); +} + +void NavigationLink3D::set_enter_cost(real_t p_enter_cost) { + ERR_FAIL_COND_MSG(p_enter_cost < 0.0, "The enter_cost must be positive."); + if (Math::is_equal_approx(enter_cost, p_enter_cost)) { + return; + } + + enter_cost = p_enter_cost; + + NavigationServer3D::get_singleton()->link_set_enter_cost(link, enter_cost); +} + +void NavigationLink3D::set_travel_cost(real_t p_travel_cost) { + ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive."); + if (Math::is_equal_approx(travel_cost, p_travel_cost)) { + return; + } + + travel_cost = p_travel_cost; + + NavigationServer3D::get_singleton()->link_set_travel_cost(link, travel_cost); +} + +TypedArray<String> NavigationLink3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + + if (start_location.is_equal_approx(end_location)) { + warnings.push_back(RTR("NavigationLink3D start location should be different than the end location to be useful.")); + } + + return warnings; +} diff --git a/scene/gui/gradient_edit.h b/scene/3d/navigation_link_3d.h index b7c99f1f1c..1f88075527 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/3d/navigation_link_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gradient_edit.h */ +/* navigation_link_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,59 +28,63 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GRADIENT_EDIT_H -#define GRADIENT_EDIT_H +#ifndef NAVIGATION_LINK_3D_H +#define NAVIGATION_LINK_3D_H -#include "scene/gui/color_picker.h" -#include "scene/gui/popup.h" -#include "scene/resources/gradient.h" +#include "scene/3d/node_3d.h" -class GradientEdit : public Control { - GDCLASS(GradientEdit, Control); +class NavigationLink3D : public Node3D { + GDCLASS(NavigationLink3D, Node3D); - PopupPanel *popup = nullptr; - ColorPicker *picker = nullptr; + bool enabled = true; + RID link = RID(); + bool bidirectional = true; + uint32_t navigation_layers = 1; + Vector3 end_location = Vector3(); + Vector3 start_location = Vector3(); + real_t enter_cost = 0.0; + real_t travel_cost = 1.0; - bool grabbing = false; - int grabbed = -1; - Vector<Gradient::Point> points; - Gradient::InterpolationMode interpolation_mode = Gradient::GRADIENT_INTERPOLATE_LINEAR; +#ifdef DEBUG_ENABLED + RID debug_instance; + Ref<ArrayMesh> debug_mesh; - Ref<Gradient> gradient_cache; - Ref<GradientTexture1D> preview_texture; - - // Make sure to use the scaled value below. - const int BASE_SPACING = 3; - const int BASE_POINT_WIDTH = 8; - - int draw_spacing = BASE_SPACING; - int draw_point_width = BASE_POINT_WIDTH; - - void _draw_checker(int x, int y, int w, int h); - void _color_changed(const Color &p_color); - int _get_point_from_pos(int x); - void _show_color_picker(); + void _update_debug_mesh(); +#endif // DEBUG_ENABLED protected: - virtual void gui_input(const Ref<InputEvent> &p_event) override; - void _notification(int p_what); static void _bind_methods(); + void _notification(int p_what); public: - void set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors); - Vector<float> get_offsets() const; - Vector<Color> get_colors() const; - void set_points(Vector<Gradient::Point> &p_points); - Vector<Gradient::Point> &get_points(); - void set_interpolation_mode(Gradient::InterpolationMode p_interp_mode); - Gradient::InterpolationMode get_interpolation_mode(); - ColorPicker *get_picker(); - PopupPanel *get_popup(); - - virtual Size2 get_minimum_size() const override; - - GradientEdit(); - virtual ~GradientEdit(); + NavigationLink3D(); + ~NavigationLink3D(); + + void set_enabled(bool p_enabled); + bool is_enabled() const { return enabled; } + + void set_bidirectional(bool p_bidirectional); + bool is_bidirectional() const { return bidirectional; } + + void set_navigation_layers(uint32_t p_navigation_layers); + uint32_t get_navigation_layers() const { return navigation_layers; } + + void set_navigation_layer_value(int p_layer_number, bool p_value); + bool get_navigation_layer_value(int p_layer_number) const; + + void set_start_location(Vector3 p_location); + Vector3 get_start_location() const { return start_location; } + + void set_end_location(Vector3 p_location); + Vector3 get_end_location() const { return end_location; } + + void set_enter_cost(real_t p_enter_cost); + real_t get_enter_cost() const { return enter_cost; } + + void set_travel_cost(real_t p_travel_cost); + real_t get_travel_cost() const { return travel_cost; } + + TypedArray<String> get_configuration_warnings() const override; }; -#endif // GRADIENT_EDIT_H +#endif // NAVIGATION_LINK_3D_H diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index 953e52e591..9b49238333 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -37,6 +37,9 @@ void NavigationObstacle3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle3D::get_rid); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle3D::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle3D::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle3D::set_estimate_radius); ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle3D::is_radius_estimated); ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle3D::set_radius); @@ -56,28 +59,26 @@ void NavigationObstacle3D::_validate_property(PropertyInfo &p_property) const { void NavigationObstacle3D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - parent_node3d = Object::cast_to<Node3D>(get_parent()); - reevaluate_agent_radius(); - if (parent_node3d != nullptr) { - // place agent on navigation map first or else the RVO agent callback creation fails silently later - NavigationServer3D::get_singleton()->agent_set_map(get_rid(), parent_node3d->get_world_3d()->get_navigation_map()); - } + case NOTIFICATION_POST_ENTER_TREE: { + set_agent_parent(get_parent()); set_physics_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { - parent_node3d = nullptr; + set_agent_parent(nullptr); set_physics_process_internal(false); } break; case NOTIFICATION_PARENTED: { - parent_node3d = Object::cast_to<Node3D>(get_parent()); - reevaluate_agent_radius(); + if (is_inside_tree() && (get_parent() != parent_node3d)) { + set_agent_parent(get_parent()); + set_physics_process_internal(true); + } } break; case NOTIFICATION_UNPARENTED: { - parent_node3d = nullptr; + set_agent_parent(nullptr); + set_physics_process_internal(false); } break; case NOTIFICATION_PAUSED: { @@ -189,6 +190,35 @@ real_t NavigationObstacle3D::estimate_agent_radius() const { return 1.0; // Never a 0 radius } +void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) { + if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) { + parent_node3d = Object::cast_to<Node3D>(p_agent_parent); + if (map_override.is_valid()) { + NavigationServer3D::get_singleton()->agent_set_map(get_rid(), map_override); + } else { + NavigationServer3D::get_singleton()->agent_set_map(get_rid(), parent_node3d->get_world_3d()->get_navigation_map()); + } + reevaluate_agent_radius(); + } else { + parent_node3d = nullptr; + NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID()); + } +} + +void NavigationObstacle3D::set_navigation_map(RID p_navigation_map) { + map_override = p_navigation_map; + NavigationServer3D::get_singleton()->agent_set_map(agent, map_override); +} + +RID NavigationObstacle3D::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (parent_node3d != nullptr) { + return parent_node3d->get_world_3d()->get_navigation_map(); + } + return RID(); +} + void NavigationObstacle3D::set_estimate_radius(bool p_estimate_radius) { estimate_radius = p_estimate_radius; notify_property_list_changed(); diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index 7f6af668b6..24caf50680 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -37,8 +37,10 @@ class NavigationObstacle3D : public Node { GDCLASS(NavigationObstacle3D, Node); Node3D *parent_node3d = nullptr; + RID agent; RID map_before_pause; + RID map_override; bool estimate_radius = true; real_t radius = 1.0; @@ -56,6 +58,11 @@ public: return agent; } + void set_agent_parent(Node *p_agent_parent); + + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_estimate_radius(bool p_estimate_radius); bool is_radius_estimated() const { return estimate_radius; diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 29ad1ba93d..049ca4c8a0 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -539,6 +539,7 @@ void NavigationRegion3D::_update_debug_edge_connections_mesh() { } Vector<Vector3> vertex_array; + vertex_array.resize(connections_count * 6); for (int i = 0; i < connections_count; i++) { Vector3 connection_pathway_start = NavigationServer3D::get_singleton()->region_get_connection_pathway_start(region, i); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 426a8c1684..59ec036558 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -792,8 +792,8 @@ void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) { void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed."); - ERR_FAIL_COND_MSG(p_up.is_equal_approx(Vector3()), "The up vector can't be zero, look_at() failed."); - ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_equal_approx(Vector3()), "Up vector and direction between node origin and target are aligned, look_at() failed."); + ERR_FAIL_COND_MSG(p_up.is_zero_approx(), "The up vector can't be zero, look_at() failed."); + ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_zero_approx(), "Up vector and direction between node origin and target are aligned, look_at() failed."); Transform3D lookat = Transform3D(Basis::looking_at(p_target - p_pos, p_up), p_pos); Vector3 original_scale = get_scale(); @@ -1052,8 +1052,8 @@ void Node3D::_bind_methods() { ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_less,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp index c1c309fdbe..015cb9a21d 100644 --- a/scene/3d/occluder_instance_3d.cpp +++ b/scene/3d/occluder_instance_3d.cpp @@ -186,21 +186,21 @@ ArrayOccluder3D::~ArrayOccluder3D() { ///////////////////////////////////////////////// -void QuadOccluder3D::set_size(const Vector2 &p_size) { +void QuadOccluder3D::set_size(const Size2 &p_size) { if (size == p_size) { return; } - size = p_size.max(Vector2()); + size = p_size.max(Size2()); _update(); } -Vector2 QuadOccluder3D::get_size() const { +Size2 QuadOccluder3D::get_size() const { return size; } void QuadOccluder3D::_update_arrays(PackedVector3Array &r_vertices, PackedInt32Array &r_indices) { - Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f); + Size2 _size = Size2(size.x / 2.0f, size.y / 2.0f); r_vertices = { Vector3(-_size.x, -_size.y, 0), diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h index 11d731b989..69a80e63fc 100644 --- a/scene/3d/occluder_instance_3d.h +++ b/scene/3d/occluder_instance_3d.h @@ -88,15 +88,15 @@ class QuadOccluder3D : public Occluder3D { GDCLASS(QuadOccluder3D, Occluder3D); private: - Vector2 size = Vector2(1.0f, 1.0f); + Size2 size = Vector2(1.0f, 1.0f); protected: virtual void _update_arrays(PackedVector3Array &r_vertices, PackedInt32Array &r_indices) override; static void _bind_methods(); public: - Vector2 get_size() const; - void set_size(const Vector2 &p_size); + Size2 get_size() const; + void set_size(const Size2 &p_size); QuadOccluder3D(); ~QuadOccluder3D(); diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 7d79d9b4fd..2d1f4a579b 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -198,17 +198,17 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { } } - Vector3 pos = c->interpolate_baked(progress, cubic); + Vector3 pos = c->sample_baked(progress, cubic); Transform3D t = get_transform(); // Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used if (rotation_mode == ROTATION_ORIENTED) { - Vector3 forward = c->interpolate_baked(o_next, cubic) - pos; + Vector3 forward = c->sample_baked(o_next, cubic) - pos; // Try with the previous position if (forward.length_squared() < CMP_EPSILON2) { - forward = pos - c->interpolate_baked(o_prev, cubic); + forward = pos - c->sample_baked(o_prev, cubic); } if (forward.length_squared() < CMP_EPSILON2) { @@ -217,10 +217,10 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { forward.normalize(); } - Vector3 up = c->interpolate_baked_up_vector(progress, true); + Vector3 up = c->sample_baked_up_vector(progress, true); if (o_next < progress) { - Vector3 up1 = c->interpolate_baked_up_vector(o_next, true); + Vector3 up1 = c->sample_baked_up_vector(o_next, true); Vector3 axis = up.cross(up1); if (axis.length_squared() < CMP_EPSILON2) { @@ -249,10 +249,10 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { t.origin = pos; if (p_update_xyz_rot && prev_offset != progress) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree. real_t sample_distance = bi * 0.01; - Vector3 t_prev_pos_a = c->interpolate_baked(prev_offset - sample_distance, cubic); - Vector3 t_prev_pos_b = c->interpolate_baked(prev_offset + sample_distance, cubic); - Vector3 t_cur_pos_a = c->interpolate_baked(progress - sample_distance, cubic); - Vector3 t_cur_pos_b = c->interpolate_baked(progress + sample_distance, cubic); + Vector3 t_prev_pos_a = c->sample_baked(prev_offset - sample_distance, cubic); + Vector3 t_prev_pos_b = c->sample_baked(prev_offset + sample_distance, cubic); + Vector3 t_cur_pos_a = c->sample_baked(progress - sample_distance, cubic); + Vector3 t_cur_pos_b = c->sample_baked(progress + sample_distance, cubic); Vector3 t_prev = (t_prev_pos_a - t_prev_pos_b).normalized(); Vector3 t_cur = (t_cur_pos_a - t_cur_pos_b).normalized(); @@ -277,7 +277,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { } // do the additional tilting - real_t tilt_angle = c->interpolate_baked_tilt(progress); + real_t tilt_angle = c->sample_baked_tilt(progress); Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct?? if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) { @@ -337,7 +337,7 @@ void PathFollow3D::_validate_property(PropertyInfo &p_property) const { max = path->get_curve()->get_baked_length(); } - p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater"; + p_property.hint_string = "0," + rtos(max) + ",0.01,or_less,or_greater"; } } @@ -380,8 +380,8 @@ void PathFollow3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop); ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:m"), "set_progress", "get_progress"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_less,or_greater,suffix:m"), "set_progress", "get_progress"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_less,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode"); diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 5534bc28f1..8888aa183a 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1088,7 +1088,7 @@ void RigidBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,1000,0.01,or_greater,exp,suffix:kg"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inertia", PROPERTY_HINT_RANGE, U"0,1000,0.01,or_greater,exp,suffix:kg\u22C5m\u00B2"), "set_inertia", "get_inertia"); ADD_PROPERTY(PropertyInfo(Variant::INT, "center_of_mass_mode", PROPERTY_HINT_ENUM, "Auto,Custom", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_center_of_mass_mode", "get_center_of_mass_mode"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_lesser,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass", PROPERTY_HINT_RANGE, "-10,10,0.01,or_less,or_greater,suffix:m"), "set_center_of_mass", "get_center_of_mass"); ADD_LINKED_PROPERTY("center_of_mass_mode", "center_of_mass"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); @@ -1208,7 +1208,7 @@ bool CharacterBody3D::move_and_slide() { last_motion = Vector3(); - if (!current_platform_velocity.is_equal_approx(Vector3())) { + if (!current_platform_velocity.is_zero_approx()) { PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin); parameters.recovery_as_collision = true; // Also report collisions generated only from recovery. @@ -1315,7 +1315,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo break; } - if (result.remainder.is_equal_approx(Vector3())) { + if (result.remainder.is_zero_approx()) { motion = Vector3(); break; } @@ -1428,7 +1428,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 && !motion_slide_up.is_equal_approx(Vector3())) { + if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_zero_approx()) { // 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(); @@ -1469,7 +1469,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo total_travel += result.travel; // Apply Constant Speed. - if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_equal_approx(Vector3())) { + if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_zero_approx()) { Vector3 travel_slide_up = total_travel.slide(up_direction); motion = motion.normalized() * MAX(0, (motion_slide_up.length() - travel_slide_up.length())); } @@ -1492,7 +1492,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo collided = true; } - if (!collided || motion.is_equal_approx(Vector3())) { + if (!collided || motion.is_zero_approx()) { break; } @@ -1533,7 +1533,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { CollisionState result_state; _set_collision_direction(result, result_state); - if (result.remainder.is_equal_approx(Vector3())) { + if (result.remainder.is_zero_approx()) { motion = Vector3(); break; } @@ -1557,7 +1557,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) { } } - if (!collided || motion.is_equal_approx(Vector3())) { + if (!collided || motion.is_zero_approx()) { break; } @@ -2346,7 +2346,7 @@ void PhysicalBone3D::ConeJointData::_get_property_list(List<PropertyInfo> *p_lis JointData::_get_property_list(p_list); p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/swing_span"), PROPERTY_HINT_RANGE, "-180,180,0.01")); - p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater")); + p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/twist_span"), PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_less,or_greater")); p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/bias"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/softness"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("joint_constraints/relaxation"), PROPERTY_HINT_RANGE, "0.01,16.0,0.01")); @@ -2997,7 +2997,7 @@ void PhysicalBone3D::_bind_methods() { 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", PROPERTY_HINT_NONE, "suffix:m"), "set_joint_offset", "get_joint_offset"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_lesser,or_greater,radians"), "set_joint_rotation", "get_joint_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_less,or_greater,radians"), "set_joint_rotation", "get_joint_rotation"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_body_offset", "get_body_offset"); diff --git a/scene/3d/shape_cast_3d.cpp b/scene/3d/shape_cast_3d.cpp index d324e09df5..a2fecf9c31 100644 --- a/scene/3d/shape_cast_3d.cpp +++ b/scene/3d/shape_cast_3d.cpp @@ -205,7 +205,7 @@ bool ShapeCast3D::is_enabled() const { void ShapeCast3D::set_target_position(const Vector3 &p_point) { target_position = p_point; - if (is_inside_tree()) { + if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) { _update_debug_shape(); } update_gizmos(); @@ -306,7 +306,7 @@ real_t ShapeCast3D::get_closest_collision_unsafe_fraction() const { } void ShapeCast3D::resource_changed(Ref<Resource> p_res) { - if (is_inside_tree()) { + if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) { _update_debug_shape(); } update_gizmos(); @@ -327,7 +327,7 @@ void ShapeCast3D::set_shape(const Ref<Shape3D> &p_shape) { shape_rid = shape->get_rid(); } - if (is_inside_tree()) { + if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) { _update_debug_shape(); } diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 1bc138704e..e04e1866db 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -315,9 +315,7 @@ 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 @@ -603,18 +601,25 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) { int Skeleton3D::get_bone_parent(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, -1); - + if (process_order_dirty) { + const_cast<Skeleton3D *>(this)->_update_process_order(); + } return bones[p_bone].parent; } -Vector<int> Skeleton3D::get_bone_children(int p_bone) { +Vector<int> Skeleton3D::get_bone_children(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Vector<int>()); + if (process_order_dirty) { + const_cast<Skeleton3D *>(this)->_update_process_order(); + } return bones[p_bone].child_bones; } -Vector<int> Skeleton3D::get_parentless_bones() { - _update_process_order(); +Vector<int> Skeleton3D::get_parentless_bones() const { + if (process_order_dirty) { + const_cast<Skeleton3D *>(this)->_update_process_order(); + } return parentless_bones; } diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 79feadf44f..5e49dfa1f4 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -191,11 +191,8 @@ public: void unparent_bone_and_rest(int p_bone); - Vector<int> get_bone_children(int p_bone); - void set_bone_children(int p_bone, Vector<int> p_children); - void add_bone_child(int p_bone, int p_child); - void remove_bone_child(int p_bone, int p_child); - Vector<int> get_parentless_bones(); + Vector<int> get_bone_children(int p_bone) const; + Vector<int> get_parentless_bones() const; int get_bone_count() const; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 669c3eb7fd..7a89bf81bb 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -30,7 +30,6 @@ #include "sprite_3d.h" -#include "core/core_string_names.h" #include "scene/scene_string_names.h" Color SpriteBase3D::_get_color_accum() { @@ -58,7 +57,7 @@ void SpriteBase3D::_propagate_color_changed() { } color_dirty = true; - _queue_update(); + _queue_redraw(); for (SpriteBase3D *&E : children) { E->_propagate_color_changed(); @@ -90,7 +89,7 @@ void SpriteBase3D::_notification(int p_what) { void SpriteBase3D::set_centered(bool p_center) { centered = p_center; - _queue_update(); + _queue_redraw(); } bool SpriteBase3D::is_centered() const { @@ -99,7 +98,7 @@ bool SpriteBase3D::is_centered() const { void SpriteBase3D::set_offset(const Point2 &p_offset) { offset = p_offset; - _queue_update(); + _queue_redraw(); } Point2 SpriteBase3D::get_offset() const { @@ -108,7 +107,7 @@ Point2 SpriteBase3D::get_offset() const { void SpriteBase3D::set_flip_h(bool p_flip) { hflip = p_flip; - _queue_update(); + _queue_redraw(); } bool SpriteBase3D::is_flipped_h() const { @@ -117,7 +116,7 @@ bool SpriteBase3D::is_flipped_h() const { void SpriteBase3D::set_flip_v(bool p_flip) { vflip = p_flip; - _queue_update(); + _queue_redraw(); } bool SpriteBase3D::is_flipped_v() const { @@ -127,7 +126,7 @@ bool SpriteBase3D::is_flipped_v() const { void SpriteBase3D::set_modulate(const Color &p_color) { modulate = p_color; _propagate_color_changed(); - _queue_update(); + _queue_redraw(); } Color SpriteBase3D::get_modulate() const { @@ -137,7 +136,7 @@ Color SpriteBase3D::get_modulate() const { void SpriteBase3D::set_render_priority(int p_priority) { ERR_FAIL_COND(p_priority < RS::MATERIAL_RENDER_PRIORITY_MIN || p_priority > RS::MATERIAL_RENDER_PRIORITY_MAX); render_priority = p_priority; - _queue_update(); + _queue_redraw(); } int SpriteBase3D::get_render_priority() const { @@ -146,7 +145,7 @@ int SpriteBase3D::get_render_priority() const { void SpriteBase3D::set_pixel_size(real_t p_amount) { pixel_size = p_amount; - _queue_update(); + _queue_redraw(); } real_t SpriteBase3D::get_pixel_size() const { @@ -156,7 +155,7 @@ real_t SpriteBase3D::get_pixel_size() const { void SpriteBase3D::set_axis(Vector3::Axis p_axis) { ERR_FAIL_INDEX(p_axis, 3); axis = p_axis; - _queue_update(); + _queue_redraw(); } Vector3::Axis SpriteBase3D::get_axis() const { @@ -171,7 +170,8 @@ void SpriteBase3D::_im_update() { //texture->draw_rect_region(ci,dst_rect,src_rect,modulate); } -void SpriteBase3D::_queue_update() { +void SpriteBase3D::_queue_redraw() { + // The 3D equivalent of CanvasItem.queue_redraw(). if (pending_update) { return; } @@ -250,7 +250,7 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const { void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_enable; - _queue_update(); + _queue_redraw(); } bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const { @@ -261,7 +261,7 @@ bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const { void SpriteBase3D::set_alpha_cut_mode(AlphaCutMode p_mode) { ERR_FAIL_INDEX(p_mode, 3); alpha_cut = p_mode; - _queue_update(); + _queue_redraw(); } SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const { @@ -269,9 +269,9 @@ SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const { } void SpriteBase3D::set_billboard_mode(StandardMaterial3D::BillboardMode p_mode) { - ERR_FAIL_INDEX(p_mode, 3); + ERR_FAIL_INDEX(p_mode, 3); // Cannot use BILLBOARD_PARTICLES. billboard_mode = p_mode; - _queue_update(); + _queue_redraw(); } StandardMaterial3D::BillboardMode SpriteBase3D::get_billboard_mode() const { @@ -281,7 +281,7 @@ StandardMaterial3D::BillboardMode SpriteBase3D::get_billboard_mode() const { void SpriteBase3D::set_texture_filter(StandardMaterial3D::TextureFilter p_filter) { if (texture_filter != p_filter) { texture_filter = p_filter; - _queue_update(); + _queue_redraw(); } } @@ -329,7 +329,6 @@ void SpriteBase3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect); ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh); - ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update); ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); @@ -368,7 +367,7 @@ SpriteBase3D::SpriteBase3D() { } material = RenderingServer::get_singleton()->material_create(); - // Set defaults for material, names need to match up those in StandardMaterial3D + // Set defaults for material, names need to match up those in StandardMaterial3D. RS::get_singleton()->material_set_param(material, "albedo", Color(1, 1, 1, 1)); RS::get_singleton()->material_set_param(material, "specular", 0.5); RS::get_singleton()->material_set_param(material, "metallic", 0.0); @@ -394,7 +393,7 @@ SpriteBase3D::SpriteBase3D() { mesh_colors.resize(4); mesh_uvs.resize(4); - // create basic mesh and store format information + // Create basic mesh and store format information. for (int i = 0; i < 4; i++) { mesh_normals.write[i] = Vector3(0.0, 0.0, 0.0); mesh_tangents.write[i * 4 + 0] = 0.0; @@ -554,7 +553,7 @@ void Sprite3D::_draw() { AABB aabb; - // Everything except position and UV is compressed + // Everything except position and UV is compressed. uint8_t *vertex_write_buffer = vertex_buffer.ptrw(); uint8_t *attribute_write_buffer = attribute_buffer.ptrw(); @@ -637,13 +636,14 @@ void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) { return; } if (texture.is_valid()) { - texture->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update")); + texture->disconnect(SceneStringNames::get_singleton()->changed, callable_mp((SpriteBase3D *)this, &Sprite3D::_queue_redraw)); } texture = p_texture; if (texture.is_valid()) { - texture->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update")); + texture->connect(SceneStringNames::get_singleton()->changed, callable_mp((SpriteBase3D *)this, &Sprite3D::_queue_redraw)); } - _queue_update(); + + _queue_redraw(); emit_signal(SceneStringNames::get_singleton()->texture_changed); } @@ -657,7 +657,7 @@ void Sprite3D::set_region_enabled(bool p_region) { } region = p_region; - _queue_update(); + _queue_redraw(); } bool Sprite3D::is_region_enabled() const { @@ -668,7 +668,7 @@ void Sprite3D::set_region_rect(const Rect2 &p_region_rect) { bool changed = region_rect != p_region_rect; region_rect = p_region_rect; if (region && changed) { - _queue_update(); + _queue_redraw(); } } @@ -681,7 +681,7 @@ void Sprite3D::set_frame(int p_frame) { frame = p_frame; - _queue_update(); + _queue_redraw(); emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -704,7 +704,7 @@ Vector2i Sprite3D::get_frame_coords() const { void Sprite3D::set_vframes(int p_amount) { ERR_FAIL_COND(p_amount < 1); vframes = p_amount; - _queue_update(); + _queue_redraw(); notify_property_list_changed(); } @@ -715,7 +715,7 @@ int Sprite3D::get_vframes() const { void Sprite3D::set_hframes(int p_amount) { ERR_FAIL_COND(p_amount < 1); hframes = p_amount; - _queue_update(); + _queue_redraw(); notify_property_list_changed(); } @@ -820,9 +820,9 @@ void AnimatedSprite3D::_draw() { } Ref<Texture2D> texture = frames->get_frame(animation, frame); - if (!texture.is_valid()) { + if (texture.is_null()) { set_base(RID()); - return; //no texuture no life + return; } Size2 tsize = texture->get_size(); if (tsize.x == 0 || tsize.y == 0) { @@ -917,7 +917,7 @@ void AnimatedSprite3D::_draw() { AABB aabb; - // Everything except position and UV is compressed + // Everything except position and UV is compressed. uint8_t *vertex_write_buffer = vertex_buffer.ptrw(); uint8_t *attribute_write_buffer = attribute_buffer.ptrw(); @@ -997,6 +997,7 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { if (!frames.is_valid()) { return; } + if (p_property.name == "animation") { p_property.hint = PROPERTY_HINT_ENUM; List<StringName> names; @@ -1026,9 +1027,15 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const { p_property.hint_string = String(animation) + "," + p_property.hint_string; } } + return; } if (p_property.name == "frame") { + if (playing) { + p_property.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY; + return; + } + p_property.hint = PROPERTY_HINT_RANGE; if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) { p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1"; @@ -1056,27 +1063,51 @@ void AnimatedSprite3D::_notification(int p_what) { double remaining = get_process_delta_time(); while (remaining) { - double speed = frames->get_animation_speed(animation); + double speed = frames->get_animation_speed(animation) * speed_scale; if (speed == 0) { return; // Do nothing. } if (timeout <= 0) { - timeout = 1.0 / speed; - - int fc = frames->get_frame_count(animation); - if (frame >= fc - 1) { - if (frames->get_animation_loop(animation)) { - frame = 0; + timeout = _get_frame_duration(); + + int last_frame = frames->get_frame_count(animation) - 1; + if (!backwards) { + // Forward. + if (frame >= last_frame) { + if (frames->get_animation_loop(animation)) { + frame = 0; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } else { + frame = last_frame; + if (!is_over) { + is_over = true; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } + } } else { - frame = fc - 1; + frame++; } - emit_signal(SceneStringNames::get_singleton()->animation_finished); } else { - frame++; + // Reversed. + if (frame <= 0) { + if (frames->get_animation_loop(animation)) { + frame = last_frame; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } else { + frame = 0; + if (!is_over) { + is_over = true; + emit_signal(SceneStringNames::get_singleton()->animation_finished); + } + } + } else { + frame--; + } } - _queue_update(); + _queue_redraw(); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -1090,14 +1121,15 @@ void AnimatedSprite3D::_notification(int p_what) { void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { if (frames.is_valid()) { - frames->disconnect("changed", Callable(this, "_res_changed")); + frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed)); } + frames = p_frames; if (frames.is_valid()) { - frames->connect("changed", Callable(this, "_res_changed")); + frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite3D::_res_changed)); } - if (!frames.is_valid()) { + if (frames.is_null()) { frame = 0; } else { set_frame(frame); @@ -1105,7 +1137,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { notify_property_list_changed(); _reset_timeout(); - _queue_update(); + _queue_redraw(); update_configuration_warnings(); } @@ -1114,7 +1146,7 @@ Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const { } void AnimatedSprite3D::set_frame(int p_frame) { - if (!frames.is_valid()) { + if (frames.is_null()) { return; } @@ -1135,7 +1167,8 @@ void AnimatedSprite3D::set_frame(int p_frame) { frame = p_frame; _reset_timeout(); - _queue_update(); + _queue_redraw(); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -1143,6 +1176,20 @@ int AnimatedSprite3D::get_frame() const { return frame; } +void AnimatedSprite3D::set_speed_scale(double p_speed_scale) { + double elapsed = _get_frame_duration() - timeout; + + speed_scale = MAX(p_speed_scale, 0.0f); + + // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed. + _reset_timeout(); + timeout -= elapsed; +} + +double AnimatedSprite3D::get_speed_scale() const { + return speed_scale; +} + Rect2 AnimatedSprite3D::get_item_rect() const { if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) { return Rect2(0, 0, 1, 1); @@ -1171,35 +1218,50 @@ Rect2 AnimatedSprite3D::get_item_rect() const { void AnimatedSprite3D::_res_changed() { set_frame(frame); - _queue_update(); + + _queue_redraw(); } -void AnimatedSprite3D::_set_playing(bool p_playing) { +void AnimatedSprite3D::set_playing(bool p_playing) { if (playing == p_playing) { return; } playing = p_playing; _reset_timeout(); set_process_internal(playing); + notify_property_list_changed(); } -bool AnimatedSprite3D::_is_playing() const { +bool AnimatedSprite3D::is_playing() const { return playing; } -void AnimatedSprite3D::play(const StringName &p_animation) { +void AnimatedSprite3D::play(const StringName &p_animation, const bool p_backwards) { + backwards = p_backwards; + if (p_animation) { set_animation(p_animation); + if (frames.is_valid() && backwards && get_frame() == 0) { + set_frame(frames->get_frame_count(p_animation) - 1); + } } - _set_playing(true); + + is_over = false; + set_playing(true); } void AnimatedSprite3D::stop() { - _set_playing(false); + set_playing(false); } -bool AnimatedSprite3D::is_playing() const { - return playing; +double AnimatedSprite3D::_get_frame_duration() { + if (frames.is_valid() && frames->has_animation(animation)) { + double speed = frames->get_animation_speed(animation) * speed_scale; + if (speed > 0) { + return 1.0 / speed; + } + } + return 0.0; } void AnimatedSprite3D::_reset_timeout() { @@ -1207,19 +1269,13 @@ void AnimatedSprite3D::_reset_timeout() { return; } - if (frames.is_valid() && frames->has_animation(animation)) { - float speed = frames->get_animation_speed(animation); - if (speed > 0) { - timeout = 1.0 / speed; - } else { - timeout = 0; - } - } else { - timeout = 0; - } + timeout = _get_frame_duration(); + is_over = false; } void AnimatedSprite3D::set_animation(const StringName &p_animation) { + ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", p_animation)); + ERR_FAIL_COND_MSG(!frames->get_animation_names().has(p_animation), vformat("There is no animation with name '%s'.", p_animation)); if (animation == p_animation) { return; } @@ -1228,7 +1284,7 @@ void AnimatedSprite3D::set_animation(const StringName &p_animation) { _reset_timeout(); set_frame(0); notify_property_list_changed(); - _queue_update(); + _queue_redraw(); } StringName AnimatedSprite3D::get_animation() const { @@ -1262,16 +1318,18 @@ void AnimatedSprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite3D::set_animation); ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite3D::get_animation); - ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite3D::_set_playing); - ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite3D::_is_playing); + ClassDB::bind_method(D_METHOD("set_playing", "playing"), &AnimatedSprite3D::set_playing); + ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing); - ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite3D::play, DEFVAL(StringName())); + ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite3D::play, DEFVAL(StringName()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite3D::stop); - ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing); ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame); ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame); + ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite3D::set_speed_scale); + ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite3D::get_speed_scale); + ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed); ADD_SIGNAL(MethodInfo("frame_changed")); @@ -1280,7 +1338,8 @@ void AnimatedSprite3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale"), "set_speed_scale", "get_speed_scale"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "set_playing", "is_playing"); } AnimatedSprite3D::AnimatedSprite3D() { diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 03688cf787..e6a546a76d 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -106,7 +106,7 @@ protected: uint32_t skin_stride = 0; uint32_t mesh_surface_format = 0; - void _queue_update(); + void _queue_redraw(); public: void set_centered(bool p_center); @@ -209,18 +209,20 @@ class AnimatedSprite3D : public SpriteBase3D { Ref<SpriteFrames> frames; bool playing = false; + bool backwards = false; StringName animation = "default"; int frame = 0; + float speed_scale = 1.0f; bool centered = false; + bool is_over = false; double timeout = 0.0; void _res_changed(); + double _get_frame_duration(); void _reset_timeout(); - void _set_playing(bool p_playing); - bool _is_playing() const; RID last_shader; RID last_texture; @@ -235,8 +237,10 @@ public: void set_sprite_frames(const Ref<SpriteFrames> &p_frames); Ref<SpriteFrames> get_sprite_frames() const; - void play(const StringName &p_animation = StringName()); + void play(const StringName &p_animation = StringName(), const bool p_backwards = false); void stop(); + + void set_playing(bool p_playing); bool is_playing() const; void set_animation(const StringName &p_animation); @@ -245,6 +249,9 @@ public: void set_frame(int p_frame); int get_frame() const; + void set_speed_scale(double p_speed_scale); + double get_speed_scale() const; + virtual Rect2 get_item_rect() const override; virtual TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 5af06cff29..db9f68544b 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -242,7 +242,7 @@ const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringNa bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) { const StringName *r = _instance_uniform_get_remap(p_name); if (r) { - set_instance_shader_uniform(*r, p_value); + set_instance_shader_parameter(*r, p_value); return true; } #ifndef DISABLE_DEPRECATED @@ -262,7 +262,7 @@ bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const { const StringName *r = _instance_uniform_get_remap(p_name); if (r) { - r_ret = get_instance_shader_uniform(*r); + r_ret = get_instance_shader_parameter(*r); return true; } @@ -271,10 +271,10 @@ bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const { void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const { List<PropertyInfo> pinfo; - RS::get_singleton()->instance_geometry_get_shader_uniform_list(get_instance(), &pinfo); + RS::get_singleton()->instance_geometry_get_shader_parameter_list(get_instance(), &pinfo); for (PropertyInfo &pi : pinfo) { bool has_def_value = false; - Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), pi.name); + Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), pi.name); if (def_value.get_type() != Variant::NIL) { has_def_value = true; } @@ -319,24 +319,24 @@ float GeometryInstance3D::get_lod_bias() const { return lod_bias; } -void GeometryInstance3D::set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value) { +void GeometryInstance3D::set_instance_shader_parameter(const StringName &p_name, const Variant &p_value) { if (p_value.get_type() == Variant::NIL) { - Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), p_uniform); - RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, def_value); + Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_name); + RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, def_value); instance_uniforms.erase(p_value); } else { - instance_uniforms[p_uniform] = p_value; + instance_uniforms[p_name] = p_value; if (p_value.get_type() == Variant::OBJECT) { RID tex_id = p_value; - RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, tex_id); + RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, tex_id); } else { - RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, p_value); + RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_name, p_value); } } } -Variant GeometryInstance3D::get_instance_shader_uniform(const StringName &p_uniform) const { - return RS::get_singleton()->instance_geometry_get_shader_uniform(get_instance(), p_uniform); +Variant GeometryInstance3D::get_instance_shader_parameter(const StringName &p_name) const { + return RS::get_singleton()->instance_geometry_get_shader_parameter(get_instance(), p_name); } void GeometryInstance3D::set_custom_aabb(AABB aabb) { @@ -434,8 +434,8 @@ void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_visibility_range_fade_mode", "mode"), &GeometryInstance3D::set_visibility_range_fade_mode); ClassDB::bind_method(D_METHOD("get_visibility_range_fade_mode"), &GeometryInstance3D::get_visibility_range_fade_mode); - ClassDB::bind_method(D_METHOD("set_instance_shader_uniform", "uniform", "value"), &GeometryInstance3D::set_instance_shader_uniform); - ClassDB::bind_method(D_METHOD("get_instance_shader_uniform", "uniform"), &GeometryInstance3D::get_instance_shader_uniform); + ClassDB::bind_method(D_METHOD("set_instance_shader_parameter", "name", "value"), &GeometryInstance3D::set_instance_shader_parameter); + ClassDB::bind_method(D_METHOD("get_instance_shader_parameter", "name"), &GeometryInstance3D::get_instance_shader_parameter); ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin); ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index f7cdcbf411..100d8d8836 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -178,8 +178,8 @@ public: void set_lightmap_scale(LightmapScale p_scale); LightmapScale get_lightmap_scale() const; - void set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value); - Variant get_instance_shader_uniform(const StringName &p_uniform) const; + void set_instance_shader_parameter(const StringName &p_name, const Variant &p_value); + Variant get_instance_shader_parameter(const StringName &p_name) const; void set_custom_aabb(AABB aabb); diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index ae231026a7..c97af087bf 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -30,8 +30,10 @@ #include "voxel_gi.h" +#include "core/core_string_names.h" #include "mesh_instance_3d.h" #include "multimesh_instance_3d.h" +#include "scene/resources/camera_attributes.h" #include "voxelizer.h" void VoxelGIData::_set_data(const Dictionary &p_data) { @@ -281,6 +283,14 @@ Vector3 VoxelGI::get_extents() const { return extents; } +void VoxelGI::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + camera_attributes = p_camera_attributes; +} + +Ref<CameraAttributes> VoxelGI::get_camera_attributes() const { + return camera_attributes; +} + void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_STATIC && mi->is_visible_in_tree()) { @@ -370,9 +380,14 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) { p_from_node = p_from_node ? p_from_node : get_parent(); ERR_FAIL_NULL(p_from_node); + float exposure_normalization = 1.0; + if (camera_attributes.is_valid()) { + exposure_normalization = camera_attributes->calculate_exposure_normalization() * camera_attributes->get_exposure_multiplier(); + } + Voxelizer baker; - baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0)); + baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0), exposure_normalization); List<PlotMesh> mesh_list; @@ -428,6 +443,8 @@ void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) { Vector<uint8_t> df = baker.get_sdf_3d_image(); + RS::get_singleton()->voxel_gi_set_baked_exposure_normalization(probe_data->get_rid(), exposure_normalization); + probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count()); set_probe_data(probe_data); @@ -472,12 +489,16 @@ void VoxelGI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extents", "extents"), &VoxelGI::set_extents); ClassDB::bind_method(D_METHOD("get_extents"), &VoxelGI::get_extents); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &VoxelGI::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &VoxelGI::get_camera_attributes); + ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &VoxelGI::bake, DEFVAL(Variant()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("debug_bake"), &VoxelGI::_debug_bake); ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_NONE, "suffix:m"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data"); BIND_ENUM_CONSTANT(SUBDIV_64); diff --git a/scene/3d/voxel_gi.h b/scene/3d/voxel_gi.h index 6d173dea87..b31ae4cd95 100644 --- a/scene/3d/voxel_gi.h +++ b/scene/3d/voxel_gi.h @@ -33,6 +33,8 @@ #include "scene/3d/visual_instance_3d.h" +class CameraAttributes; + class VoxelGIData : public Resource { GDCLASS(VoxelGIData, Resource); @@ -117,6 +119,7 @@ private: Subdiv subdiv = SUBDIV_128; Vector3 extents = Vector3(10, 10, 10); + Ref<CameraAttributes> camera_attributes; struct PlotMesh { Ref<Material> override_material; @@ -144,6 +147,10 @@ public: void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; + + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; + Vector3i get_estimated_cell_size() const; void bake(Node *p_from_node = nullptr, bool p_create_visual_debug = false); diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index 9380d1cf32..6daa9e0aec 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -30,6 +30,8 @@ #include "voxelizer.h" +#include "core/config/project_settings.h" + static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) { if (p_pos.is_equal_approx(p_vtx[0])) { r_uv = p_uv[0]; @@ -348,7 +350,10 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material Ref<Texture2D> emission_tex = mat->get_texture(BaseMaterial3D::TEXTURE_EMISSION); Color emission_col = mat->get_emission(); - float emission_energy = mat->get_emission_energy(); + float emission_energy = mat->get_emission_energy_multiplier() * exposure_normalization; + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + emission_energy *= mat->get_emission_intensity(); + } Ref<Image> img_emission; @@ -608,10 +613,11 @@ void Voxelizer::_fixup_plot(int p_idx, int p_level) { } } -void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) { +void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization) { sorted = false; original_bounds = p_bounds; cell_subdiv = p_subdiv; + exposure_normalization = p_exposure_normalization; bake_cells.resize(1); material_cache.clear(); diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h index 68bce768b7..f5bb9af107 100644 --- a/scene/3d/voxelizer.h +++ b/scene/3d/voxelizer.h @@ -87,6 +87,7 @@ private: }; HashMap<Ref<Material>, MaterialCache> material_cache; + float exposure_normalization = 1.0; AABB original_bounds; AABB po2_bounds; int axis_cell_size[3] = {}; @@ -111,7 +112,7 @@ private: void _sort(); public: - void begin_bake(int p_subdiv, const AABB &p_bounds); + void begin_bake(int p_subdiv, const AABB &p_bounds, float p_exposure_normalization); void plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material); void end_bake(); diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index fe9d9ae4dd..ae7d79e8b0 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -42,9 +42,9 @@ void WorldEnvironment::_notification(int p_what) { _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(); + if (camera_attributes.is_valid()) { + add_to_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_attributes(); } } break; @@ -55,9 +55,9 @@ void WorldEnvironment::_notification(int p_what) { _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(); + if (camera_attributes.is_valid()) { + remove_from_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_attributes(); } } break; } @@ -74,15 +74,15 @@ void WorldEnvironment::_update_current_environment() { get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); } -void WorldEnvironment::_update_current_camera_effects() { - WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()))); +void WorldEnvironment::_update_current_camera_attributes() { + WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()))); if (first) { - get_viewport()->find_world_3d()->set_camera_effects(first->camera_effects); + get_viewport()->find_world_3d()->set_camera_attributes(first->camera_attributes); } else { - get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>()); + get_viewport()->find_world_3d()->set_camera_attributes(Ref<CameraAttributes>()); } - get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, "_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warnings"); } void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { @@ -110,36 +110,36 @@ Ref<Environment> WorldEnvironment::get_environment() const { return environment; } -void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) { - if (camera_effects == p_camera_effects) { +void WorldEnvironment::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + if (camera_attributes == p_camera_attributes) { return; } - if (is_inside_tree() && camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() == camera_effects) { - remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + if (is_inside_tree() && camera_attributes.is_valid() && get_viewport()->find_world_3d()->get_camera_attributes() == camera_attributes) { + remove_from_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); } - camera_effects = p_camera_effects; - if (is_inside_tree() && camera_effects.is_valid()) { - add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + camera_attributes = p_camera_attributes; + if (is_inside_tree() && camera_attributes.is_valid()) { + add_to_group("_world_camera_attributes_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); } if (is_inside_tree()) { - _update_current_camera_effects(); + _update_current_camera_attributes(); } else { update_configuration_warnings(); } } -Ref<CameraEffects> WorldEnvironment::get_camera_effects() const { - return camera_effects; +Ref<CameraAttributes> WorldEnvironment::get_camera_attributes() const { + return camera_attributes; } TypedArray<String> WorldEnvironment::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); - if (!environment.is_valid() && !camera_effects.is_valid()) { - warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Effects\" property to contain a CameraEffects resource, or both.")); + if (!environment.is_valid() && !camera_attributes.is_valid()) { + warnings.push_back(RTR("To have any visible effect, WorldEnvironment requires its \"Environment\" property to contain an Environment, its \"Camera Attributes\" property to contain a CameraAttributes resource, or both.")); } if (!is_inside_tree()) { @@ -150,7 +150,7 @@ TypedArray<String> WorldEnvironment::get_configuration_warnings() const { warnings.push_back(("Only the first Environment has an effect in a scene (or set of instantiated scenes).")); } - if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) { + if (camera_attributes.is_valid() && get_viewport()->find_world_3d()->get_camera_attributes() != camera_attributes) { warnings.push_back(RTR("Only one WorldEnvironment is allowed per scene (or set of instantiated scenes).")); } @@ -162,9 +162,9 @@ void WorldEnvironment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_environment"), &WorldEnvironment::get_environment); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); - ClassDB::bind_method(D_METHOD("set_camera_effects", "env"), &WorldEnvironment::set_camera_effects); - ClassDB::bind_method(D_METHOD("get_camera_effects"), &WorldEnvironment::get_camera_effects); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "camera_attributes"), &WorldEnvironment::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &WorldEnvironment::get_camera_attributes); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); } WorldEnvironment::WorldEnvironment() { diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h index 9955aa72a8..07f243c750 100644 --- a/scene/3d/world_environment.h +++ b/scene/3d/world_environment.h @@ -32,17 +32,17 @@ #define WORLD_ENVIRONMENT_H #include "scene/main/node.h" -#include "scene/resources/camera_effects.h" +#include "scene/resources/camera_attributes.h" #include "scene/resources/environment.h" class WorldEnvironment : public Node { GDCLASS(WorldEnvironment, Node); Ref<Environment> environment; - Ref<CameraEffects> camera_effects; + Ref<CameraAttributes> camera_attributes; void _update_current_environment(); - void _update_current_camera_effects(); + void _update_current_camera_attributes(); protected: void _notification(int p_what); @@ -52,8 +52,8 @@ public: void set_environment(const Ref<Environment> &p_environment); Ref<Environment> get_environment() const; - void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); - Ref<CameraEffects> get_camera_effects() const; + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; TypedArray<String> get_configuration_warnings() const override; diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 61f068408c..99f17a1eef 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -542,7 +542,7 @@ AnimationNodeBlend3::AnimationNodeBlend3() { ///////////////////////////////// void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const { - r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_lesser,or_greater")); + r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_less,or_greater")); } Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const { @@ -750,7 +750,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_ float blend = xfade_time == 0 ? 0 : (prev_xfading / xfade_time); if (xfade_curve.is_valid()) { - blend = xfade_curve->interpolate(blend); + blend = xfade_curve->sample(blend); } if (from_start && !p_seek && switched) { //just switched, seek to start of current @@ -810,7 +810,7 @@ void AnimationNodeTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start); ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start); - ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start"); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index afb52de307..49a59de9b2 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -344,6 +344,15 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta } double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_seek_root) { + if (p_time == -1) { + Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node; + if (anodesm.is_valid()) { + p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); + } + playing = false; + return 0; + } + //if not playing and it can restart, then restart if (!playing && start_request == StringName()) { if (!stop_request && p_state_machine->start_node) { @@ -433,7 +442,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } if (current_curve.is_valid()) { - fade_blend = current_curve->interpolate(fade_blend); + fade_blend = current_curve->sample(fade_blend); } float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true); @@ -491,7 +500,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s // handles start_node: if previous state machine is pointing to a node inside the current state machine, starts the current machine from start_node to prev_local_to if (p_state_machine->start_node == current && p_state_machine->transitions[i].local_from == current) { if (p_state_machine->prev_state_machine != nullptr) { - Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter("playback"); + Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter(p_state_machine->playback); if (prev_playback.is_valid()) { StringName prev_local_to = String(prev_playback->current_transition.next).replace_first(String(p_state_machine->state_machine_name) + "/", ""); @@ -530,7 +539,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s AnimationNodeStateMachine *prev_state_machine = p_state_machine->prev_state_machine; if (prev_state_machine != nullptr) { - Ref<AnimationNodeStateMachinePlayback> prev_playback = prev_state_machine->get_parameter("playback"); + Ref<AnimationNodeStateMachinePlayback> prev_playback = prev_state_machine->get_parameter(p_state_machine->playback); if (prev_playback.is_valid()) { if (next_xfade) { @@ -578,7 +587,6 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } if (goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped - if (next_xfade) { //time to fade, baby fading_from = current; @@ -592,7 +600,16 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s if (path.size()) { //if it came from path, remove path path.remove_at(0); } + + { // if the current node is a state machine, update the "playing" variable to false by passing -1 in p_time + Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node; + if (anodesm.is_valid()) { + p_state_machine->blend_node(current, p_state_machine->states[current].node, -1, p_seek, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); + } + } + current = next; + if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) { len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_seek_root, 0, AnimationNode::FILTER_IGNORE, true); pos_current = MIN(pos_current, len_current); @@ -607,15 +624,16 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s } } - // time left must always be 1 because the end node don't length to compute - if (p_state_machine->end_node != current) { - rem = 1; + if (current != p_state_machine->end_node) { + rem = 1; // the time remaining must always be 1 because there is no way to predict how long it takes for the entire state machine to complete } else { - Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter("playback"); + if (p_state_machine->prev_state_machine != nullptr) { + Ref<AnimationNodeStateMachinePlayback> prev_playback = p_state_machine->prev_state_machine->get_parameter(p_state_machine->playback); - if (prev_playback.is_valid()) { - prev_playback->current_transition = current_transition; - prev_playback->force_auto_advance = true; + if (prev_playback.is_valid()) { + prev_playback->current_transition = current_transition; + prev_playback->force_auto_advance = true; + } } } @@ -690,23 +708,6 @@ void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) c for (const StringName &E : advance_conditions) { r_list->push_back(PropertyInfo(Variant::BOOL, E)); } - - // for (const KeyValue<StringName, State> &E : states) { - // if (E->node == ansm) { - // for (int i = 0; i < E->node->transitions.size(); i++) { - // StringName ac = E->node->transitions[i].transition->get_advance_condition_name(); - // if (ac != StringName() && advance_conditions.find(ac) == nullptr) { - // advance_conditions.push_back(ac); - // } - // } - - // advance_conditions.sort_custom<StringName::AlphCompare>(); - - // for (const StringName &E : advance_conditions) { - // r_list->push_back(PropertyInfo(Variant::BOOL, E)); - // } - // } - // } } Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName &p_parameter) const { @@ -900,10 +901,6 @@ void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, co void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const { List<StringName> nodes; for (const KeyValue<StringName, State> &E : states) { - if (E.key == end_node && prev_state_machine == nullptr) { - continue; - } - nodes.push_back(E.key); } nodes.sort_custom<StringName::AlphCompare>(); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 073f61bfdd..096f4edee2 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -323,7 +323,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov #endif // _3D_DISABLED if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) { - child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT); + child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONE_SHOT); } TrackNodeCacheKey key; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 7d9f83b7a2..5b18d4e457 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -75,10 +75,17 @@ Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree."); ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); -#ifdef DEBUG_ENABLED Variant::Type property_type = p_target->get_indexed(p_property.get_as_property_path().get_subnames()).get_type(); - ERR_FAIL_COND_V_MSG(property_type != p_to.get_type(), Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type())); -#endif + if (property_type != p_to.get_type()) { + // Cast p_to between floats and ints to avoid minor annoyances. + if (property_type == Variant::FLOAT && p_to.get_type() == Variant::INT) { + p_to = float(p_to); + } else if (property_type == Variant::INT && p_to.get_type() == Variant::FLOAT) { + p_to = int(p_to); + } else { + ERR_FAIL_V_MSG(Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type())); + } + } Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration)); append(tweener); diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 04feb0dc6f..03115e765f 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -40,6 +40,7 @@ void AudioStreamPlayer::_notification(int p_what) { if (autoplay && !Engine::get_singleton()->is_editor_hint()) { play(); } + set_stream_paused(false); } break; case NOTIFICATION_INTERNAL_PROCESS: { @@ -64,6 +65,10 @@ void AudioStreamPlayer::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { + set_stream_paused(true); + } break; + + case NOTIFICATION_PREDELETE: { for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { AudioServer::get_singleton()->stop_playback_stream(playback); } diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index cee7c049a9..cf467ceafb 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -77,7 +77,7 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) { bool last_press_inside = status.pressing_inside; status.pressing_inside = has_point(mouse_motion->get_position()); if (last_press_inside != status.pressing_inside) { - update(); + queue_redraw(); } } } @@ -87,32 +87,32 @@ void BaseButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_MOUSE_ENTER: { status.hovering = true; - update(); + queue_redraw(); } break; case NOTIFICATION_MOUSE_EXIT: { status.hovering = false; - update(); + queue_redraw(); } break; case NOTIFICATION_DRAG_BEGIN: case NOTIFICATION_SCROLL_BEGIN: { if (status.press_attempt) { status.press_attempt = false; - update(); + queue_redraw(); } } break; case NOTIFICATION_FOCUS_ENTER: { - update(); + queue_redraw(); } break; case NOTIFICATION_FOCUS_EXIT: { if (status.press_attempt) { status.press_attempt = false; - update(); + queue_redraw(); } else if (status.hovering) { - update(); + queue_redraw(); } } break; @@ -188,7 +188,7 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { emit_signal(SNAME("button_up")); } - update(); + queue_redraw(); } void BaseButton::pressed() { @@ -210,7 +210,7 @@ void BaseButton::set_disabled(bool p_disabled) { status.press_attempt = false; status.pressing_inside = false; } - update(); + queue_redraw(); } bool BaseButton::is_disabled() const { @@ -234,7 +234,7 @@ void BaseButton::set_pressed(bool p_pressed) { } _toggled(status.pressed); - update(); + queue_redraw(); } void BaseButton::set_pressed_no_signal(bool p_pressed) { @@ -246,7 +246,7 @@ void BaseButton::set_pressed_no_signal(bool p_pressed) { } status.pressed = p_pressed; - update(); + queue_redraw(); } bool BaseButton::is_pressing() const { @@ -385,7 +385,7 @@ void BaseButton::set_button_group(const Ref<ButtonGroup> &p_group) { button_group->buttons.insert(this); } - update(); //checkbox changes to radio if set a buttongroup + queue_redraw(); //checkbox changes to radio if set a buttongroup } Ref<ButtonGroup> BaseButton::get_button_group() const { diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index a56a51a547..151b0b93d4 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -44,7 +44,6 @@ void BoxContainer::_resort() { Size2i new_size = get_size(); - int sep = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer"); bool rtl = is_layout_rtl(); bool first = true; @@ -90,7 +89,7 @@ void BoxContainer::_resort() { return; } - int stretch_max = (vertical ? new_size.height : new_size.width) - (children_count - 1) * sep; + int stretch_max = (vertical ? new_size.height : new_size.width) - (children_count - 1) * theme_cache.separation; int stretch_diff = stretch_max - stretch_min; if (stretch_diff < 0) { //avoid negative stretch space @@ -214,7 +213,7 @@ void BoxContainer::_resort() { if (first) { first = false; } else { - ofs += sep; + ofs += theme_cache.separation; } int from = ofs; @@ -248,7 +247,6 @@ Size2 BoxContainer::get_minimum_size() const { /* Calculate MINIMUM SIZE */ Size2i minimum; - int sep = get_theme_constant(SNAME("separation")); //,vertical?"VBoxContainer":"HBoxContainer"); bool first = true; @@ -273,7 +271,7 @@ Size2 BoxContainer::get_minimum_size() const { minimum.width = size.width; } - minimum.height += size.height + (first ? 0 : sep); + minimum.height += size.height + (first ? 0 : theme_cache.separation); } else { /* HORIZONTAL */ @@ -281,7 +279,7 @@ Size2 BoxContainer::get_minimum_size() const { minimum.height = size.height; } - minimum.width += size.width + (first ? 0 : sep); + minimum.width += size.width + (first ? 0 : theme_cache.separation); } first = false; @@ -290,6 +288,12 @@ Size2 BoxContainer::get_minimum_size() const { return minimum; } +void BoxContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.separation = get_theme_constant(SNAME("separation")); +} + void BoxContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { @@ -307,6 +311,12 @@ void BoxContainer::_notification(int p_what) { } } +void BoxContainer::_validate_property(PropertyInfo &p_property) const { + if (is_fixed && p_property.name == "vertical") { + p_property.usage = PROPERTY_USAGE_NONE; + } +} + void BoxContainer::set_alignment(AlignmentMode p_alignment) { if (alignment == p_alignment) { return; @@ -319,6 +329,17 @@ BoxContainer::AlignmentMode BoxContainer::get_alignment() const { return alignment; } +void BoxContainer::set_vertical(bool p_vertical) { + ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + "."); + vertical = p_vertical; + update_minimum_size(); + _resort(); +} + +bool BoxContainer::is_vertical() const { + return vertical; +} + Control *BoxContainer::add_spacer(bool p_begin) { Control *c = memnew(Control); c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events @@ -367,14 +388,17 @@ BoxContainer::BoxContainer(bool p_vertical) { void BoxContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("add_spacer", "begin"), &BoxContainer::add_spacer); - ClassDB::bind_method(D_METHOD("get_alignment"), &BoxContainer::get_alignment); ClassDB::bind_method(D_METHOD("set_alignment", "alignment"), &BoxContainer::set_alignment); + ClassDB::bind_method(D_METHOD("get_alignment"), &BoxContainer::get_alignment); + ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &BoxContainer::set_vertical); + ClassDB::bind_method(D_METHOD("is_vertical"), &BoxContainer::is_vertical); BIND_ENUM_CONSTANT(ALIGNMENT_BEGIN); BIND_ENUM_CONSTANT(ALIGNMENT_CENTER); BIND_ENUM_CONSTANT(ALIGNMENT_END); ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control *p_control, bool p_expand) { diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h index 3043c3ea45..0ee5bd1772 100644 --- a/scene/gui/box_container.h +++ b/scene/gui/box_container.h @@ -47,11 +47,19 @@ private: bool vertical = false; AlignmentMode alignment = ALIGNMENT_BEGIN; + struct ThemeCache { + int separation = 0; + } theme_cache; + void _resort(); protected: - void _notification(int p_what); + bool is_fixed = false; + + virtual void _update_theme_item_cache() override; + void _notification(int p_what); + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: @@ -60,6 +68,9 @@ public: void set_alignment(AlignmentMode p_alignment); AlignmentMode get_alignment() const; + void set_vertical(bool p_vertical); + bool is_vertical() const; + virtual Size2 get_minimum_size() const override; virtual Vector<int> get_allowed_size_flags_horizontal() const override; @@ -73,7 +84,7 @@ class HBoxContainer : public BoxContainer { public: HBoxContainer() : - BoxContainer(false) {} + BoxContainer(false) { is_fixed = true; } }; class MarginContainer; @@ -84,7 +95,7 @@ public: MarginContainer *add_margin_child(const String &p_label, Control *p_control, bool p_expand = false); VBoxContainer() : - BoxContainer(true) {} + BoxContainer(true) { is_fixed = true; } }; VARIANT_ENUM_CAST(BoxContainer::AlignmentMode); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index e163f4355c..c2b82e01d1 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -36,7 +36,7 @@ Size2 Button::get_minimum_size() const { Ref<Texture2D> _icon = icon; if (_icon.is_null() && has_theme_icon(SNAME("icon"))) { - _icon = Control::get_theme_icon(SNAME("icon")); + _icon = theme_cache.icon; } return get_minimum_size_for_text_and_icon("", _icon); @@ -46,10 +46,49 @@ void Button::_set_internal_margin(Side p_side, float p_value) { _internal_margin[p_side] = p_value; } +void Button::_update_theme_item_cache() { + BaseButton::_update_theme_item_cache(); + + theme_cache.normal = get_theme_stylebox(SNAME("normal")); + theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored")); + theme_cache.pressed = get_theme_stylebox(SNAME("pressed")); + theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored")); + theme_cache.hover = get_theme_stylebox(SNAME("hover")); + theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored")); + theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed")); + theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored")); + theme_cache.disabled = get_theme_stylebox(SNAME("disabled")); + theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored")); + theme_cache.focus = get_theme_stylebox(SNAME("focus")); + + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color")); + theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color")); + theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color")); + theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color")); + theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + + theme_cache.icon_normal_color = get_theme_color(SNAME("icon_normal_color")); + theme_cache.icon_focus_color = get_theme_color(SNAME("icon_focus_color")); + theme_cache.icon_pressed_color = get_theme_color(SNAME("icon_pressed_color")); + theme_cache.icon_hover_color = get_theme_color(SNAME("icon_hover_color")); + theme_cache.icon_hover_pressed_color = get_theme_color(SNAME("icon_hover_pressed_color")); + theme_cache.icon_disabled_color = get_theme_color(SNAME("icon_disabled_color")); + + theme_cache.icon = get_theme_icon(SNAME("icon")); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); +} + void Button::_notification(int p_what) { switch (p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - update(); + queue_redraw(); } break; case NOTIFICATION_TRANSLATION_CHANGED: { @@ -57,14 +96,14 @@ void Button::_notification(int p_what) { _shape(); update_minimum_size(); - update(); + queue_redraw(); } break; case NOTIFICATION_THEME_CHANGED: { _shape(); update_minimum_size(); - update(); + queue_redraw(); } break; case NOTIFICATION_DRAW: { @@ -73,15 +112,15 @@ void Button::_notification(int p_what) { Color color; Color color_icon(1, 1, 1, 1); - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; bool rtl = is_layout_rtl(); switch (get_draw_mode()) { case DRAW_NORMAL: { if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) { - style = get_theme_stylebox(SNAME("normal_mirrored")); + style = theme_cache.normal_mirrored; } else { - style = get_theme_stylebox(SNAME("normal")); + style = theme_cache.normal; } if (!flat) { @@ -90,14 +129,14 @@ void Button::_notification(int p_what) { // Focus colors only take precedence over normal state. if (has_focus()) { - color = get_theme_color(SNAME("font_focus_color")); + color = theme_cache.font_focus_color; if (has_theme_color(SNAME("icon_focus_color"))) { - color_icon = get_theme_color(SNAME("icon_focus_color")); + color_icon = theme_cache.icon_focus_color; } } else { - color = get_theme_color(SNAME("font_color")); + color = theme_cache.font_color; if (has_theme_color(SNAME("icon_normal_color"))) { - color_icon = get_theme_color(SNAME("icon_normal_color")); + color_icon = theme_cache.icon_normal_color; } } } break; @@ -105,19 +144,19 @@ void Button::_notification(int p_what) { // Edge case for CheckButton and CheckBox. if (has_theme_stylebox("hover_pressed")) { if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) { - style = get_theme_stylebox(SNAME("hover_pressed_mirrored")); + style = theme_cache.hover_pressed_mirrored; } else { - style = get_theme_stylebox(SNAME("hover_pressed")); + style = theme_cache.hover_pressed; } if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } if (has_theme_color(SNAME("font_hover_pressed_color"))) { - color = get_theme_color(SNAME("font_hover_pressed_color")); + color = theme_cache.font_hover_pressed_color; } if (has_theme_color(SNAME("icon_hover_pressed_color"))) { - color_icon = get_theme_color(SNAME("icon_hover_pressed_color")); + color_icon = theme_cache.icon_hover_pressed_color; } break; @@ -126,53 +165,53 @@ void Button::_notification(int p_what) { } case DRAW_PRESSED: { if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) { - style = get_theme_stylebox(SNAME("pressed_mirrored")); + style = theme_cache.pressed_mirrored; } else { - style = get_theme_stylebox(SNAME("pressed")); + style = theme_cache.pressed; } if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } if (has_theme_color(SNAME("font_pressed_color"))) { - color = get_theme_color(SNAME("font_pressed_color")); + color = theme_cache.font_pressed_color; } else { - color = get_theme_color(SNAME("font_color")); + color = theme_cache.font_color; } if (has_theme_color(SNAME("icon_pressed_color"))) { - color_icon = get_theme_color(SNAME("icon_pressed_color")); + color_icon = theme_cache.icon_pressed_color; } } break; case DRAW_HOVER: { if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) { - style = get_theme_stylebox(SNAME("hover_mirrored")); + style = theme_cache.hover_mirrored; } else { - style = get_theme_stylebox(SNAME("hover")); + style = theme_cache.hover; } if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } - color = get_theme_color(SNAME("font_hover_color")); + color = theme_cache.font_hover_color; if (has_theme_color(SNAME("icon_hover_color"))) { - color_icon = get_theme_color(SNAME("icon_hover_color")); + color_icon = theme_cache.icon_hover_color; } } break; case DRAW_DISABLED: { if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) { - style = get_theme_stylebox(SNAME("disabled_mirrored")); + style = theme_cache.disabled_mirrored; } else { - style = get_theme_stylebox(SNAME("disabled")); + style = theme_cache.disabled; } if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } - color = get_theme_color(SNAME("font_disabled_color")); + color = theme_cache.font_disabled_color; if (has_theme_color(SNAME("icon_disabled_color"))) { - color_icon = get_theme_color(SNAME("icon_disabled_color")); + color_icon = theme_cache.icon_disabled_color; } else { color_icon.a = 0.4; } @@ -181,13 +220,13 @@ void Button::_notification(int p_what) { } if (has_focus()) { - Ref<StyleBox> style2 = get_theme_stylebox(SNAME("focus")); + Ref<StyleBox> style2 = theme_cache.focus; style2->draw(ci, Rect2(Point2(), size)); } Ref<Texture2D> _icon; if (icon.is_null() && has_theme_icon(SNAME("icon"))) { - _icon = Control::get_theme_icon(SNAME("icon")); + _icon = theme_cache.icon; } else { _icon = icon; } @@ -217,21 +256,21 @@ void Button::_notification(int p_what) { if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { style_offset.x = style->get_margin(SIDE_LEFT); if (_internal_margin[SIDE_LEFT] > 0) { - icon_ofs_region = _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation")); + icon_ofs_region = _internal_margin[SIDE_LEFT] + theme_cache.h_separation; } } else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) { style_offset.x = 0.0; } else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_RIGHT) { style_offset.x = -style->get_margin(SIDE_RIGHT); if (_internal_margin[SIDE_RIGHT] > 0) { - icon_ofs_region = -_internal_margin[SIDE_RIGHT] - get_theme_constant(SNAME("h_separation")); + icon_ofs_region = -_internal_margin[SIDE_RIGHT] - theme_cache.h_separation; } } style_offset.y = style->get_margin(SIDE_TOP); if (expand_icon) { Size2 _size = get_size() - style->get_offset() * 2; - int icon_text_separation = text.is_empty() ? 0 : get_theme_constant(SNAME("h_separation")); + int icon_text_separation = text.is_empty() ? 0 : theme_cache.h_separation; _size.width -= icon_text_separation + icon_ofs_region; if (!clip_text && icon_align_rtl_checked != HORIZONTAL_ALIGNMENT_CENTER) { _size.width -= text_buf->get_size().width; @@ -261,7 +300,7 @@ void Button::_notification(int p_what) { } } - Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_theme_constant(SNAME("h_separation")), 0) : Point2(); + Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + theme_cache.h_separation, 0) : Point2(); if (align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER && icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) { icon_ofs.x = 0.0; } @@ -271,10 +310,10 @@ void Button::_notification(int p_what) { int text_width = MAX(1, (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x); if (_internal_margin[SIDE_LEFT] > 0) { - text_clip -= _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation")); + text_clip -= _internal_margin[SIDE_LEFT] + theme_cache.h_separation; } if (_internal_margin[SIDE_RIGHT] > 0) { - text_clip -= _internal_margin[SIDE_RIGHT] + get_theme_constant(SNAME("h_separation")); + text_clip -= _internal_margin[SIDE_RIGHT] + theme_cache.h_separation; } Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0; @@ -288,7 +327,7 @@ void Button::_notification(int p_what) { icon_ofs.x = 0.0; } if (_internal_margin[SIDE_LEFT] > 0) { - text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant(SNAME("h_separation")); + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + theme_cache.h_separation; } else { text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; } @@ -305,7 +344,7 @@ void Button::_notification(int p_what) { } break; case HORIZONTAL_ALIGNMENT_RIGHT: { if (_internal_margin[SIDE_RIGHT] > 0) { - text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant(SNAME("h_separation")); + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - theme_cache.h_separation; } else { text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; } @@ -316,8 +355,8 @@ void Button::_notification(int p_what) { } break; } - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); + Color font_outline_color = theme_cache.font_outline_color; + int outline_size = theme_cache.outline_size; if (outline_size > 0 && font_outline_color.a > 0) { text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color); } @@ -346,7 +385,7 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) { minsize.width += p_icon->get_width(); if (!xl_text.is_empty() || !p_text.is_empty()) { - minsize.width += MAX(0, get_theme_constant(SNAME("h_separation"))); + minsize.width += MAX(0, theme_cache.h_separation); } } else { minsize.width = MAX(minsize.width, p_icon->get_width()); @@ -354,12 +393,12 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu } if (!xl_text.is_empty() || !p_text.is_empty()) { - Ref<Font> font = get_theme_font(SNAME("font")); - float font_height = font->get_height(get_theme_font_size(SNAME("font_size"))); + Ref<Font> font = theme_cache.font; + float font_height = font->get_height(theme_cache.font_size); minsize.height = MAX(font_height, minsize.height); } - return get_theme_stylebox(SNAME("normal"))->get_minimum_size() + minsize; + return theme_cache.normal->get_minimum_size() + minsize; } void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) { @@ -371,10 +410,15 @@ void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) { p_text = xl_text; } - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); - p_paragraph->clear(); + + Ref<Font> font = theme_cache.font; + int font_size = theme_cache.font_size; + if (font.is_null() || font_size == 0) { + // Can't shape without a valid font and a non-zero size. + return; + } + if (text_direction == Control::TEXT_DIRECTION_INHERITED) { p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); } else { @@ -389,7 +433,7 @@ void Button::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) { overrun_behavior = p_behavior; _shape(); - update(); + queue_redraw(); update_minimum_size(); } } @@ -404,7 +448,7 @@ void Button::set_text(const String &p_text) { xl_text = atr(text); _shape(); - update(); + queue_redraw(); update_minimum_size(); } } @@ -418,7 +462,7 @@ void Button::set_text_direction(Control::TextDirection p_text_direction) { if (text_direction != p_text_direction) { text_direction = p_text_direction; _shape(); - update(); + queue_redraw(); } } @@ -430,7 +474,7 @@ void Button::set_language(const String &p_language) { if (language != p_language) { language = p_language; _shape(); - update(); + queue_redraw(); } } @@ -441,7 +485,7 @@ String Button::get_language() const { void Button::set_icon(const Ref<Texture2D> &p_icon) { if (icon != p_icon) { icon = p_icon; - update(); + queue_redraw(); update_minimum_size(); } } @@ -453,7 +497,7 @@ Ref<Texture2D> Button::get_icon() const { void Button::set_expand_icon(bool p_enabled) { if (expand_icon != p_enabled) { expand_icon = p_enabled; - update(); + queue_redraw(); update_minimum_size(); } } @@ -465,7 +509,7 @@ bool Button::is_expand_icon() const { void Button::set_flat(bool p_enabled) { if (flat != p_enabled) { flat = p_enabled; - update(); + queue_redraw(); } } @@ -476,7 +520,7 @@ bool Button::is_flat() const { void Button::set_clip_text(bool p_enabled) { if (clip_text != p_enabled) { clip_text = p_enabled; - update(); + queue_redraw(); update_minimum_size(); } } @@ -488,7 +532,7 @@ bool Button::get_clip_text() const { void Button::set_text_alignment(HorizontalAlignment p_alignment) { if (alignment != p_alignment) { alignment = p_alignment; - update(); + queue_redraw(); } } @@ -499,7 +543,7 @@ HorizontalAlignment Button::get_text_alignment() const { void Button::set_icon_alignment(HorizontalAlignment p_alignment) { icon_alignment = p_alignment; update_minimum_size(); - update(); + queue_redraw(); } HorizontalAlignment Button::get_icon_alignment() const { @@ -544,7 +588,7 @@ void Button::_bind_methods() { Button::Button(const String &p_text) { text_buf.instantiate(); - text_buf->set_break_flags(TextServer::BREAK_MANDATORY); + text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_TRIM_EDGE_SPACES); set_mouse_filter(MOUSE_FILTER_STOP); set_text(p_text); diff --git a/scene/gui/button.h b/scene/gui/button.h index 23b5c78166..9d9f9763db 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -54,10 +54,48 @@ private: HorizontalAlignment icon_alignment = HORIZONTAL_ALIGNMENT_LEFT; float _internal_margin[4] = {}; + struct ThemeCache { + Ref<StyleBox> normal; + Ref<StyleBox> normal_mirrored; + Ref<StyleBox> pressed; + Ref<StyleBox> pressed_mirrored; + Ref<StyleBox> hover; + Ref<StyleBox> hover_mirrored; + Ref<StyleBox> hover_pressed; + Ref<StyleBox> hover_pressed_mirrored; + Ref<StyleBox> disabled; + Ref<StyleBox> disabled_mirrored; + Ref<StyleBox> focus; + + Color font_color; + Color font_focus_color; + Color font_pressed_color; + Color font_hover_color; + Color font_hover_pressed_color; + Color font_disabled_color; + + Ref<Font> font; + int font_size = 0; + int outline_size = 0; + Color font_outline_color; + + Color icon_normal_color; + Color icon_focus_color; + Color icon_pressed_color; + Color icon_hover_color; + Color icon_hover_pressed_color; + Color icon_disabled_color; + + Ref<Texture2D> icon; + + int h_separation = 0; + } theme_cache; + void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = ""); protected: void _set_internal_margin(Side p_side, float p_value); + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index 26edc1f1b0..f5eb0b957f 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -33,39 +33,30 @@ #include "servers/rendering_server.h" Size2 CheckBox::get_icon_size() const { - Ref<Texture2D> checked = Control::get_theme_icon(SNAME("checked")); - Ref<Texture2D> unchecked = Control::get_theme_icon(SNAME("unchecked")); - Ref<Texture2D> radio_checked = Control::get_theme_icon(SNAME("radio_checked")); - Ref<Texture2D> radio_unchecked = Control::get_theme_icon(SNAME("radio_unchecked")); - Ref<Texture2D> checked_disabled = Control::get_theme_icon(SNAME("checked_disabled")); - Ref<Texture2D> unchecked_disabled = Control::get_theme_icon(SNAME("unchecked_disabled")); - Ref<Texture2D> radio_checked_disabled = Control::get_theme_icon(SNAME("radio_checked_disabled")); - Ref<Texture2D> radio_unchecked_disabled = Control::get_theme_icon(SNAME("radio_unchecked_disabled")); - Size2 tex_size = Size2(0, 0); - if (!checked.is_null()) { - tex_size = Size2(checked->get_width(), checked->get_height()); + if (!theme_cache.checked.is_null()) { + tex_size = Size2(theme_cache.checked->get_width(), theme_cache.checked->get_height()); } - if (!unchecked.is_null()) { - tex_size = Size2(MAX(tex_size.width, unchecked->get_width()), MAX(tex_size.height, unchecked->get_height())); + if (!theme_cache.unchecked.is_null()) { + tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked->get_width()), MAX(tex_size.height, theme_cache.unchecked->get_height())); } - if (!radio_checked.is_null()) { - tex_size = Size2(MAX(tex_size.width, radio_checked->get_width()), MAX(tex_size.height, radio_checked->get_height())); + if (!theme_cache.radio_checked.is_null()) { + tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked->get_width()), MAX(tex_size.height, theme_cache.radio_checked->get_height())); } - if (!radio_unchecked.is_null()) { - tex_size = Size2(MAX(tex_size.width, radio_unchecked->get_width()), MAX(tex_size.height, radio_unchecked->get_height())); + if (!theme_cache.radio_unchecked.is_null()) { + tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked->get_height())); } - if (!checked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, checked_disabled->get_width()), MAX(tex_size.height, checked_disabled->get_height())); + if (!theme_cache.checked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, theme_cache.checked_disabled->get_width()), MAX(tex_size.height, theme_cache.checked_disabled->get_height())); } - if (!unchecked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, unchecked_disabled->get_width()), MAX(tex_size.height, unchecked_disabled->get_height())); + if (!theme_cache.unchecked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.unchecked_disabled->get_height())); } - if (!radio_checked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, radio_checked_disabled->get_width()), MAX(tex_size.height, radio_checked_disabled->get_height())); + if (!theme_cache.radio_checked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_checked_disabled->get_height())); } - if (!radio_unchecked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, radio_unchecked_disabled->get_width()), MAX(tex_size.height, radio_unchecked_disabled->get_height())); + if (!theme_cache.radio_unchecked_disabled.is_null()) { + tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked_disabled->get_height())); } return tex_size; } @@ -75,14 +66,30 @@ Size2 CheckBox::get_minimum_size() const { Size2 tex_size = get_icon_size(); minsize.width += tex_size.width; if (get_text().length() > 0) { - minsize.width += MAX(0, get_theme_constant(SNAME("h_separation"))); + minsize.width += MAX(0, theme_cache.h_separation); } - Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); - minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM)); + minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM)); return minsize; } +void CheckBox::_update_theme_item_cache() { + Button::_update_theme_item_cache(); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + theme_cache.check_v_offset = get_theme_constant(SNAME("check_v_offset")); + theme_cache.normal_style = get_theme_stylebox(SNAME("normal")); + + theme_cache.checked = get_theme_icon(SNAME("checked")); + theme_cache.unchecked = get_theme_icon(SNAME("unchecked")); + theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked")); + theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked")); + theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled")); + theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled")); + theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled")); + theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled")); +} + void CheckBox::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: @@ -100,22 +107,39 @@ void CheckBox::_notification(int p_what) { 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")); + Ref<Texture2D> on_tex; + Ref<Texture2D> off_tex; + + if (is_radio()) { + if (is_disabled()) { + on_tex = theme_cache.radio_checked_disabled; + off_tex = theme_cache.radio_unchecked_disabled; + } else { + on_tex = theme_cache.radio_checked; + off_tex = theme_cache.radio_unchecked; + } + } else { + if (is_disabled()) { + on_tex = theme_cache.checked_disabled; + off_tex = theme_cache.unchecked_disabled; + } else { + on_tex = theme_cache.checked; + off_tex = theme_cache.unchecked; + } + } Vector2 ofs; if (is_layout_rtl()) { - ofs.x = get_size().x - sb->get_margin(SIDE_RIGHT) - get_icon_size().width; + ofs.x = get_size().x - theme_cache.normal_style->get_margin(SIDE_RIGHT) - get_icon_size().width; } else { - ofs.x = sb->get_margin(SIDE_LEFT); + ofs.x = theme_cache.normal_style->get_margin(SIDE_LEFT); } - ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant(SNAME("check_v_adjust")); + ofs.y = int((get_size().height - get_icon_size().height) / 2) + theme_cache.check_v_offset; if (is_pressed()) { - on->draw(ci, ofs); + on_tex->draw(ci, ofs); } else { - off->draw(ci, ofs); + off_tex->draw(ci, ofs); } } break; } diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h index fcdb2ce08c..8438d0e589 100644 --- a/scene/gui/check_box.h +++ b/scene/gui/check_box.h @@ -36,9 +36,26 @@ class CheckBox : public Button { GDCLASS(CheckBox, Button); + struct ThemeCache { + int h_separation = 0; + int check_v_offset = 0; + Ref<StyleBox> normal_style; + + Ref<Texture2D> checked; + Ref<Texture2D> unchecked; + Ref<Texture2D> radio_checked; + Ref<Texture2D> radio_unchecked; + Ref<Texture2D> checked_disabled; + Ref<Texture2D> unchecked_disabled; + Ref<Texture2D> radio_checked_disabled; + Ref<Texture2D> radio_unchecked_disabled; + } theme_cache; + protected: Size2 get_icon_size() const; Size2 get_minimum_size() const override; + + virtual void _update_theme_item_cache() override; void _notification(int p_what); bool is_radio(); diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index b9674ca41e..9466512699 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -34,14 +34,33 @@ #include "servers/rendering_server.h" Size2 CheckButton::get_icon_size() const { - Ref<Texture2D> on = Control::get_theme_icon(is_disabled() ? "on_disabled" : "on"); - Ref<Texture2D> off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off"); + Ref<Texture2D> on_tex; + Ref<Texture2D> off_tex; + + if (is_layout_rtl()) { + if (is_disabled()) { + on_tex = theme_cache.checked_disabled_mirrored; + off_tex = theme_cache.unchecked_disabled_mirrored; + } else { + on_tex = theme_cache.checked_mirrored; + off_tex = theme_cache.unchecked_mirrored; + } + } else { + if (is_disabled()) { + on_tex = theme_cache.checked_disabled; + off_tex = theme_cache.unchecked_disabled; + } else { + on_tex = theme_cache.checked; + off_tex = theme_cache.unchecked; + } + } + Size2 tex_size = Size2(0, 0); - if (!on.is_null()) { - tex_size = Size2(on->get_width(), on->get_height()); + if (!on_tex.is_null()) { + tex_size = Size2(on_tex->get_width(), on_tex->get_height()); } - if (!off.is_null()) { - tex_size = Size2(MAX(tex_size.width, off->get_width()), MAX(tex_size.height, off->get_height())); + if (!off_tex.is_null()) { + tex_size = Size2(MAX(tex_size.width, off_tex->get_width()), MAX(tex_size.height, off_tex->get_height())); } return tex_size; @@ -52,14 +71,30 @@ Size2 CheckButton::get_minimum_size() const { Size2 tex_size = get_icon_size(); minsize.width += tex_size.width; if (get_text().length() > 0) { - minsize.width += MAX(0, get_theme_constant(SNAME("h_separation"))); + minsize.width += MAX(0, theme_cache.h_separation); } - Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal")); - minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM)); + minsize.height = MAX(minsize.height, tex_size.height + theme_cache.normal_style->get_margin(SIDE_TOP) + theme_cache.normal_style->get_margin(SIDE_BOTTOM)); return minsize; } +void CheckButton::_update_theme_item_cache() { + Button::_update_theme_item_cache(); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + theme_cache.check_v_offset = get_theme_constant(SNAME("check_v_offset")); + theme_cache.normal_style = get_theme_stylebox(SNAME("normal")); + + theme_cache.checked = get_theme_icon(SNAME("checked")); + theme_cache.unchecked = get_theme_icon(SNAME("unchecked")); + theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled")); + theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled")); + theme_cache.checked_mirrored = get_theme_icon(SNAME("checked_mirrored")); + theme_cache.unchecked_mirrored = get_theme_icon(SNAME("unchecked_mirrored")); + theme_cache.checked_disabled_mirrored = get_theme_icon(SNAME("checked_disabled_mirrored")); + theme_cache.unchecked_disabled_mirrored = get_theme_icon(SNAME("unchecked_disabled_mirrored")); +} + void CheckButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: @@ -78,34 +113,41 @@ void CheckButton::_notification(int p_what) { 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; + Ref<Texture2D> on_tex; + Ref<Texture2D> off_tex; + if (rtl) { - off = Control::get_theme_icon(is_disabled() ? "off_disabled_mirrored" : "off_mirrored"); + if (is_disabled()) { + on_tex = theme_cache.checked_disabled_mirrored; + off_tex = theme_cache.unchecked_disabled_mirrored; + } else { + on_tex = theme_cache.checked_mirrored; + off_tex = theme_cache.unchecked_mirrored; + } } else { - off = Control::get_theme_icon(is_disabled() ? "off_disabled" : "off"); + if (is_disabled()) { + on_tex = theme_cache.checked_disabled; + off_tex = theme_cache.unchecked_disabled; + } else { + on_tex = theme_cache.checked; + off_tex = theme_cache.unchecked; + } } - 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); + ofs.x = theme_cache.normal_style->get_margin(SIDE_LEFT); } else { - ofs.x = get_size().width - (tex_size.width + sb->get_margin(SIDE_RIGHT)); + ofs.x = get_size().width - (tex_size.width + theme_cache.normal_style->get_margin(SIDE_RIGHT)); } - ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant(SNAME("check_v_adjust")); + ofs.y = (get_size().height - tex_size.height) / 2 + theme_cache.check_v_offset; if (is_pressed()) { - on->draw(ci, ofs); + on_tex->draw(ci, ofs); } else { - off->draw(ci, ofs); + off_tex->draw(ci, ofs); } } break; } diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h index 7d4bb8bdfc..3878c9628a 100644 --- a/scene/gui/check_button.h +++ b/scene/gui/check_button.h @@ -36,9 +36,26 @@ class CheckButton : public Button { GDCLASS(CheckButton, Button); + struct ThemeCache { + int h_separation = 0; + int check_v_offset = 0; + Ref<StyleBox> normal_style; + + Ref<Texture2D> checked; + Ref<Texture2D> unchecked; + Ref<Texture2D> checked_disabled; + Ref<Texture2D> unchecked_disabled; + Ref<Texture2D> checked_mirrored; + Ref<Texture2D> unchecked_mirrored; + Ref<Texture2D> checked_disabled_mirrored; + Ref<Texture2D> unchecked_disabled_mirrored; + } theme_cache; + protected: Size2 get_icon_size() const; virtual Size2 get_minimum_size() const override; + + virtual void _update_theme_item_cache() override; void _notification(int p_what); public: diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index e54ba7ce13..f6e0e4216d 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -268,7 +268,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { if (is_code_completion_scroll_pressed && mb->get_button_index() == MouseButton::LEFT) { is_code_completion_scroll_pressed = false; - update(); + queue_redraw(); return; } @@ -281,13 +281,13 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { case MouseButton::WHEEL_UP: { if (code_completion_current_selected > 0) { code_completion_current_selected--; - update(); + queue_redraw(); } } break; case MouseButton::WHEEL_DOWN: { if (code_completion_current_selected < code_completion_options.size() - 1) { code_completion_current_selected++; - update(); + queue_redraw(); } } break; case MouseButton::LEFT: { @@ -295,7 +295,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->is_double_click()) { confirm_code_completion(); } - update(); + queue_redraw(); } break; default: break; @@ -310,7 +310,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { is_code_completion_scroll_pressed = true; _update_scroll_selected_line(mb->get_position().y); - update(); + queue_redraw(); } return; @@ -344,7 +344,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } } else { if (mb->get_button_index() == MouseButton::LEFT) { - if (mb->is_command_pressed() && !symbol_lookup_word.is_empty()) { + if (mb->is_command_or_control_pressed() && !symbol_lookup_word.is_empty()) { Vector2i mpos = mb->get_position(); if (is_layout_rtl()) { mpos.x = get_size().x - mpos.x; @@ -371,7 +371,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } if (symbol_lookup_on_click_enabled) { - if (mm->is_command_pressed() && mm->get_button_mask() == MouseButton::NONE && !is_dragging_cursor()) { + if (mm->is_command_or_control_pressed() && mm->get_button_mask() == MouseButton::NONE && !is_dragging_cursor()) { symbol_lookup_new_word = get_word_at_pos(mpos); if (symbol_lookup_new_word != symbol_lookup_word) { emit_signal(SNAME("symbol_validate"), symbol_lookup_new_word); @@ -384,12 +384,12 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { bool scroll_hovered = code_completion_scroll_rect.has_point(mpos); if (is_code_completion_scroll_hovered != scroll_hovered) { is_code_completion_scroll_hovered = scroll_hovered; - update(); + queue_redraw(); } if (is_code_completion_scroll_pressed) { _update_scroll_selected_line(mpos.y); - update(); + queue_redraw(); return; } } @@ -432,7 +432,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { /* Allow unicode handling if: */ /* No Modifiers are pressed (except shift) */ - bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed()); + bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed()); /* AUTO-COMPLETE */ if (code_completion_enabled && k->is_action("ui_text_completion_query", true)) { @@ -448,7 +448,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } else { code_completion_current_selected = code_completion_options.size() - 1; } - update(); + queue_redraw(); accept_event(); return; } @@ -458,31 +458,31 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } else { code_completion_current_selected = 0; } - update(); + queue_redraw(); accept_event(); return; } if (k->is_action("ui_page_up", true)) { code_completion_current_selected = MAX(0, code_completion_current_selected - code_completion_max_lines); - update(); + queue_redraw(); accept_event(); return; } if (k->is_action("ui_page_down", true)) { code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines); - update(); + queue_redraw(); accept_event(); return; } if (k->is_action("ui_home", true)) { code_completion_current_selected = 0; - update(); + queue_redraw(); accept_event(); return; } if (k->is_action("ui_end", true)) { code_completion_current_selected = code_completion_options.size() - 1; - update(); + queue_redraw(); accept_event(); return; } @@ -1106,7 +1106,7 @@ bool CodeEdit::is_auto_brace_completion_enabled() const { void CodeEdit::set_highlight_matching_braces_enabled(bool p_enabled) { highlight_matching_braces_enabled = p_enabled; - update(); + queue_redraw(); } bool CodeEdit::is_highlight_matching_braces_enabled() const { @@ -1265,7 +1265,7 @@ void CodeEdit::set_line_as_breakpoint(int p_line, bool p_breakpointed) { breakpointed_lines.erase(p_line); } emit_signal(SNAME("breakpoint_toggled"), p_line); - update(); + queue_redraw(); } bool CodeEdit::is_line_breakpointed(int p_line) const { @@ -1294,7 +1294,7 @@ PackedInt32Array CodeEdit::get_breakpointed_lines() const { void CodeEdit::set_line_as_bookmarked(int p_line, bool p_bookmarked) { int mask = get_line_gutter_metadata(p_line, main_gutter); set_line_gutter_metadata(p_line, main_gutter, p_bookmarked ? mask | MAIN_GUTTER_BOOKMARK : mask & ~MAIN_GUTTER_BOOKMARK); - update(); + queue_redraw(); } bool CodeEdit::is_line_bookmarked(int p_line) const { @@ -1323,7 +1323,7 @@ PackedInt32Array CodeEdit::get_bookmarked_lines() const { void CodeEdit::set_line_as_executing(int p_line, bool p_executing) { int mask = get_line_gutter_metadata(p_line, main_gutter); set_line_gutter_metadata(p_line, main_gutter, p_executing ? mask | MAIN_GUTTER_EXECUTING : mask & ~MAIN_GUTTER_EXECUTING); - update(); + queue_redraw(); } bool CodeEdit::is_line_executing(int p_line) const { @@ -1359,7 +1359,7 @@ bool CodeEdit::is_draw_line_numbers_enabled() const { void CodeEdit::set_line_numbers_zero_padded(bool p_zero_padded) { p_zero_padded ? line_number_padding = "0" : line_number_padding = " "; - update(); + queue_redraw(); } bool CodeEdit::is_line_numbers_zero_padded() const { @@ -1529,7 +1529,7 @@ void CodeEdit::fold_line(int p_line) { set_caret_line(p_line, false, false); set_caret_column(get_line(p_line).length(), false); } - update(); + queue_redraw(); } void CodeEdit::unfold_line(int p_line) { @@ -1552,14 +1552,14 @@ void CodeEdit::unfold_line(int p_line) { } _set_line_as_hidden(i, false); } - update(); + queue_redraw(); } void CodeEdit::fold_all_lines() { for (int i = 0; i < get_line_count(); i++) { fold_line(i); } - update(); + queue_redraw(); } void CodeEdit::unfold_all_lines() { @@ -1765,12 +1765,12 @@ Point2 CodeEdit::get_delimiter_end_position(int p_line, int p_column) const { void CodeEdit::set_code_hint(const String &p_hint) { code_hint = p_hint; code_hint_xpos = -0xFFFF; - update(); + queue_redraw(); } void CodeEdit::set_code_hint_draw_below(bool p_below) { code_hint_draw_below = p_below; - update(); + queue_redraw(); } /* Code Completion */ @@ -1929,7 +1929,7 @@ void CodeEdit::set_code_completion_selected_index(int p_index) { } ERR_FAIL_INDEX(p_index, code_completion_options.size()); code_completion_current_selected = p_index; - update(); + queue_redraw(); } void CodeEdit::confirm_code_completion(bool p_replace) { @@ -2043,13 +2043,13 @@ void CodeEdit::cancel_code_completion() { } code_completion_forced = false; code_completion_active = false; - update(); + queue_redraw(); } /* Line length guidelines */ void CodeEdit::set_line_length_guidelines(TypedArray<int> p_guideline_columns) { line_length_guideline_columns = p_guideline_columns; - update(); + queue_redraw(); } TypedArray<int> CodeEdit::get_line_length_guidelines() const { @@ -2802,7 +2802,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() { code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size); code_completion_current_selected = 0; code_completion_active = true; - update(); + queue_redraw(); return; } @@ -3052,7 +3052,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() { code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size); code_completion_current_selected = 0; code_completion_active = true; - update(); + queue_redraw(); } void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) { diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index a417e7b9e2..4a1f2ab7c6 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -303,7 +303,7 @@ void ColorPicker::set_edit_alpha(bool p_show) { } _update_color(); - sample->update(); + sample->queue_redraw(); } bool ColorPicker::is_editing_alpha() const { @@ -458,15 +458,15 @@ void ColorPicker::_update_color(bool p_update_sliders) { _update_text_value(); - sample->update(); - uv_edit->update(); - w_edit->update(); + sample->queue_redraw(); + uv_edit->queue_redraw(); + w_edit->queue_redraw(); for (int i = 0; i < current_slider_count; i++) { - sliders[i]->update(); + sliders[i]->queue_redraw(); } - alpha_slider->update(); - wheel->update(); - wheel_uv->update(); + alpha_slider->queue_redraw(); + wheel->queue_redraw(); + wheel_uv->queue_redraw(); updating = false; } @@ -853,7 +853,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } else if (p_which == 2) { c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1)); if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) { - circle_mat->set_shader_uniform("v", v); + circle_mat->set_shader_parameter("v", v); } } } @@ -1086,7 +1086,7 @@ void ColorPicker::_screen_pick_pressed() { } else { screen->show(); } - screen->raise(); + screen->move_to_front(); #ifndef _MSC_VER #warning show modal no longer works, needs to be converted to a popup #endif @@ -1359,7 +1359,7 @@ void ColorPickerButton::_about_to_popup() { void ColorPickerButton::_color_changed(const Color &p_color) { color = p_color; - update(); + queue_redraw(); emit_signal(SNAME("color_changed"), color); } @@ -1439,7 +1439,7 @@ void ColorPickerButton::set_pick_color(const Color &p_color) { picker->set_pick_color(p_color); } - update(); + queue_redraw(); } Color ColorPickerButton::get_pick_color() const { diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp index c30fa8461a..143662efc6 100644 --- a/scene/gui/color_rect.cpp +++ b/scene/gui/color_rect.cpp @@ -35,7 +35,7 @@ void ColorRect::set_color(const Color &p_color) { return; } color = p_color; - update(); + queue_redraw(); } Color ColorRect::get_color() const { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 4de16a0a29..347fe9aa11 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -44,6 +44,7 @@ #include "scene/main/window.h" #include "scene/scene_string_names.h" #include "scene/theme/theme_db.h" +#include "scene/theme/theme_owner.h" #include "servers/rendering_server.h" #include "servers/text_server.h" @@ -713,7 +714,7 @@ void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool _size_changed(); } - update(); + queue_redraw(); } real_t Control::get_anchor(Side p_side) const { @@ -1459,7 +1460,7 @@ void Control::set_scale(const Vector2 &p_scale) { if (data.scale.y == 0) { data.scale.y = CMP_EPSILON; } - update(); + queue_redraw(); _notify_transform(); } @@ -1473,7 +1474,7 @@ void Control::set_rotation(real_t p_radians) { } data.rotation = p_radians; - update(); + queue_redraw(); _notify_transform(); } @@ -1487,7 +1488,7 @@ void Control::set_pivot_offset(const Vector2 &p_pivot) { } data.pivot_offset = p_pivot; - update(); + queue_redraw(); _notify_transform(); } @@ -1563,7 +1564,7 @@ Size2 Control::get_minimum_size() const { return Vector2(); } -void Control::set_custom_minimum_size(const Size2 &p_custom) { +void Control::set_custom_minimum_size(const Size2i &p_custom) { if (p_custom == data.custom_minimum_size) { return; } @@ -1571,7 +1572,7 @@ void Control::set_custom_minimum_size(const Size2 &p_custom) { update_minimum_size(); } -Size2 Control::get_custom_minimum_size() const { +Size2i Control::get_custom_minimum_size() const { return data.custom_minimum_size; } @@ -2240,7 +2241,7 @@ void Control::set_disable_visibility_clip(bool p_ignore) { return; } data.disable_visibility_clip = p_ignore; - update(); + queue_redraw(); } bool Control::is_visibility_clip_disabled() const { @@ -2252,7 +2253,7 @@ void Control::set_clip_contents(bool p_clip) { return; } data.clip_contents = p_clip; - update(); + queue_redraw(); } bool Control::is_clipping_contents() { @@ -2261,57 +2262,9 @@ bool Control::is_clipping_contents() { // Theming. -void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign) { - Control *c = Object::cast_to<Control>(p_at); - Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr; - - if (!c && !w) { - // Theme inheritance chains are broken by nodes that aren't Control or Window. - return; - } - - bool assign = p_assign; - if (c) { - if (c != p_owner && c->data.theme.is_valid()) { - // Has a theme, so we don't want to change the theme owner, - // but we still want to propagate in case this child has theme items - // it inherits from the theme this node uses. - // See https://github.com/godotengine/godot/issues/62844. - assign = false; - } - - if (assign) { - c->data.theme_owner = p_owner; - c->data.theme_owner_window = p_owner_window; - } - - if (p_notify) { - c->notification(Control::NOTIFICATION_THEME_CHANGED); - } - } else if (w) { - if (w != p_owner_window && w->theme.is_valid()) { - // Same as above. - assign = false; - } - - if (assign) { - w->theme_owner = p_owner; - w->theme_owner_window = p_owner_window; - } - - if (p_notify) { - w->notification(Window::NOTIFICATION_THEME_CHANGED); - } - } - - for (int i = 0; i < p_at->get_child_count(); i++) { - _propagate_theme_changed(p_at->get_child(i), p_owner, p_owner_window, p_notify, assign); - } -} - void Control::_theme_changed() { if (is_inside_tree()) { - _propagate_theme_changed(this, this, nullptr, true, false); + data.theme_owner->propagate_theme_changed(this, this, true, false); } } @@ -2330,6 +2283,21 @@ void Control::_invalidate_theme_cache() { data.theme_constant_cache.clear(); } +void Control::_update_theme_item_cache() { +} + +void Control::set_theme_owner_node(Node *p_node) { + data.theme_owner->set_owner_node(p_node); +} + +Node *Control::get_theme_owner_node() const { + return data.theme_owner->get_owner_node(); +} + +bool Control::has_theme_owner_node() const { + return data.theme_owner->has_owner_node(); +} + void Control::set_theme(const Ref<Theme> &p_theme) { if (data.theme == p_theme) { return; @@ -2341,24 +2309,24 @@ void Control::set_theme(const Ref<Theme> &p_theme) { data.theme = p_theme; if (data.theme.is_valid()) { - _propagate_theme_changed(this, this, nullptr, is_inside_tree(), true); + data.theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true); data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED); return; } Control *parent_c = Object::cast_to<Control>(get_parent()); - if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { - _propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true); + if (parent_c && parent_c->has_theme_owner_node()) { + data.theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true); return; } Window *parent_w = cast_to<Window>(get_parent()); - if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { - _propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true); + if (parent_w && parent_w->has_theme_owner_node()) { + data.theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true); return; } - _propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true); + data.theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true); } Ref<Theme> Control::get_theme() const { @@ -2381,130 +2349,6 @@ StringName Control::get_theme_type_variation() const { /// Theme property lookup. -template <class T> -T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) { - ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified."); - - // First, look through each control or window node in the branch, until no valid parent can be found. - // Only nodes with a theme resource attached are considered. - Control *theme_owner = p_theme_owner; - Window *theme_owner_window = p_theme_owner_window; - - while (theme_owner || theme_owner_window) { - // For each theme resource check the theme types provided and see if p_name exists with any of them. - for (const StringName &E : p_theme_types) { - if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) { - return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E); - } - - if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) { - return theme_owner_window->theme->get_theme_item(p_data_type, p_name, E); - } - } - - Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); - Control *parent_c = Object::cast_to<Control>(parent); - if (parent_c) { - theme_owner = parent_c->data.theme_owner; - theme_owner_window = parent_c->data.theme_owner_window; - } else { - Window *parent_w = Object::cast_to<Window>(parent); - if (parent_w) { - theme_owner = parent_w->theme_owner; - theme_owner_window = parent_w->theme_owner_window; - } else { - theme_owner = nullptr; - theme_owner_window = nullptr; - } - } - } - - // Secondly, check the project-defined Theme resource. - if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { - for (const StringName &E : p_theme_types) { - if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) { - return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(p_data_type, p_name, E); - } - } - } - - // Lastly, fall back on the items defined in the default Theme, if they exist. - for (const StringName &E : p_theme_types) { - if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) { - return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, E); - } - } - // If they don't exist, use any type to return the default/empty value. - return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]); -} - -bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) { - ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified."); - - // First, look through each control or window node in the branch, until no valid parent can be found. - // Only nodes with a theme resource attached are considered. - Control *theme_owner = p_theme_owner; - Window *theme_owner_window = p_theme_owner_window; - - while (theme_owner || theme_owner_window) { - // For each theme resource check the theme types provided and see if p_name exists with any of them. - for (const StringName &E : p_theme_types) { - if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) { - return true; - } - - if (theme_owner_window && theme_owner_window->theme->has_theme_item(p_data_type, p_name, E)) { - return true; - } - } - - Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); - Control *parent_c = Object::cast_to<Control>(parent); - if (parent_c) { - theme_owner = parent_c->data.theme_owner; - theme_owner_window = parent_c->data.theme_owner_window; - } else { - Window *parent_w = Object::cast_to<Window>(parent); - if (parent_w) { - theme_owner = parent_w->theme_owner; - theme_owner_window = parent_w->theme_owner_window; - } else { - theme_owner = nullptr; - theme_owner_window = nullptr; - } - } - } - - // Secondly, check the project-defined Theme resource. - if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { - for (const StringName &E : p_theme_types) { - if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) { - return true; - } - } - } - - // Lastly, fall back on the items defined in the default Theme, if they exist. - for (const StringName &E : p_theme_types) { - if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) { - return true; - } - } - return false; -} - -void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const { - if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) { - if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(data.theme_type_variation) != StringName()) { - ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list); - } else { - ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list); - } - } else { - ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list); - } -} - Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) { const Ref<Texture2D> *tex = data.icon_override.getptr(p_name); @@ -2518,8 +2362,8 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - Ref<Texture2D> icon = get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<Texture2D> icon = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); data.theme_icon_cache[p_theme_type][p_name] = icon; return icon; } @@ -2537,8 +2381,8 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - Ref<StyleBox> style = get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<StyleBox> style = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); data.theme_style_cache[p_theme_type][p_name] = style; return style; } @@ -2556,8 +2400,8 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_ } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - Ref<Font> font = get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<Font> font = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); data.theme_font_cache[p_theme_type][p_name] = font; return font; } @@ -2575,8 +2419,8 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - int font_size = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + int font_size = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); data.theme_font_size_cache[p_theme_type][p_name] = font_size; return font_size; } @@ -2594,8 +2438,8 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - Color color = get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Color color = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); data.theme_color_cache[p_theme_type][p_name] = color; return color; } @@ -2613,8 +2457,8 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - int constant = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + int constant = data.theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); data.theme_constant_cache[p_theme_type][p_name] = constant; return constant; } @@ -2627,8 +2471,8 @@ bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); } bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { @@ -2639,8 +2483,8 @@ bool Control::has_theme_stylebox(const StringName &p_name, const StringName &p_t } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); } bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const { @@ -2651,8 +2495,8 @@ bool Control::has_theme_font(const StringName &p_name, const StringName &p_theme } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); } bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { @@ -2663,8 +2507,8 @@ bool Control::has_theme_font_size(const StringName &p_name, const StringName &p_ } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); } bool Control::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const { @@ -2675,8 +2519,8 @@ bool Control::has_theme_color(const StringName &p_name, const StringName &p_them } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); } bool Control::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { @@ -2687,8 +2531,8 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t } List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + data.theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return data.theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); } /// Local property overrides. @@ -2818,157 +2662,16 @@ bool Control::has_theme_constant_override(const StringName &p_name) const { /// Default theme properties. -float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) { - // First, look through each control or window node in the branch, until no valid parent can be found. - // Only nodes with a theme resource attached are considered. - // For each theme resource see if their assigned theme has the default value defined and valid. - Control *theme_owner = p_theme_owner; - Window *theme_owner_window = p_theme_owner_window; - - while (theme_owner || theme_owner_window) { - if (theme_owner && theme_owner->data.theme->has_default_base_scale()) { - return theme_owner->data.theme->get_default_base_scale(); - } - - if (theme_owner_window && theme_owner_window->theme->has_default_base_scale()) { - return theme_owner_window->theme->get_default_base_scale(); - } - - Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); - Control *parent_c = Object::cast_to<Control>(parent); - if (parent_c) { - theme_owner = parent_c->data.theme_owner; - theme_owner_window = parent_c->data.theme_owner_window; - } else { - Window *parent_w = Object::cast_to<Window>(parent); - if (parent_w) { - theme_owner = parent_w->theme_owner; - theme_owner_window = parent_w->theme_owner_window; - } else { - theme_owner = nullptr; - theme_owner_window = nullptr; - } - } - } - - // Secondly, check the project-defined Theme resource. - if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { - if (ThemeDB::get_singleton()->get_project_theme()->has_default_base_scale()) { - return ThemeDB::get_singleton()->get_project_theme()->get_default_base_scale(); - } - } - - // Lastly, fall back on the default Theme. - if (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) { - return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale(); - } - return ThemeDB::get_singleton()->get_fallback_base_scale(); -} - float Control::get_theme_default_base_scale() const { - return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window); -} - -Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) { - // First, look through each control or window node in the branch, until no valid parent can be found. - // Only nodes with a theme resource attached are considered. - // For each theme resource see if their assigned theme has the default value defined and valid. - Control *theme_owner = p_theme_owner; - Window *theme_owner_window = p_theme_owner_window; - - while (theme_owner || theme_owner_window) { - if (theme_owner && theme_owner->data.theme->has_default_font()) { - return theme_owner->data.theme->get_default_font(); - } - - if (theme_owner_window && theme_owner_window->theme->has_default_font()) { - return theme_owner_window->theme->get_default_font(); - } - - Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); - Control *parent_c = Object::cast_to<Control>(parent); - if (parent_c) { - theme_owner = parent_c->data.theme_owner; - theme_owner_window = parent_c->data.theme_owner_window; - } else { - Window *parent_w = Object::cast_to<Window>(parent); - if (parent_w) { - theme_owner = parent_w->theme_owner; - theme_owner_window = parent_w->theme_owner_window; - } else { - theme_owner = nullptr; - theme_owner_window = nullptr; - } - } - } - - // Secondly, check the project-defined Theme resource. - if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { - if (ThemeDB::get_singleton()->get_project_theme()->has_default_font()) { - return ThemeDB::get_singleton()->get_project_theme()->get_default_font(); - } - } - - // Lastly, fall back on the default Theme. - if (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) { - return ThemeDB::get_singleton()->get_default_theme()->get_default_font(); - } - return ThemeDB::get_singleton()->get_fallback_font(); + return data.theme_owner->get_theme_default_base_scale(); } Ref<Font> Control::get_theme_default_font() const { - return fetch_theme_default_font(data.theme_owner, data.theme_owner_window); -} - -int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) { - // First, look through each control or window node in the branch, until no valid parent can be found. - // Only nodes with a theme resource attached are considered. - // For each theme resource see if their assigned theme has the default value defined and valid. - Control *theme_owner = p_theme_owner; - Window *theme_owner_window = p_theme_owner_window; - - while (theme_owner || theme_owner_window) { - if (theme_owner && theme_owner->data.theme->has_default_font_size()) { - return theme_owner->data.theme->get_default_font_size(); - } - - if (theme_owner_window && theme_owner_window->theme->has_default_font_size()) { - return theme_owner_window->theme->get_default_font_size(); - } - - Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent(); - Control *parent_c = Object::cast_to<Control>(parent); - if (parent_c) { - theme_owner = parent_c->data.theme_owner; - theme_owner_window = parent_c->data.theme_owner_window; - } else { - Window *parent_w = Object::cast_to<Window>(parent); - if (parent_w) { - theme_owner = parent_w->theme_owner; - theme_owner_window = parent_w->theme_owner_window; - } else { - theme_owner = nullptr; - theme_owner_window = nullptr; - } - } - } - - // Secondly, check the project-defined Theme resource. - if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { - if (ThemeDB::get_singleton()->get_project_theme()->has_default_font_size()) { - return ThemeDB::get_singleton()->get_project_theme()->get_default_font_size(); - } - } - - // Lastly, fall back on the default Theme. - if (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) { - return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size(); - } - return ThemeDB::get_singleton()->get_fallback_font_size(); + return data.theme_owner->get_theme_default_font(); } int Control::get_theme_default_font_size() const { - return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window); + return data.theme_owner->get_theme_default_font_size(); } /// Bulk actions. @@ -3086,27 +2789,23 @@ Control *Control::make_custom_tooltip(const String &p_text) const { // Base object overrides. -void Control::add_child_notify(Node *p_child) { - // We propagate when this node uses a custom theme, so it can pass it on to its children. - if (data.theme_owner || data.theme_owner_window) { - // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`. - _propagate_theme_changed(p_child, data.theme_owner, data.theme_owner_window, false, true); - } -} - -void Control::remove_child_notify(Node *p_child) { - // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate. - if (data.theme_owner || data.theme_owner_window) { - _propagate_theme_changed(p_child, nullptr, nullptr, false, true); - } -} - void Control::_notification(int p_notification) { switch (p_notification) { + case NOTIFICATION_POSTINITIALIZE: { + _invalidate_theme_cache(); + _update_theme_item_cache(); + } break; + + case NOTIFICATION_PARENTED: { + data.theme_owner->assign_theme_on_parented(this); + } break; + + case NOTIFICATION_UNPARENTED: { + data.theme_owner->clear_theme_on_unparented(this); + } break; + case NOTIFICATION_ENTER_TREE: { - // Need to defer here, because theme owner information might be set in - // add_child_notify, which doesn't get called until right after this. - call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED); + notification(NOTIFICATION_THEME_CHANGED); } break; case NOTIFICATION_POST_ENTER_TREE: { @@ -3122,7 +2821,7 @@ void Control::_notification(int p_notification) { case NOTIFICATION_READY: { #ifdef DEBUG_ENABLED - connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONESHOT); + connect("ready", callable_mp(this, &Control::_clear_size_warning), CONNECT_DEFERRED | CONNECT_ONE_SHOT); #endif } break; @@ -3196,9 +2895,9 @@ void Control::_notification(int p_notification) { // some parents need to know the order of the children to draw (like TabContainer) // update if necessary if (data.parent) { - data.parent->update(); + data.parent->queue_redraw(); } - update(); + queue_redraw(); if (data.RI) { get_viewport()->_gui_set_root_order_dirty(); @@ -3225,19 +2924,20 @@ void Control::_notification(int p_notification) { case NOTIFICATION_FOCUS_ENTER: { emit_signal(SceneStringNames::get_singleton()->focus_entered); - update(); + queue_redraw(); } break; case NOTIFICATION_FOCUS_EXIT: { emit_signal(SceneStringNames::get_singleton()->focus_exited); - update(); + queue_redraw(); } break; case NOTIFICATION_THEME_CHANGED: { emit_signal(SceneStringNames::get_singleton()->theme_changed); _invalidate_theme_cache(); + _update_theme_item_cache(); update_minimum_size(); - update(); + queue_redraw(); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -3257,6 +2957,7 @@ void Control::_notification(int p_notification) { if (is_inside_tree()) { data.is_rtl_dirty = true; _invalidate_theme_cache(); + _update_theme_item_cache(); _size_changed(); } } break; @@ -3431,7 +3132,7 @@ void Control::_bind_methods() { ADD_GROUP("Layout", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "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_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode"); ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION); @@ -3445,10 +3146,10 @@ void Control::_bind_methods() { ADD_PROPERTY_DEFAULT("anchors_preset", -1); ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_less,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM); ADD_SUBGROUP_INDENT("Anchor Offsets", "offset_", 1); ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_left", PROPERTY_HINT_RANGE, "-4096,4096,suffix:px"), "set_offset", "get_offset", SIDE_LEFT); @@ -3464,7 +3165,7 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "_set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "suffix:px", 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::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "pivot_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_pivot_offset", "get_pivot_offset"); @@ -3601,7 +3302,13 @@ void Control::_bind_methods() { GDVIRTUAL_BIND(_gui_input, "event"); } +Control::Control() { + data.theme_owner = memnew(ThemeOwner); +} + Control::~Control() { + memdelete(data.theme_owner); + // Resources need to be disconnected. for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) { E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); diff --git a/scene/gui/control.h b/scene/gui/control.h index 6215594ae0..38cafd835a 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -41,6 +41,7 @@ class Viewport; class Label; class Panel; +class ThemeOwner; class Control : public CanvasItem { GDCLASS(Control, CanvasItem); @@ -199,7 +200,7 @@ private: int h_size_flags = SIZE_FILL; int v_size_flags = SIZE_FILL; real_t expand = 1.0; - Point2 custom_minimum_size; + Point2i custom_minimum_size; // Input events and rendering. @@ -219,9 +220,8 @@ private: // Theming. + ThemeOwner *theme_owner = nullptr; Ref<Theme> theme; - Control *theme_owner = nullptr; - Window *theme_owner_window = nullptr; StringName theme_type_variation; bool bulk_theme_override = false; @@ -261,7 +261,6 @@ private: // Global relations. friend class Viewport; - friend class Window; // Positioning and sizing. @@ -303,13 +302,6 @@ private: void _notify_theme_override_changed(); void _invalidate_theme_cache(); - static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign); - - template <class T> - static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); - static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); - _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const; - // Extra properties. String get_tooltip_text() const; @@ -325,15 +317,16 @@ protected: bool _property_can_revert(const StringName &p_name) const; bool _property_get_revert(const StringName &p_name, Variant &r_property) const; + // Theming. + + virtual void _update_theme_item_cache(); + // Internationalization. virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; // Base object overrides. - virtual void add_child_notify(Node *p_child) override; - virtual void remove_child_notify(Node *p_child) override; - void _notification(int p_notification); static void _bind_methods(); @@ -467,8 +460,8 @@ public: virtual Size2 get_minimum_size() const; virtual Size2 get_combined_minimum_size() const; - void set_custom_minimum_size(const Size2 &p_custom); - Size2 get_custom_minimum_size() const; + void set_custom_minimum_size(const Size2i &p_custom); + Size2i get_custom_minimum_size() const; // Container sizing. @@ -538,6 +531,10 @@ public: // Theming. + void set_theme_owner_node(Node *p_node); + Node *get_theme_owner_node() const; + bool has_theme_owner_node() const; + void set_theme(const Ref<Theme> &p_theme); Ref<Theme> get_theme() const; @@ -582,10 +579,6 @@ public: bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const; bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const; - static float fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window); - static Ref<Font> fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window); - static int fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window); - float get_theme_default_base_scale() const; Ref<Font> get_theme_default_font() const; int get_theme_default_font_size() const; @@ -608,7 +601,7 @@ public: virtual String get_tooltip(const Point2 &p_pos) const; virtual Control *make_custom_tooltip(const String &p_text) const; - Control() {} + Control(); ~Control(); }; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index b4e0747ab8..f5edaf02d8 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -50,12 +50,27 @@ void AcceptDialog::_parent_focused() { } } +void AcceptDialog::_update_theme_item_cache() { + Window::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); + theme_cache.buttons_separation = get_theme_constant(SNAME("buttons_separation")); +} + void AcceptDialog::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_VISIBILITY_CHANGED: { + case NOTIFICATION_POST_ENTER_TREE: { if (is_visible()) { get_ok_button()->grab_focus(); + } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible()) { + if (get_ok_button()->is_inside_tree()) { + get_ok_button()->grab_focus(); + } _update_child_rects(); + parent_visible = get_parent_visible_window(); if (parent_visible) { parent_visible->connect("focus_entered", callable_mp(this, &AcceptDialog::_parent_focused)); @@ -69,7 +84,12 @@ 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"))); + bg_panel->add_theme_style_override("panel", theme_cache.panel_style); + + child_controls_changed(); + if (is_visible()) { + _update_child_rects(); + } } break; case NOTIFICATION_EXIT_TREE: { @@ -126,14 +146,16 @@ void AcceptDialog::_cancel_pressed() { } String AcceptDialog::get_text() const { - return label->get_text(); + return message_label->get_text(); } void AcceptDialog::set_text(String p_text) { - if (label->get_text() == p_text) { + if (message_label->get_text() == p_text) { return; } - label->set_text(p_text); + + message_label->set_text(p_text); + child_controls_changed(); if (is_visible()) { _update_child_rects(); @@ -157,19 +179,24 @@ bool AcceptDialog::get_close_on_escape() const { } void AcceptDialog::set_autowrap(bool p_autowrap) { - label->set_autowrap_mode(p_autowrap ? TextServer::AUTOWRAP_WORD : TextServer::AUTOWRAP_OFF); + message_label->set_autowrap_mode(p_autowrap ? TextServer::AUTOWRAP_WORD : TextServer::AUTOWRAP_OFF); } bool AcceptDialog::has_autowrap() { - return label->get_autowrap_mode() != TextServer::AUTOWRAP_OFF; + return message_label->get_autowrap_mode() != TextServer::AUTOWRAP_OFF; } void AcceptDialog::set_ok_button_text(String p_ok_button_text) { - ok->set_text(p_ok_button_text); + ok_button->set_text(p_ok_button_text); + + child_controls_changed(); + if (is_visible()) { + _update_child_rects(); + } } String AcceptDialog::get_ok_button_text() const { - return ok->get_text(); + return ok_button->get_text(); } void AcceptDialog::register_text_enter(Control *p_line_edit) { @@ -181,69 +208,79 @@ void AcceptDialog::register_text_enter(Control *p_line_edit) { } void AcceptDialog::_update_child_rects() { - Size2 label_size = label->get_minimum_size(); - if (label->get_text().is_empty()) { - label_size.height = 0; - } - int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs")); Size2 size = get_size(); - Size2 hminsize = hbc->get_combined_minimum_size(); + float h_margins = theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT); + float v_margins = theme_cache.panel_style->get_margin(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_BOTTOM); + + // Fill the entire size of the window with the background. + bg_panel->set_position(Point2()); + bg_panel->set_size(size); + + // Place the buttons from the bottom edge to their minimum required size. + Size2 buttons_minsize = buttons_hbox->get_combined_minimum_size(); + Size2 buttons_size = Size2(size.x - h_margins, buttons_minsize.y); + Point2 buttons_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), size.y - theme_cache.panel_style->get_margin(SIDE_BOTTOM) - buttons_size.y); + buttons_hbox->set_position(buttons_position); + buttons_hbox->set_size(buttons_size); - Vector2 cpos(margin, margin + label_size.height); - Vector2 csize(size.x - margin * 2, size.y - margin * 3 - hminsize.y - label_size.height); + // Place the content from the top to fill the rest of the space (minus the separation). + Point2 content_position = Point2(theme_cache.panel_style->get_margin(SIDE_LEFT), theme_cache.panel_style->get_margin(SIDE_TOP)); + Size2 content_size = Size2(size.x - h_margins, size.y - v_margins - buttons_size.y - theme_cache.buttons_separation); for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); if (!c) { continue; } - - if (c == hbc || c == label || c == bg || c->is_set_as_top_level()) { + if (c == buttons_hbox || c == bg_panel || c->is_set_as_top_level()) { continue; } - c->set_position(cpos); - c->set_size(csize); + c->set_position(content_position); + c->set_size(content_size); } - - cpos.y += csize.y + margin; - csize.y = hminsize.y; - - hbc->set_position(cpos); - hbc->set_size(csize); - - bg->set_position(Point2()); - bg->set_size(size); } Size2 AcceptDialog::_get_contents_minimum_size() const { - int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs")); - Size2 minsize = label->get_combined_minimum_size(); - + // First, we then iterate over the label and any other custom controls + // to try and find the size that encompasses all content. + Size2 content_minsize; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); if (!c) { continue; } - if (c == hbc || c == label || c->is_set_as_top_level()) { + // Buttons will be included afterwards. + // The panel only displays the stylebox and doesn't contribute to the size. + if (c == buttons_hbox || c == bg_panel || c->is_set_as_top_level()) { continue; } - Size2 cminsize = c->get_combined_minimum_size(); - minsize.x = MAX(cminsize.x, minsize.x); - minsize.y = MAX(cminsize.y, minsize.y); + Size2 child_minsize = c->get_combined_minimum_size(); + content_minsize.x = MAX(child_minsize.x, content_minsize.x); + content_minsize.y = MAX(child_minsize.y, content_minsize.y); + } + + // Then we take the background panel as it provides the offsets, + // which are always added to the minimum size. + if (theme_cache.panel_style.is_valid()) { + content_minsize += theme_cache.panel_style->get_minimum_size(); } - Size2 hminsize = hbc->get_combined_minimum_size(); - minsize.x = MAX(hminsize.x, minsize.x); - minsize.y += hminsize.y; - minsize.x += margin * 2; - minsize.y += margin * 3; //one as separation between hbc and child + // Then we add buttons. Horizontally we're interested in whichever + // value is the biggest. Vertically buttons add to the overall size. + Size2 buttons_minsize = buttons_hbox->get_combined_minimum_size(); + content_minsize.x = MAX(buttons_minsize.x, content_minsize.x); + content_minsize.y += buttons_minsize.y; + // Plus there is a separation size added on top. + content_minsize.y += theme_cache.buttons_separation; - Size2 wmsize = get_min_size(); - minsize.x = MAX(wmsize.x, minsize.x); - return minsize; + // Last, we make sure that we aren't below the minimum window size. + Size2 window_minsize = get_min_size(); + content_minsize.x = MAX(window_minsize.x, content_minsize.x); + content_minsize.y = MAX(window_minsize.y, content_minsize.y); + return content_minsize; } void AcceptDialog::_custom_action(const String &p_action) { @@ -254,13 +291,19 @@ void AcceptDialog::_custom_action(const String &p_action) { Button *AcceptDialog::add_button(const String &p_text, bool p_right, const String &p_action) { Button *button = memnew(Button); button->set_text(p_text); + if (p_right) { - hbc->add_child(button); - hbc->add_spacer(); + buttons_hbox->add_child(button); + buttons_hbox->add_spacer(); } else { - hbc->add_child(button); - hbc->move_child(button, 0); - hbc->add_spacer(true); + buttons_hbox->add_child(button); + buttons_hbox->move_child(button, 0); + buttons_hbox->add_spacer(true); + } + + child_controls_changed(); + if (is_visible()) { + _update_child_rects(); } if (!p_action.is_empty()) { @@ -275,24 +318,19 @@ Button *AcceptDialog::add_cancel_button(const String &p_cancel) { if (p_cancel.is_empty()) { c = "Cancel"; } + Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c); + b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); + return b; } void AcceptDialog::remove_button(Control *p_button) { Button *button = Object::cast_to<Button>(p_button); ERR_FAIL_NULL(button); - ERR_FAIL_COND_MSG(button->get_parent() != hbc, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name())); - ERR_FAIL_COND_MSG(button == ok, "Cannot remove dialog's OK button."); - - Node *right_spacer = hbc->get_child(button->get_index() + 1); - // Should always be valid but let's avoid crashing - if (right_spacer) { - hbc->remove_child(right_spacer); - memdelete(right_spacer); - } - hbc->remove_child(button); + ERR_FAIL_COND_MSG(button->get_parent() != buttons_hbox, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name())); + ERR_FAIL_COND_MSG(button == ok_button, "Cannot remove dialog's OK button."); if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_custom_action))) { button->disconnect("pressed", callable_mp(this, &AcceptDialog::_custom_action)); @@ -300,6 +338,19 @@ void AcceptDialog::remove_button(Control *p_button) { if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed))) { button->disconnect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); } + + Node *right_spacer = buttons_hbox->get_child(button->get_index() + 1); + // Should always be valid but let's avoid crashing. + if (right_spacer) { + buttons_hbox->remove_child(right_spacer); + memdelete(right_spacer); + } + buttons_hbox->remove_child(button); + + child_controls_changed(); + if (is_visible()) { + _update_child_rects(); + } } void AcceptDialog::_bind_methods() { @@ -345,30 +396,25 @@ AcceptDialog::AcceptDialog() { set_exclusive(true); set_clamp_to_embedder(true); - bg = memnew(Panel); - add_child(bg, false, INTERNAL_MODE_FRONT); - - hbc = memnew(HBoxContainer); + bg_panel = memnew(Panel); + add_child(bg_panel, false, INTERNAL_MODE_FRONT); - int margin = hbc->get_theme_constant(SNAME("margin"), SNAME("Dialogs")); - int button_margin = hbc->get_theme_constant(SNAME("button_margin"), SNAME("Dialogs")); + buttons_hbox = memnew(HBoxContainer); - label = memnew(Label); - label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END); - label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END); - label->set_begin(Point2(margin, margin)); - label->set_end(Point2(-margin, -button_margin - 10)); - add_child(label, false, INTERNAL_MODE_FRONT); + message_label = memnew(Label); + message_label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END); + message_label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END); + add_child(message_label, false, INTERNAL_MODE_FRONT); - add_child(hbc, false, INTERNAL_MODE_FRONT); + add_child(buttons_hbox, false, INTERNAL_MODE_FRONT); - hbc->add_spacer(); - ok = memnew(Button); - ok->set_text("OK"); - hbc->add_child(ok); - hbc->add_spacer(); + buttons_hbox->add_spacer(); + ok_button = memnew(Button); + ok_button->set_text("OK"); + buttons_hbox->add_child(ok_button); + buttons_hbox->add_spacer(); - ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed)); + ok_button->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed)); set_title(TTRC("Alert!")); diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 9ebf5ddfb2..81e82d851e 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -45,13 +45,20 @@ class AcceptDialog : public Window { GDCLASS(AcceptDialog, Window); Window *parent_visible = nullptr; - Panel *bg = nullptr; - HBoxContainer *hbc = nullptr; - Label *label = nullptr; - Button *ok = nullptr; + + Panel *bg_panel = nullptr; + Label *message_label = nullptr; + HBoxContainer *buttons_hbox = nullptr; + Button *ok_button = nullptr; + bool hide_on_ok = true; bool close_on_escape = true; + struct ThemeCache { + Ref<StyleBox> panel_style; + int buttons_separation = 0; + } theme_cache; + void _custom_action(const String &p_action); void _update_child_rects(); @@ -62,6 +69,7 @@ class AcceptDialog : public Window { protected: virtual Size2 _get_contents_minimum_size() const override; + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); @@ -75,12 +83,12 @@ protected: void _cancel_pressed(); public: - Label *get_label() { return label; } + Label *get_label() { return message_label; } static void set_swap_cancel_ok(bool p_swap); void register_text_enter(Control *p_line_edit); - Button *get_ok_button() { return ok; } + Button *get_ok_button() { return ok_button; } Button *add_button(const String &p_text, bool p_right = false, const String &p_action = ""); Button *add_cancel_button(const String &p_cancel = ""); void remove_button(Control *p_button); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 57655afb4c..57f27e299f 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -59,36 +59,26 @@ VBoxContainer *FileDialog::get_vbox() { return vbox; } -void FileDialog::_theme_changed() { - Color font_color = vbox->get_theme_color(SNAME("font_color"), SNAME("Button")); - Color font_hover_color = vbox->get_theme_color(SNAME("font_hover_color"), SNAME("Button")); - Color font_focus_color = vbox->get_theme_color(SNAME("font_focus_color"), SNAME("Button")); - Color font_pressed_color = vbox->get_theme_color(SNAME("font_pressed_color"), SNAME("Button")); - - dir_up->add_theme_color_override("icon_normal_color", font_color); - dir_up->add_theme_color_override("icon_hover_color", font_hover_color); - dir_up->add_theme_color_override("icon_focus_color", font_focus_color); - dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color); - - dir_prev->add_theme_color_override("icon_color_normal", font_color); - dir_prev->add_theme_color_override("icon_color_hover", font_hover_color); - dir_prev->add_theme_color_override("icon_focus_color", font_focus_color); - dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color); - - dir_next->add_theme_color_override("icon_color_normal", font_color); - dir_next->add_theme_color_override("icon_color_hover", font_hover_color); - dir_next->add_theme_color_override("icon_focus_color", font_focus_color); - dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color); - - refresh->add_theme_color_override("icon_normal_color", font_color); - refresh->add_theme_color_override("icon_hover_color", font_hover_color); - refresh->add_theme_color_override("icon_focus_color", font_focus_color); - refresh->add_theme_color_override("icon_pressed_color", font_pressed_color); - - show_hidden->add_theme_color_override("icon_normal_color", font_color); - show_hidden->add_theme_color_override("icon_hover_color", font_hover_color); - show_hidden->add_theme_color_override("icon_focus_color", font_focus_color); - show_hidden->add_theme_color_override("icon_pressed_color", font_pressed_color); +void FileDialog::_update_theme_item_cache() { + ConfirmationDialog::_update_theme_item_cache(); + + theme_cache.parent_folder = get_theme_icon(SNAME("parent_folder")); + theme_cache.forward_folder = get_theme_icon(SNAME("forward_folder")); + theme_cache.back_folder = get_theme_icon(SNAME("back_folder")); + theme_cache.reload = get_theme_icon(SNAME("reload")); + theme_cache.toggle_hidden = get_theme_icon(SNAME("toggle_hidden")); + theme_cache.folder = get_theme_icon(SNAME("folder")); + theme_cache.file = get_theme_icon(SNAME("file")); + + theme_cache.folder_icon_color = get_theme_color(SNAME("folder_icon_color")); + theme_cache.file_icon_color = get_theme_color(SNAME("file_icon_color")); + theme_cache.file_disabled_color = get_theme_color(SNAME("file_disabled_color")); + + // TODO: Define own colors? + theme_cache.icon_normal_color = get_theme_color(SNAME("font_color"), SNAME("Button")); + theme_cache.icon_hover_color = get_theme_color(SNAME("font_hover_color"), SNAME("Button")); + theme_cache.icon_focus_color = get_theme_color(SNAME("font_focus_color"), SNAME("Button")); + theme_cache.icon_pressed_color = get_theme_color(SNAME("font_pressed_color"), SNAME("Button")); } void FileDialog::_notification(int p_what) { @@ -97,20 +87,46 @@ void FileDialog::_notification(int p_what) { if (!is_visible()) { set_process_shortcut_input(false); } + + invalidate(); // Put it here to preview in the editor. } break; - case NOTIFICATION_ENTER_TREE: { - dir_up->set_icon(vbox->get_theme_icon(SNAME("parent_folder"), SNAME("FileDialog"))); + case NOTIFICATION_THEME_CHANGED: { + dir_up->set_icon(theme_cache.parent_folder); 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"))); + dir_prev->set_icon(theme_cache.forward_folder); + dir_next->set_icon(theme_cache.back_folder); } 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"))); + dir_prev->set_icon(theme_cache.back_folder); + dir_next->set_icon(theme_cache.forward_folder); } - 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(); + refresh->set_icon(theme_cache.reload); + show_hidden->set_icon(theme_cache.toggle_hidden); + + dir_up->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color); + dir_up->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color); + dir_up->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); + dir_up->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color); + + dir_prev->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color); + dir_prev->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color); + dir_prev->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); + dir_prev->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color); + + dir_next->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color); + dir_next->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color); + dir_next->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); + dir_next->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color); + + refresh->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color); + refresh->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color); + refresh->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); + refresh->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color); + + show_hidden->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color); + show_hidden->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color); + show_hidden->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); + show_hidden->add_theme_color_override("icon_pressed_color", theme_cache.icon_pressed_color); } break; case NOTIFICATION_TRANSLATION_CHANGED: { @@ -129,7 +145,7 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) { switch (k->get_keycode()) { case Key::H: { - if (k->is_command_pressed()) { + if (k->is_command_or_control_pressed()) { set_show_hidden_files(!show_hidden_files); } else { handled = false; @@ -163,7 +179,7 @@ Vector<String> FileDialog::get_selected_files() const { TreeItem *item = tree->get_root(); while ((item = tree->get_next_selected(item))) { - list.push_back(dir_access->get_current_dir().plus_file(item->get_text(0))); + list.push_back(dir_access->get_current_dir().path_join(item->get_text(0))); }; return list; @@ -192,7 +208,7 @@ void FileDialog::update_dir() { } void FileDialog::_dir_submitted(String p_dir) { - _change_dir(root_prefix.plus_file(p_dir)); + _change_dir(root_prefix.path_join(p_dir)); file->set_text(""); _push_history(); } @@ -202,17 +218,13 @@ void FileDialog::_file_submitted(const String &p_file) { } void FileDialog::_save_confirm_pressed() { - String f = dir_access->get_current_dir().plus_file(file->get_text()); + String f = dir_access->get_current_dir().path_join(file->get_text()); emit_signal(SNAME("file_selected"), f); hide(); } void FileDialog::_post_popup() { ConfirmationDialog::_post_popup(); - if (invalidated) { - update_file_list(); - invalidated = false; - } if (mode == FILE_MODE_SAVE_FILE) { file->grab_focus(); } else { @@ -252,7 +264,7 @@ void FileDialog::_action_pressed() { Vector<String> files; while (ti) { - files.push_back(fbase.plus_file(ti->get_text(0))); + files.push_back(fbase.path_join(ti->get_text(0))); ti = tree->get_next_selected(ti); } @@ -265,7 +277,7 @@ void FileDialog::_action_pressed() { } String file_text = file->get_text(); - String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text); + String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text); if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) { emit_signal(SNAME("file_selected"), f); @@ -278,7 +290,7 @@ void FileDialog::_action_pressed() { if (item) { Dictionary d = item->get_metadata(0); if (d["dir"] && d["name"] != "..") { - path = path.plus_file(d["name"]); + path = path.path_join(d["name"]); } } @@ -506,10 +518,6 @@ void FileDialog::update_file_list() { } TreeItem *root = tree->create_item(); - Ref<Texture2D> folder = vbox->get_theme_icon(SNAME("folder"), SNAME("FileDialog")); - Ref<Texture2D> file_icon = vbox->get_theme_icon(SNAME("file"), SNAME("FileDialog")); - const Color folder_color = vbox->get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")); - const Color file_color = vbox->get_theme_color(SNAME("file_icon_modulate"), SNAME("FileDialog")); List<String> files; List<String> dirs; @@ -541,8 +549,8 @@ void FileDialog::update_file_list() { String &dir_name = dirs.front()->get(); TreeItem *ti = tree->create_item(root); ti->set_text(0, dir_name); - ti->set_icon(0, folder); - ti->set_icon_modulate(0, folder_color); + ti->set_icon(0, theme_cache.folder); + ti->set_icon_modulate(0, theme_cache.folder_icon_color); Dictionary d; d["name"] = dir_name; @@ -598,15 +606,15 @@ void FileDialog::update_file_list() { ti->set_text(0, files.front()->get()); if (get_icon_func) { - Ref<Texture2D> icon = get_icon_func(base_dir.plus_file(files.front()->get())); + Ref<Texture2D> icon = get_icon_func(base_dir.path_join(files.front()->get())); ti->set_icon(0, icon); } else { - ti->set_icon(0, file_icon); + ti->set_icon(0, theme_cache.file); } - ti->set_icon_modulate(0, file_color); + ti->set_icon_modulate(0, theme_cache.file_icon_color); if (mode == FILE_MODE_OPEN_DIR) { - ti->set_custom_color(0, vbox->get_theme_color(SNAME("files_disabled"), SNAME("FileDialog"))); + ti->set_custom_color(0, theme_cache.file_disabled_color); ti->set_selectable(0, false); } Dictionary d; @@ -706,7 +714,7 @@ String FileDialog::get_current_file() const { } String FileDialog::get_current_path() const { - return dir->get_text().plus_file(file->get_text()); + return dir->get_text().path_join(file->get_text()); } void FileDialog::set_current_dir(const String &p_dir) { @@ -1006,7 +1014,6 @@ FileDialog::FileDialog() { vbox = memnew(VBoxContainer); add_child(vbox, false, INTERNAL_MODE_FRONT); - vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed)); mode = FILE_MODE_SAVE_FILE; set_title(TTRC("Save a File")); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 4945094086..1add0a9cf5 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -109,6 +109,25 @@ private: bool invalidated = true; + struct ThemeCache { + Ref<Texture2D> parent_folder; + Ref<Texture2D> forward_folder; + Ref<Texture2D> back_folder; + Ref<Texture2D> reload; + Ref<Texture2D> toggle_hidden; + Ref<Texture2D> folder; + Ref<Texture2D> file; + + Color folder_icon_color; + Color file_icon_color; + Color file_disabled_color; + + Color icon_normal_color; + Color icon_hover_color; + Color icon_focus_color; + Color icon_pressed_color; + } theme_cache; + void update_dir(); void update_file_name(); void update_file_list(); @@ -143,7 +162,7 @@ private: virtual void _post_popup() override; protected: - void _theme_changed(); + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp index 30b694da76..b0d15aa7f4 100644 --- a/scene/gui/flow_container.cpp +++ b/scene/gui/flow_container.cpp @@ -44,9 +44,6 @@ void FlowContainer::_resort() { return; } - int separation_horizontal = get_theme_constant(SNAME("h_separation")); - int separation_vertical = get_theme_constant(SNAME("v_separation")); - bool rtl = is_layout_rtl(); HashMap<Control *, Size2i> children_minsize_cache; @@ -74,14 +71,14 @@ void FlowContainer::_resort() { if (vertical) { /* VERTICAL */ if (children_in_current_line > 0) { - ofs.y += separation_vertical; + ofs.y += theme_cache.v_separation; } if (ofs.y + child_msc.y > current_container_size) { - line_length = ofs.y - separation_vertical; + line_length = ofs.y - theme_cache.v_separation; lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total }); // Move in new column (vertical line). - ofs.x += line_height + separation_horizontal; + ofs.x += line_height + theme_cache.h_separation; ofs.y = 0; line_height = 0; line_stretch_ratio_total = 0; @@ -96,14 +93,14 @@ void FlowContainer::_resort() { } else { /* HORIZONTAL */ if (children_in_current_line > 0) { - ofs.x += separation_horizontal; + ofs.x += theme_cache.h_separation; } if (ofs.x + child_msc.x > current_container_size) { - line_length = ofs.x - separation_horizontal; + line_length = ofs.x - theme_cache.h_separation; lines_data.push_back(_LineData{ children_in_current_line, line_height, line_length, current_container_size - line_length, line_stretch_ratio_total }); // Move in new line. - ofs.y += line_height + separation_vertical; + ofs.y += line_height + theme_cache.v_separation; ofs.x = 0; line_height = 0; line_stretch_ratio_total = 0; @@ -146,11 +143,11 @@ void FlowContainer::_resort() { current_line_idx++; child_idx_in_line = 0; if (vertical) { - ofs.x += line_data.min_line_height + separation_horizontal; + ofs.x += line_data.min_line_height + theme_cache.h_separation; ofs.y = 0; } else { ofs.x = 0; - ofs.y += line_data.min_line_height + separation_vertical; + ofs.y += line_data.min_line_height + theme_cache.v_separation; } line_data = lines_data[current_line_idx]; } @@ -184,9 +181,9 @@ void FlowContainer::_resort() { fit_child_in_rect(child, child_rect); if (vertical) { /* VERTICAL */ - ofs.y += child_size.height + separation_vertical; + ofs.y += child_size.height + theme_cache.v_separation; } else { /* HORIZONTAL */ - ofs.x += child_size.width + separation_horizontal; + ofs.x += child_size.width + theme_cache.h_separation; } child_idx_in_line++; @@ -250,6 +247,13 @@ Vector<int> FlowContainer::get_allowed_size_flags_vertical() const { return flags; } +void FlowContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + theme_cache.v_separation = get_theme_constant(SNAME("v_separation")); +} + void FlowContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { @@ -268,14 +272,36 @@ void FlowContainer::_notification(int p_what) { } } +void FlowContainer::_validate_property(PropertyInfo &p_property) const { + if (is_fixed && p_property.name == "vertical") { + p_property.usage = PROPERTY_USAGE_NONE; + } +} + int FlowContainer::get_line_count() const { return cached_line_count; } +void FlowContainer::set_vertical(bool p_vertical) { + ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + "."); + vertical = p_vertical; + update_minimum_size(); + _resort(); +} + +bool FlowContainer::is_vertical() const { + return vertical; +} + FlowContainer::FlowContainer(bool p_vertical) { vertical = p_vertical; } void FlowContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line_count"), &FlowContainer::get_line_count); + + ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &FlowContainer::set_vertical); + ClassDB::bind_method(D_METHOD("is_vertical"), &FlowContainer::is_vertical); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h index a2da43e071..536df27ad6 100644 --- a/scene/gui/flow_container.h +++ b/scene/gui/flow_container.h @@ -42,16 +42,28 @@ private: bool vertical = false; + struct ThemeCache { + int h_separation = 0; + int v_separation = 0; + } theme_cache; + void _resort(); protected: - void _notification(int p_what); + bool is_fixed = false; + + virtual void _update_theme_item_cache() override; + void _notification(int p_what); + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: int get_line_count() const; + void set_vertical(bool p_vertical); + bool is_vertical() const; + virtual Size2 get_minimum_size() const override; virtual Vector<int> get_allowed_size_flags_horizontal() const override; @@ -65,7 +77,7 @@ class HFlowContainer : public FlowContainer { public: HFlowContainer() : - FlowContainer(false) {} + FlowContainer(false) { is_fixed = true; } }; class VFlowContainer : public FlowContainer { @@ -73,7 +85,7 @@ class VFlowContainer : public FlowContainer { public: VFlowContainer() : - FlowContainer(true) {} + FlowContainer(true) { is_fixed = true; } }; #endif // FLOW_CONTAINER_H diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp deleted file mode 100644 index cc27a6b7c2..0000000000 --- a/scene/gui/gradient_edit.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/*************************************************************************/ -/* gradient_edit.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "gradient_edit.h" - -#include "core/os/keyboard.h" - -GradientEdit::GradientEdit() { - set_focus_mode(FOCUS_ALL); - - popup = memnew(PopupPanel); - picker = memnew(ColorPicker); - popup->add_child(picker); - - gradient_cache.instantiate(); - preview_texture.instantiate(); - - preview_texture->set_width(1024); - add_child(popup, false, INTERNAL_MODE_FRONT); -} - -int GradientEdit::_get_point_from_pos(int x) { - int result = -1; - int total_w = get_size().width - get_size().height - draw_spacing; - float min_distance = 1e20; - for (int i = 0; i < points.size(); i++) { - // Check if we clicked at point. - float distance = ABS(x - points[i].offset * total_w); - float min = (draw_point_width / 2 * 1.7); //make it easier to grab - if (distance <= min && distance < min_distance) { - result = i; - min_distance = distance; - } - } - return result; -} - -void GradientEdit::_show_color_picker() { - if (grabbed == -1) { - return; - } - picker->set_pick_color(points[grabbed].color); - Size2 minsize = popup->get_contents_minimum_size(); - bool show_above = false; - if (get_global_position().y + get_size().y + minsize.y > get_viewport_rect().size.y) { - show_above = true; - } - if (show_above) { - popup->set_position(get_screen_position() - Vector2(0, minsize.y)); - } else { - popup->set_position(get_screen_position() + Vector2(0, get_size().y)); - } - popup->popup(); -} - -GradientEdit::~GradientEdit() { -} - -void GradientEdit::gui_input(const Ref<InputEvent> &p_event) { - ERR_FAIL_COND(p_event.is_null()); - - Ref<InputEventKey> k = p_event; - - if (k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && grabbed != -1) { - points.remove_at(grabbed); - grabbed = -1; - grabbing = false; - update(); - emit_signal(SNAME("ramp_changed")); - accept_event(); - } - - Ref<InputEventMouseButton> mb = p_event; - // Show color picker on double click. - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) { - grabbed = _get_point_from_pos(mb->get_position().x); - _show_color_picker(); - accept_event(); - } - - // Delete point on right click. - if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { - grabbed = _get_point_from_pos(mb->get_position().x); - if (grabbed != -1) { - points.remove_at(grabbed); - grabbed = -1; - grabbing = false; - update(); - emit_signal(SNAME("ramp_changed")); - accept_event(); - } - } - - // Hold alt key to duplicate selected color. - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed() && mb->is_alt_pressed()) { - int x = mb->get_position().x; - grabbed = _get_point_from_pos(x); - - if (grabbed != -1) { - int total_w = get_size().width - get_size().height - draw_spacing; - Gradient::Point new_point = points[grabbed]; - new_point.offset = CLAMP(x / float(total_w), 0, 1); - - points.push_back(new_point); - points.sort(); - for (int i = 0; i < points.size(); ++i) { - if (points[i].offset == new_point.offset) { - grabbed = i; - break; - } - } - - emit_signal(SNAME("ramp_changed")); - update(); - } - } - - // Select. - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { - update(); - int x = mb->get_position().x; - int total_w = get_size().width - get_size().height - draw_spacing; - - //Check if color selector was clicked. - if (x > total_w + draw_spacing) { - _show_color_picker(); - return; - } - - grabbing = true; - - grabbed = _get_point_from_pos(x); - //grab or select - if (grabbed != -1) { - return; - } - - // Insert point. - Gradient::Point new_point; - new_point.offset = CLAMP(x / float(total_w), 0, 1); - - Gradient::Point prev; - Gradient::Point next; - - int pos = -1; - for (int i = 0; i < points.size(); i++) { - if (points[i].offset < new_point.offset) { - pos = i; - } - } - - if (pos == -1) { - prev.color = Color(0, 0, 0); - prev.offset = 0; - if (points.size()) { - next = points[0]; - } else { - next.color = Color(1, 1, 1); - next.offset = 1.0; - } - } else { - if (pos == points.size() - 1) { - next.color = Color(1, 1, 1); - next.offset = 1.0; - } else { - next = points[pos + 1]; - } - prev = points[pos]; - } - - new_point.color = prev.color.lerp(next.color, (new_point.offset - prev.offset) / (next.offset - prev.offset)); - - points.push_back(new_point); - points.sort(); - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == new_point.offset) { - grabbed = i; - break; - } - } - - emit_signal(SNAME("ramp_changed")); - } - - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed()) { - if (grabbing) { - grabbing = false; - emit_signal(SNAME("ramp_changed")); - } - update(); - } - - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid() && grabbing) { - int total_w = get_size().width - get_size().height - draw_spacing; - - int x = mm->get_position().x; - - float newofs = CLAMP(x / float(total_w), 0, 1); - - // Snap to "round" coordinates if holding Ctrl. - // Be more precise if holding Shift as well. - if (mm->is_ctrl_pressed()) { - newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1); - } else if (mm->is_shift_pressed()) { - // Snap to nearest point if holding just Shift - const float snap_threshold = 0.03; - float smallest_ofs = snap_threshold; - bool found = false; - int nearest_point = 0; - for (int i = 0; i < points.size(); ++i) { - if (i != grabbed) { - float temp_ofs = ABS(points[i].offset - newofs); - if (temp_ofs < smallest_ofs) { - smallest_ofs = temp_ofs; - nearest_point = i; - if (found) { - break; - } - found = true; - } - } - } - if (found) { - if (points[nearest_point].offset < newofs) { - newofs = points[nearest_point].offset + 0.00001; - } else { - newofs = points[nearest_point].offset - 0.00001; - } - newofs = CLAMP(newofs, 0, 1); - } - } - - bool valid = true; - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == newofs && i != grabbed) { - valid = false; - break; - } - } - - if (!valid || grabbed == -1) { - return; - } - points.write[grabbed].offset = newofs; - - points.sort(); - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == newofs) { - grabbed = i; - break; - } - } - - emit_signal(SNAME("ramp_changed")); - - update(); - } -} - -void GradientEdit::_notification(int p_what) { - 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; - - case 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. - } - - 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 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 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); - } - } - - // 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)); - } - } break; - - case NOTIFICATION_VISIBILITY_CHANGED: { - if (!is_visible()) { - grabbing = false; - } - } break; - } -} - -Size2 GradientEdit::get_minimum_size() const { - return Vector2(0, 16); -} - -void GradientEdit::_color_changed(const Color &p_color) { - if (grabbed == -1) { - return; - } - points.write[grabbed].color = p_color; - update(); - emit_signal(SNAME("ramp_changed")); -} - -void GradientEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) { - ERR_FAIL_COND(p_offsets.size() != p_colors.size()); - points.clear(); - for (int i = 0; i < p_offsets.size(); i++) { - Gradient::Point p; - p.offset = p_offsets[i]; - p.color = p_colors[i]; - points.push_back(p); - } - - points.sort(); - update(); -} - -Vector<float> GradientEdit::get_offsets() const { - Vector<float> ret; - for (int i = 0; i < points.size(); i++) { - ret.push_back(points[i].offset); - } - return ret; -} - -Vector<Color> GradientEdit::get_colors() const { - Vector<Color> ret; - for (int i = 0; i < points.size(); i++) { - ret.push_back(points[i].color); - } - return ret; -} - -void GradientEdit::set_points(Vector<Gradient::Point> &p_points) { - if (points.size() != p_points.size()) { - grabbed = -1; - } - points.clear(); - points = p_points; - points.sort(); -} - -Vector<Gradient::Point> &GradientEdit::get_points() { - return points; -} - -void GradientEdit::set_interpolation_mode(Gradient::InterpolationMode p_interp_mode) { - interpolation_mode = p_interp_mode; -} - -Gradient::InterpolationMode GradientEdit::get_interpolation_mode() { - return interpolation_mode; -} - -ColorPicker *GradientEdit::get_picker() { - return picker; -} - -PopupPanel *GradientEdit::get_popup() { - return popup; -} - -void GradientEdit::_bind_methods() { - ADD_SIGNAL(MethodInfo("ramp_changed")); -} diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 00f2e48601..5a0236268b 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -176,7 +176,7 @@ void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) { new_minimap_size.y = MIN(get_size().y - mm->get_relative().y, ge->get_size().y - 2.0 * minimap_padding.y); ge->set_minimap_size(new_minimap_size); - update(); + queue_redraw(); } else { Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding; _adjust_graph_scroll(click_position); @@ -190,6 +190,14 @@ void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) { ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2); } +TypedArray<String> GraphEdit::get_configuration_warnings() const { + TypedArray<String> warnings = Control::get_configuration_warnings(); + + warnings.push_back(RTR("Please be aware that GraphEdit and GraphNode will undergo extensive refactoring in a future beta version involving compatibility-breaking API changes.")); + + return warnings; +} + Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) { if (is_node_connected(p_from, p_from_port, p_to, p_to_port)) { return OK; @@ -201,10 +209,10 @@ Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const S c.to_port = p_to_port; c.activity = 0; connections.push_back(c); - top_layer->update(); - minimap->update(); - update(); - connections_layer->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + queue_redraw(); + connections_layer->queue_redraw(); return OK; } @@ -223,10 +231,10 @@ void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const for (const List<Connection>::Element *E = connections.front(); E; E = E->next()) { if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) { connections.erase(E); - top_layer->update(); - minimap->update(); - update(); - connections_layer->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + queue_redraw(); + connections_layer->queue_redraw(); return; } } @@ -253,9 +261,9 @@ void GraphEdit::_scroll_moved(double) { call_deferred(SNAME("_update_scroll_offset")); awaiting_scroll_offset_update = true; } - top_layer->update(); - minimap->update(); - update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + queue_redraw(); if (!setting_scroll_ofs) { //in godot, signals on change value are avoided as a convention emit_signal(SNAME("scroll_offset_changed"), get_scroll_ofs()); @@ -351,27 +359,40 @@ void GraphEdit::_graph_node_raised(Node *p_gn) { if (gn->is_comment()) { move_child(gn, 0); } else { - gn->raise(); + gn->move_to_front(); } - emit_signal(SNAME("node_selected"), p_gn); +} + +void GraphEdit::_graph_node_selected(Node *p_gn) { + GraphNode *gn = Object::cast_to<GraphNode>(p_gn); + ERR_FAIL_COND(!gn); + + emit_signal(SNAME("node_selected"), gn); +} + +void GraphEdit::_graph_node_deselected(Node *p_gn) { + GraphNode *gn = Object::cast_to<GraphNode>(p_gn); + ERR_FAIL_COND(!gn); + + emit_signal(SNAME("node_deselected"), gn); } void GraphEdit::_graph_node_moved(Node *p_gn) { GraphNode *gn = Object::cast_to<GraphNode>(p_gn); ERR_FAIL_COND(!gn); - top_layer->update(); - minimap->update(); - update(); - connections_layer->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + queue_redraw(); + connections_layer->queue_redraw(); } void GraphEdit::_graph_node_slot_updated(int p_index, Node *p_gn) { GraphNode *gn = Object::cast_to<GraphNode>(p_gn); ERR_FAIL_COND(!gn); - top_layer->update(); - minimap->update(); - update(); - connections_layer->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + queue_redraw(); + connections_layer->queue_redraw(); } void GraphEdit::add_child_notify(Node *p_child) { @@ -383,10 +404,12 @@ void GraphEdit::add_child_notify(Node *p_child) { if (gn) { gn->set_scale(Vector2(zoom, zoom)); gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved).bind(gn)); + gn->connect("selected", callable_mp(this, &GraphEdit::_graph_node_selected).bind(gn)); + gn->connect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected).bind(gn)); gn->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated).bind(gn)); gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised).bind(gn)); - gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update)); - gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update)); + gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw)); + gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw)); _graph_node_moved(gn); gn->set_mouse_filter(MOUSE_FILTER_PASS); } @@ -409,15 +432,17 @@ void GraphEdit::remove_child_notify(Node *p_child) { GraphNode *gn = Object::cast_to<GraphNode>(p_child); if (gn) { gn->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved)); + gn->disconnect("selected", callable_mp(this, &GraphEdit::_graph_node_selected)); + gn->disconnect("deselected", callable_mp(this, &GraphEdit::_graph_node_deselected)); gn->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated)); gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised)); // In case of the whole GraphEdit being destroyed these references can already be freed. if (connections_layer != nullptr && connections_layer->is_inside_tree()) { - gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update)); + gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::queue_redraw)); } if (minimap != nullptr && minimap->is_inside_tree()) { - gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update)); + gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::queue_redraw)); } } } @@ -500,8 +525,8 @@ void GraphEdit::_notification(int p_what) { case NOTIFICATION_RESIZED: { _update_scroll(); - top_layer->update(); - minimap->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); } break; } } @@ -698,8 +723,8 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { if (mm.is_valid() && connecting) { connecting_to = mm->get_position(); connecting_target = false; - top_layer->update(); - minimap->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0; if (connecting_valid) { @@ -756,25 +781,25 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { if (connecting_valid) { if (connecting && connecting_target) { String from = connecting_from; - int from_slot = connecting_index; + int from_port = connecting_index; String to = connecting_target_to; - int to_slot = connecting_target_index; + int to_port = connecting_target_index; if (!connecting_out) { SWAP(from, to); - SWAP(from_slot, to_slot); + SWAP(from_port, to_port); } - emit_signal(SNAME("connection_request"), from, from_slot, to, to_slot); + emit_signal(SNAME("connection_request"), from, from_port, to, to_port); } else if (!just_disconnected) { String from = connecting_from; - int from_slot = connecting_index; + int from_port = connecting_index; Vector2 ofs = mb->get_position(); if (!connecting_out) { - emit_signal(SNAME("connection_from_empty"), from, from_slot, ofs); + emit_signal(SNAME("connection_from_empty"), from, from_port, ofs); } else { - emit_signal(SNAME("connection_to_empty"), from, from_slot, ofs); + emit_signal(SNAME("connection_to_empty"), from, from_port, ofs); } } } @@ -813,22 +838,22 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos } } -bool GraphEdit::is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) { +bool GraphEdit::is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) { bool success; - if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_graph_node, p_slot_index, p_mouse_pos, success)) { + if (GDVIRTUAL_CALL(_is_in_input_hotzone, p_node, p_port, p_mouse_pos, success)) { return success; } else { - Vector2 pos = p_graph_node->get_connection_input_position(p_slot_index) + p_graph_node->get_position(); + Vector2 pos = p_node->get_connection_input_position(p_port) + p_node->get_position(); return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, true); } } -bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) { +bool GraphEdit::is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) { bool success; - if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_graph_node, p_slot_index, p_mouse_pos, success)) { + if (GDVIRTUAL_CALL(_is_in_output_hotzone, p_node, p_port, p_mouse_pos, success)) { return success; } else { - Vector2 pos = p_graph_node->get_connection_output_position(p_slot_index) + p_graph_node->get_position(); + Vector2 pos = p_node->get_connection_output_position(p_port) + p_node->get_position(); return is_in_port_hotzone(pos / zoom, p_mouse_pos, p_port_size, false); } } @@ -1083,11 +1108,11 @@ void GraphEdit::_minimap_draw() { continue; } - Vector2 from_slot_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E.from_port); - Vector2 from_position = minimap->_convert_from_graph_position(from_slot_position - graph_offset) + minimap_offset; + Vector2 from_port_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E.from_port); + Vector2 from_position = minimap->_convert_from_graph_position(from_port_position - graph_offset) + minimap_offset; Color from_color = gfrom->get_connection_output_color(E.from_port); - Vector2 to_slot_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E.to_port); - Vector2 to_position = minimap->_convert_from_graph_position(to_slot_position - graph_offset) + minimap_offset; + Vector2 to_port_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E.to_port); + Vector2 to_position = minimap->_convert_from_graph_position(to_port_position - graph_offset) + minimap_offset; Color to_color = gto->get_connection_input_color(E.to_port); if (E.activity > 0) { @@ -1170,29 +1195,14 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { bool in_box = r.intersects(box_selecting_rect); if (in_box) { - if (!gn->is_selected() && box_selection_mode_additive) { - emit_signal(SNAME("node_selected"), gn); - } else if (gn->is_selected() && !box_selection_mode_additive) { - emit_signal(SNAME("node_deselected"), gn); - } - if (gn->is_selectable()) { - gn->set_selected(box_selection_mode_additive); - } + gn->set_selected(box_selection_mode_additive); } else { - bool select = (previous_selected.find(gn) != nullptr); - if (gn->is_selected() && !select) { - emit_signal(SNAME("node_deselected"), gn); - } else if (!gn->is_selected() && select) { - emit_signal(SNAME("node_selected"), gn); - } - if (gn->is_selectable()) { - gn->set_selected(select); - } + gn->set_selected(previous_selected.find(gn) != nullptr); } } - top_layer->update(); - minimap->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); } Ref<InputEventMouseButton> b = p_ev; @@ -1206,16 +1216,10 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { continue; } - bool select = (gn->is_selectable() && previous_selected.find(gn) != nullptr); - if (gn->is_selected() && !select) { - emit_signal(SNAME("node_deselected"), gn); - } else if (!gn->is_selected() && select) { - emit_signal(SNAME("node_selected"), gn); - } - gn->set_selected(select); + gn->set_selected(previous_selected.find(gn) != nullptr); } - top_layer->update(); - minimap->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); } else { if (connecting) { force_connection_drag_end(); @@ -1235,7 +1239,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { Rect2 r = gn->get_rect(); r.size *= zoom; if (r.has_point(b->get_position())) { - emit_signal(SNAME("node_deselected"), gn); gn->set_selected(false); } } @@ -1261,27 +1264,30 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { dragging = false; - top_layer->update(); - minimap->update(); - update(); - connections_layer->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + queue_redraw(); + connections_layer->queue_redraw(); } if (b->get_button_index() == MouseButton::LEFT && b->is_pressed()) { GraphNode *gn = nullptr; + // Find node which was clicked on. for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn_selected = Object::cast_to<GraphNode>(get_child(i)); - if (gn_selected) { - if (gn_selected->is_resizing()) { - continue; - } + if (!gn_selected) { + continue; + } - if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) { - gn = gn_selected; - break; - } + if (gn_selected->is_resizing()) { + continue; + } + + if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) { + gn = gn_selected; + break; } } @@ -1290,26 +1296,22 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { return; } + // Left-clicked on a node, select it. dragging = true; drag_accum = Vector2(); just_selected = !gn->is_selected(); if (!gn->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) { for (int i = 0; i < get_child_count(); i++) { GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i)); - if (o_gn) { - if (o_gn == gn) { - o_gn->set_selected(o_gn->is_selectable()); - } else { - if (o_gn->is_selected()) { - emit_signal(SNAME("node_deselected"), o_gn); - } - o_gn->set_selected(false); - } + if (!o_gn) { + continue; } + + o_gn->set_selected(o_gn == gn); } } - gn->set_selected(gn->is_selectable()); + gn->set_selected(true); for (int i = 0; i < get_child_count(); i++) { GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i)); if (!o_gn) { @@ -1332,6 +1334,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { return; } + // Left-clicked on empty space, start box select. box_selecting = true; box_selecting_from = b->get_position(); if (b->is_ctrl_pressed()) { @@ -1364,9 +1367,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { if (!gn2) { continue; } - if (gn2->is_selected()) { - emit_signal(SNAME("node_deselected"), gn2); - } + gn2->set_selected(false); } } @@ -1374,11 +1375,12 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { } if (b->get_button_index() == MouseButton::LEFT && !b->is_pressed() && box_selecting) { + // Box selection ended. Nodes were selected during mouse movement. box_selecting = false; box_selecting_rect = Rect2(); previous_selected.clear(); - top_layer->update(); - minimap->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); } } @@ -1444,9 +1446,9 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por if (E.from == p_from && E.from_port == p_from_port && E.to == p_to && E.to_port == p_to_port) { if (Math::is_equal_approx(E.activity, p_activity)) { //update only if changed - top_layer->update(); - minimap->update(); - connections_layer->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + connections_layer->queue_redraw(); } E.activity = p_activity; return; @@ -1456,19 +1458,19 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por void GraphEdit::clear_connections() { connections.clear(); - minimap->update(); - update(); - connections_layer->update(); + minimap->queue_redraw(); + queue_redraw(); + connections_layer->queue_redraw(); } void GraphEdit::force_connection_drag_end() { ERR_FAIL_COND_MSG(!connecting, "Drag end requested without active drag!"); connecting = false; connecting_valid = false; - top_layer->update(); - minimap->update(); - update(); - connections_layer->update(); + top_layer->queue_redraw(); + minimap->queue_redraw(); + queue_redraw(); + connections_layer->queue_redraw(); emit_signal(SNAME("connection_drag_ended")); } @@ -1502,14 +1504,14 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) { Vector2 sbofs = (Vector2(h_scroll->get_value(), v_scroll->get_value()) + p_center) / zoom; zoom = p_zoom; - top_layer->update(); + top_layer->queue_redraw(); zoom_minus->set_disabled(zoom == zoom_min); zoom_plus->set_disabled(zoom == zoom_max); _update_scroll(); - minimap->update(); - connections_layer->update(); + minimap->queue_redraw(); + connections_layer->queue_redraw(); if (is_visible_in_tree()) { Vector2 ofs = sbofs * zoom - p_center; @@ -1518,7 +1520,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) { } _update_zoom_label(); - update(); + queue_redraw(); } float GraphEdit::get_zoom() const { @@ -1657,7 +1659,7 @@ void GraphEdit::set_use_snap(bool p_enable) { return; } snap_button->set_pressed(p_enable); - update(); + queue_redraw(); } bool GraphEdit::is_using_snap() const { @@ -1671,15 +1673,15 @@ int GraphEdit::get_snap() const { void GraphEdit::set_snap(int p_snap) { ERR_FAIL_COND(p_snap < 5); snap_amount->set_value(p_snap); - update(); + queue_redraw(); } void GraphEdit::_snap_toggled() { - update(); + queue_redraw(); } void GraphEdit::_snap_value_changed(double) { - update(); + queue_redraw(); } void GraphEdit::set_minimap_size(Vector2 p_size) { @@ -1691,7 +1693,7 @@ void GraphEdit::set_minimap_size(Vector2 p_size) { minimap->set_offset(Side::SIDE_TOP, -minimap_size.y - MINIMAP_OFFSET); minimap->set_offset(Side::SIDE_RIGHT, -MINIMAP_OFFSET); minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET); - minimap->update(); + minimap->queue_redraw(); } Vector2 GraphEdit::get_minimap_size() const { @@ -1703,7 +1705,7 @@ void GraphEdit::set_minimap_opacity(float p_opacity) { return; } minimap->set_modulate(Color(1, 1, 1, p_opacity)); - minimap->update(); + minimap->queue_redraw(); } float GraphEdit::get_minimap_opacity() const { @@ -1717,7 +1719,7 @@ void GraphEdit::set_minimap_enabled(bool p_enable) { } minimap_button->set_pressed(p_enable); _minimap_toggled(); - minimap->update(); + minimap->queue_redraw(); } bool GraphEdit::is_minimap_enabled() const { @@ -1740,7 +1742,7 @@ bool GraphEdit::is_arrange_nodes_button_hidden() const { void GraphEdit::_minimap_toggled() { if (is_minimap_enabled()) { minimap->set_visible(true); - minimap->update(); + minimap->queue_redraw(); } else { minimap->set_visible(false); } @@ -1748,7 +1750,7 @@ void GraphEdit::_minimap_toggled() { void GraphEdit::set_connection_lines_curvature(float p_curvature) { lines_curvature = p_curvature; - update(); + queue_redraw(); } float GraphEdit::get_connection_lines_curvature() const { @@ -1760,7 +1762,7 @@ void GraphEdit::set_connection_lines_thickness(float p_thickness) { return; } lines_thickness = p_thickness; - update(); + queue_redraw(); } float GraphEdit::get_connection_lines_thickness() const { @@ -1772,7 +1774,7 @@ void GraphEdit::set_connection_lines_antialiased(bool p_antialiased) { return; } lines_antialiased = p_antialiased; - update(); + queue_redraw(); } bool GraphEdit::is_connection_lines_antialiased() const { @@ -2309,10 +2311,10 @@ void GraphEdit::arrange_nodes() { } void GraphEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("connect_node", "from", "from_port", "to", "to_port"), &GraphEdit::connect_node); - ClassDB::bind_method(D_METHOD("is_node_connected", "from", "from_port", "to", "to_port"), &GraphEdit::is_node_connected); - ClassDB::bind_method(D_METHOD("disconnect_node", "from", "from_port", "to", "to_port"), &GraphEdit::disconnect_node); - ClassDB::bind_method(D_METHOD("set_connection_activity", "from", "from_port", "to", "to_port", "amount"), &GraphEdit::set_connection_activity); + ClassDB::bind_method(D_METHOD("connect_node", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::connect_node); + ClassDB::bind_method(D_METHOD("is_node_connected", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::is_node_connected); + ClassDB::bind_method(D_METHOD("disconnect_node", "from_node", "from_port", "to_node", "to_port"), &GraphEdit::disconnect_node); + ClassDB::bind_method(D_METHOD("set_connection_activity", "from_node", "from_port", "to_node", "to_port", "amount"), &GraphEdit::set_connection_activity); ClassDB::bind_method(D_METHOD("get_connection_list"), &GraphEdit::_get_connection_list); ClassDB::bind_method(D_METHOD("clear_connections"), &GraphEdit::clear_connections); ClassDB::bind_method(D_METHOD("force_connection_drag_end"), &GraphEdit::force_connection_drag_end); @@ -2326,7 +2328,7 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("add_valid_connection_type", "from_type", "to_type"), &GraphEdit::add_valid_connection_type); ClassDB::bind_method(D_METHOD("remove_valid_connection_type", "from_type", "to_type"), &GraphEdit::remove_valid_connection_type); ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type); - ClassDB::bind_method(D_METHOD("get_connection_line", "from", "to"), &GraphEdit::get_connection_line); + ClassDB::bind_method(D_METHOD("get_connection_line", "from_node", "to_node"), &GraphEdit::get_connection_line); ClassDB::bind_method(D_METHOD("set_panning_scheme", "scheme"), &GraphEdit::set_panning_scheme); ClassDB::bind_method(D_METHOD("get_panning_scheme"), &GraphEdit::get_panning_scheme); @@ -2376,8 +2378,8 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled); ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset); - GDVIRTUAL_BIND(_is_in_input_hotzone, "graph_node", "slot_index", "mouse_position"); - GDVIRTUAL_BIND(_is_in_output_hotzone, "graph_node", "slot_index", "mouse_position"); + GDVIRTUAL_BIND(_is_in_input_hotzone, "in_node", "in_port", "mouse_position"); + GDVIRTUAL_BIND(_is_in_output_hotzone, "in_node", "in_port", "mouse_position"); ClassDB::bind_method(D_METHOD("get_zoom_hbox"), &GraphEdit::get_zoom_hbox); @@ -2385,8 +2387,8 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected); - GDVIRTUAL_BIND(_get_connection_line, "from", "to") - GDVIRTUAL_BIND(_is_node_hover_valid, "from", "from_slot", "to", "to_slot"); + GDVIRTUAL_BIND(_get_connection_line, "from_position", "to_position") + GDVIRTUAL_BIND(_is_node_hover_valid, "from_node", "from_port", "to_node", "to_port"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_ofs", "get_scroll_ofs"); @@ -2414,21 +2416,21 @@ void GraphEdit::_bind_methods() { ADD_GROUP("UI", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arrange_nodes_button_hidden"), "set_arrange_nodes_button_hidden", "is_arrange_nodes_button_hidden"); - ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"))); - ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"))); + ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port"))); + ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port"))); ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "position"))); ADD_SIGNAL(MethodInfo("duplicate_nodes_request")); ADD_SIGNAL(MethodInfo("copy_nodes_request")); ADD_SIGNAL(MethodInfo("paste_nodes_request")); ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_deselected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::VECTOR2, "release_position"))); - ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot"), PropertyInfo(Variant::VECTOR2, "release_position"))); + ADD_SIGNAL(MethodInfo("connection_to_empty", PropertyInfo(Variant::STRING_NAME, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::VECTOR2, "release_position"))); + ADD_SIGNAL(MethodInfo("connection_from_empty", PropertyInfo(Variant::STRING_NAME, "to_node"), PropertyInfo(Variant::INT, "to_port"), PropertyInfo(Variant::VECTOR2, "release_position"))); ADD_SIGNAL(MethodInfo("delete_nodes_request", PropertyInfo(Variant::ARRAY, "nodes", PROPERTY_HINT_ARRAY_TYPE, "StringName"))); ADD_SIGNAL(MethodInfo("begin_node_move")); ADD_SIGNAL(MethodInfo("end_node_move")); ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "offset"))); - ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "slot"), PropertyInfo(Variant::BOOL, "is_output"))); + ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from_node"), PropertyInfo(Variant::INT, "from_port"), PropertyInfo(Variant::BOOL, "is_output"))); ADD_SIGNAL(MethodInfo("connection_drag_ended")); BIND_ENUM_CONSTANT(SCROLL_ZOOMS); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index 0a0676699f..0fe9e7c555 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -186,6 +186,8 @@ private: PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to); void _draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom); + void _graph_node_selected(Node *p_gn); + void _graph_node_deselected(Node *p_gn); void _graph_node_raised(Node *p_gn); void _graph_node_moved(Node *p_gn); void _graph_node_slot_updated(int p_index, Node *p_gn); @@ -199,8 +201,8 @@ private: GraphEditMinimap *minimap = nullptr; void _top_layer_input(const Ref<InputEvent> &p_ev); - bool is_in_input_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size); - bool is_in_output_hotzone(GraphNode *p_graph_node, int p_slot_index, const Vector2 &p_mouse_pos, const Vector2i &p_port_size); + bool is_in_input_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size); + bool is_in_output_hotzone(GraphNode *p_node, int p_port, const Vector2 &p_mouse_pos, const Vector2i &p_port_size); bool is_in_port_hotzone(const Vector2 &pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left); void _top_layer_draw(); @@ -285,6 +287,8 @@ protected: GDVIRTUAL4R(bool, _is_node_hover_valid, StringName, int, StringName, int); public: + TypedArray<String> get_configuration_warnings() const override; + Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); void disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index b07d401e6b..21c0b5a842 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -78,7 +78,7 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { } set_slot(idx, si.enable_left, si.type_left, si.color_left, si.enable_right, si.type_right, si.color_right, si.custom_slot_left, si.custom_slot_right, si.draw_stylebox); - update(); + queue_redraw(); return true; } @@ -288,7 +288,7 @@ void GraphNode::_resort() { idx++; } - update(); + queue_redraw(); connpos_dirty = true; } @@ -416,7 +416,7 @@ void GraphNode::_notification(int p_what) { _shape(); update_minimum_size(); - update(); + queue_redraw(); } break; } } @@ -475,7 +475,7 @@ void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const C s.custom_slot_right = p_custom_right; s.draw_stylebox = p_draw_stylebox; slot_info[p_idx] = s; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -483,13 +483,13 @@ void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const C void GraphNode::clear_slot(int p_idx) { slot_info.erase(p_idx); - update(); + queue_redraw(); connpos_dirty = true; } void GraphNode::clear_all_slots() { slot_info.clear(); - update(); + queue_redraw(); connpos_dirty = true; } @@ -508,7 +508,7 @@ void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) { } slot_info[p_idx].enable_left = p_enable_left; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -522,7 +522,7 @@ void GraphNode::set_slot_type_left(int p_idx, int p_type_left) { } slot_info[p_idx].type_left = p_type_left; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -543,7 +543,7 @@ void GraphNode::set_slot_color_left(int p_idx, const Color &p_color_left) { } slot_info[p_idx].color_left = p_color_left; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -571,7 +571,7 @@ void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) { } slot_info[p_idx].enable_right = p_enable_right; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -585,7 +585,7 @@ void GraphNode::set_slot_type_right(int p_idx, int p_type_right) { } slot_info[p_idx].type_right = p_type_right; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -606,7 +606,7 @@ void GraphNode::set_slot_color_right(int p_idx, const Color &p_color_right) { } slot_info[p_idx].color_right = p_color_right; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -630,7 +630,7 @@ void GraphNode::set_slot_draw_stylebox(int p_idx, bool p_enable) { ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set draw_stylebox for the slot with p_idx (%d) lesser than zero.", p_idx)); slot_info[p_idx].draw_stylebox = p_enable; - update(); + queue_redraw(); connpos_dirty = true; emit_signal(SNAME("slot_updated"), p_idx); @@ -688,7 +688,7 @@ void GraphNode::set_title(const String &p_title) { title = p_title; _shape(); - update(); + queue_redraw(); update_minimum_size(); } @@ -701,7 +701,7 @@ void GraphNode::set_text_direction(Control::TextDirection p_text_direction) { if (text_direction != p_text_direction) { text_direction = p_text_direction; _shape(); - update(); + queue_redraw(); } } @@ -713,7 +713,7 @@ void GraphNode::set_language(const String &p_language) { if (language != p_language) { language = p_language; _shape(); - update(); + queue_redraw(); } } @@ -728,7 +728,7 @@ void GraphNode::set_position_offset(const Vector2 &p_offset) { position_offset = p_offset; emit_signal(SNAME("position_offset_changed")); - update(); + queue_redraw(); } Vector2 GraphNode::get_position_offset() const { @@ -736,12 +736,13 @@ Vector2 GraphNode::get_position_offset() const { } void GraphNode::set_selected(bool p_selected) { - if (selected == p_selected) { + if (!is_selectable() || selected == p_selected) { return; } selected = p_selected; - update(); + emit_signal(p_selected ? SNAME("selected") : SNAME("deselected")); + queue_redraw(); } bool GraphNode::is_selected() { @@ -766,7 +767,7 @@ void GraphNode::set_show_close_button(bool p_enable) { } show_close = p_enable; - update(); + queue_redraw(); } bool GraphNode::is_close_button_visible() const { @@ -778,8 +779,8 @@ void GraphNode::_connpos_update() { int sep = get_theme_constant(SNAME("separation")); Ref<StyleBox> sb = get_theme_stylebox(SNAME("frame")); - conn_input_cache.clear(); - conn_output_cache.clear(); + left_port_cache.clear(); + right_port_cache.clear(); int vofs = 0; int idx = 0; @@ -800,20 +801,26 @@ void GraphNode::_connpos_update() { if (slot_info.has(idx)) { if (slot_info[idx].enable_left) { - ConnCache cc; - cc.pos = Point2i(edgeofs, y + h / 2); + PortCache cc; + cc.position = Point2i(edgeofs, y + h / 2); + cc.height = size.height; + + cc.slot_idx = idx; cc.type = slot_info[idx].type_left; cc.color = slot_info[idx].color_left; - cc.height = size.height; - conn_input_cache.push_back(cc); + + left_port_cache.push_back(cc); } if (slot_info[idx].enable_right) { - ConnCache cc; - cc.pos = Point2i(get_size().width - edgeofs, y + h / 2); + PortCache cc; + cc.position = Point2i(get_size().width - edgeofs, y + h / 2); + cc.height = size.height; + + cc.slot_idx = idx; cc.type = slot_info[idx].type_right; cc.color = slot_info[idx].color_right; - cc.height = size.height; - conn_output_cache.push_back(cc); + + right_port_cache.push_back(cc); } } @@ -830,46 +837,55 @@ int GraphNode::get_connection_input_count() { _connpos_update(); } - return conn_input_cache.size(); + return left_port_cache.size(); } -int GraphNode::get_connection_input_height(int p_idx) { +int GraphNode::get_connection_input_height(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0); - return conn_input_cache[p_idx].height; + ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0); + return left_port_cache[p_port].height; } -Vector2 GraphNode::get_connection_input_position(int p_idx) { +Vector2 GraphNode::get_connection_input_position(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), Vector2()); - Vector2 pos = conn_input_cache[p_idx].pos; + ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Vector2()); + Vector2 pos = left_port_cache[p_port].position; pos.x *= get_scale().x; pos.y *= get_scale().y; return pos; } -int GraphNode::get_connection_input_type(int p_idx) { +int GraphNode::get_connection_input_type(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), 0); - return conn_input_cache[p_idx].type; + ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), 0); + return left_port_cache[p_port].type; } -Color GraphNode::get_connection_input_color(int p_idx) { +Color GraphNode::get_connection_input_color(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_input_cache.size(), Color()); - return conn_input_cache[p_idx].color; + ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), Color()); + return left_port_cache[p_port].color; +} + +int GraphNode::get_connection_input_slot(int p_port) { + if (connpos_dirty) { + _connpos_update(); + } + + ERR_FAIL_INDEX_V(p_port, left_port_cache.size(), -1); + return left_port_cache[p_port].slot_idx; } int GraphNode::get_connection_output_count() { @@ -877,46 +893,55 @@ int GraphNode::get_connection_output_count() { _connpos_update(); } - return conn_output_cache.size(); + return right_port_cache.size(); } -int GraphNode::get_connection_output_height(int p_idx) { +int GraphNode::get_connection_output_height(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0); - return conn_output_cache[p_idx].height; + ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0); + return right_port_cache[p_port].height; } -Vector2 GraphNode::get_connection_output_position(int p_idx) { +Vector2 GraphNode::get_connection_output_position(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), Vector2()); - Vector2 pos = conn_output_cache[p_idx].pos; + ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Vector2()); + Vector2 pos = right_port_cache[p_port].position; pos.x *= get_scale().x; pos.y *= get_scale().y; return pos; } -int GraphNode::get_connection_output_type(int p_idx) { +int GraphNode::get_connection_output_type(int p_port) { + if (connpos_dirty) { + _connpos_update(); + } + + ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), 0); + return right_port_cache[p_port].type; +} + +Color GraphNode::get_connection_output_color(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), 0); - return conn_output_cache[p_idx].type; + ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), Color()); + return right_port_cache[p_port].color; } -Color GraphNode::get_connection_output_color(int p_idx) { +int GraphNode::get_connection_output_slot(int p_port) { if (connpos_dirty) { _connpos_update(); } - ERR_FAIL_INDEX_V(p_idx, conn_output_cache.size(), Color()); - return conn_output_cache[p_idx].color; + ERR_FAIL_INDEX_V(p_port, right_port_cache.size(), -1); + return right_port_cache[p_port].slot_idx; } void GraphNode::gui_input(const Ref<InputEvent> &p_ev) { @@ -970,7 +995,7 @@ void GraphNode::set_overlay(Overlay p_overlay) { } overlay = p_overlay; - update(); + queue_redraw(); } GraphNode::Overlay GraphNode::get_overlay() const { @@ -983,7 +1008,7 @@ void GraphNode::set_comment(bool p_enable) { } comment = p_enable; - update(); + queue_redraw(); } bool GraphNode::is_comment() const { @@ -996,7 +1021,7 @@ void GraphNode::set_resizable(bool p_enable) { } resizable = p_enable; - update(); + queue_redraw(); } bool GraphNode::is_resizable() const { @@ -1012,6 +1037,9 @@ bool GraphNode::is_draggable() { } void GraphNode::set_selectable(bool p_selectable) { + if (!p_selectable) { + set_selected(false); + } selectable = p_selectable; } @@ -1046,30 +1074,30 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_language", "language"), &GraphNode::set_language); ClassDB::bind_method(D_METHOD("get_language"), &GraphNode::get_language); - ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right", "enable"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("clear_slot", "idx"), &GraphNode::clear_slot); + ClassDB::bind_method(D_METHOD("set_slot", "slot_index", "enable_left_port", "type_left", "color_left", "enable_right_port", "type_right", "color_right", "custom_icon_left", "custom_icon_right", "draw_stylebox"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("clear_slot", "slot_index"), &GraphNode::clear_slot); ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots); - ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "idx"), &GraphNode::is_slot_enabled_left); - ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "idx", "enable_left"), &GraphNode::set_slot_enabled_left); + ClassDB::bind_method(D_METHOD("set_slot_enabled_left", "slot_index", "enable"), &GraphNode::set_slot_enabled_left); + ClassDB::bind_method(D_METHOD("is_slot_enabled_left", "slot_index"), &GraphNode::is_slot_enabled_left); - ClassDB::bind_method(D_METHOD("set_slot_type_left", "idx", "type_left"), &GraphNode::set_slot_type_left); - ClassDB::bind_method(D_METHOD("get_slot_type_left", "idx"), &GraphNode::get_slot_type_left); + ClassDB::bind_method(D_METHOD("set_slot_type_left", "slot_index", "type"), &GraphNode::set_slot_type_left); + ClassDB::bind_method(D_METHOD("get_slot_type_left", "slot_index"), &GraphNode::get_slot_type_left); - ClassDB::bind_method(D_METHOD("set_slot_color_left", "idx", "color_left"), &GraphNode::set_slot_color_left); - ClassDB::bind_method(D_METHOD("get_slot_color_left", "idx"), &GraphNode::get_slot_color_left); + ClassDB::bind_method(D_METHOD("set_slot_color_left", "slot_index", "color"), &GraphNode::set_slot_color_left); + ClassDB::bind_method(D_METHOD("get_slot_color_left", "slot_index"), &GraphNode::get_slot_color_left); - ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "idx"), &GraphNode::is_slot_enabled_right); - ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "idx", "enable_right"), &GraphNode::set_slot_enabled_right); + ClassDB::bind_method(D_METHOD("set_slot_enabled_right", "slot_index", "enable"), &GraphNode::set_slot_enabled_right); + ClassDB::bind_method(D_METHOD("is_slot_enabled_right", "slot_index"), &GraphNode::is_slot_enabled_right); - ClassDB::bind_method(D_METHOD("set_slot_type_right", "idx", "type_right"), &GraphNode::set_slot_type_right); - ClassDB::bind_method(D_METHOD("get_slot_type_right", "idx"), &GraphNode::get_slot_type_right); + ClassDB::bind_method(D_METHOD("set_slot_type_right", "slot_index", "type"), &GraphNode::set_slot_type_right); + ClassDB::bind_method(D_METHOD("get_slot_type_right", "slot_index"), &GraphNode::get_slot_type_right); - ClassDB::bind_method(D_METHOD("set_slot_color_right", "idx", "color_right"), &GraphNode::set_slot_color_right); - ClassDB::bind_method(D_METHOD("get_slot_color_right", "idx"), &GraphNode::get_slot_color_right); + ClassDB::bind_method(D_METHOD("set_slot_color_right", "slot_index", "color"), &GraphNode::set_slot_color_right); + ClassDB::bind_method(D_METHOD("get_slot_color_right", "slot_index"), &GraphNode::get_slot_color_right); - ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "idx"), &GraphNode::is_slot_draw_stylebox); - ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "idx", "draw_stylebox"), &GraphNode::set_slot_draw_stylebox); + ClassDB::bind_method(D_METHOD("is_slot_draw_stylebox", "slot_index"), &GraphNode::is_slot_draw_stylebox); + ClassDB::bind_method(D_METHOD("set_slot_draw_stylebox", "slot_index", "enable"), &GraphNode::set_slot_draw_stylebox); ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset); ClassDB::bind_method(D_METHOD("get_position_offset"), &GraphNode::get_position_offset); @@ -1090,16 +1118,18 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected); ClassDB::bind_method(D_METHOD("get_connection_input_count"), &GraphNode::get_connection_input_count); - ClassDB::bind_method(D_METHOD("get_connection_input_height", "idx"), &GraphNode::get_connection_input_height); - ClassDB::bind_method(D_METHOD("get_connection_input_position", "idx"), &GraphNode::get_connection_input_position); - ClassDB::bind_method(D_METHOD("get_connection_input_type", "idx"), &GraphNode::get_connection_input_type); - ClassDB::bind_method(D_METHOD("get_connection_input_color", "idx"), &GraphNode::get_connection_input_color); + ClassDB::bind_method(D_METHOD("get_connection_input_height", "port"), &GraphNode::get_connection_input_height); + ClassDB::bind_method(D_METHOD("get_connection_input_position", "port"), &GraphNode::get_connection_input_position); + ClassDB::bind_method(D_METHOD("get_connection_input_type", "port"), &GraphNode::get_connection_input_type); + ClassDB::bind_method(D_METHOD("get_connection_input_color", "port"), &GraphNode::get_connection_input_color); + ClassDB::bind_method(D_METHOD("get_connection_input_slot", "port"), &GraphNode::get_connection_input_slot); ClassDB::bind_method(D_METHOD("get_connection_output_count"), &GraphNode::get_connection_output_count); - ClassDB::bind_method(D_METHOD("get_connection_output_height", "idx"), &GraphNode::get_connection_output_height); - ClassDB::bind_method(D_METHOD("get_connection_output_position", "idx"), &GraphNode::get_connection_output_position); - ClassDB::bind_method(D_METHOD("get_connection_output_type", "idx"), &GraphNode::get_connection_output_type); - ClassDB::bind_method(D_METHOD("get_connection_output_color", "idx"), &GraphNode::get_connection_output_color); + ClassDB::bind_method(D_METHOD("get_connection_output_height", "port"), &GraphNode::get_connection_output_height); + ClassDB::bind_method(D_METHOD("get_connection_output_position", "port"), &GraphNode::get_connection_output_position); + ClassDB::bind_method(D_METHOD("get_connection_output_type", "port"), &GraphNode::get_connection_output_type); + ClassDB::bind_method(D_METHOD("get_connection_output_color", "port"), &GraphNode::get_connection_output_color); + ClassDB::bind_method(D_METHOD("get_connection_output_slot", "port"), &GraphNode::get_connection_output_slot); ClassDB::bind_method(D_METHOD("set_show_close_button", "show"), &GraphNode::set_show_close_button); ClassDB::bind_method(D_METHOD("is_close_button_visible"), &GraphNode::is_close_button_visible); @@ -1123,6 +1153,8 @@ void GraphNode::_bind_methods() { ADD_GROUP("", ""); ADD_SIGNAL(MethodInfo("position_offset_changed")); + ADD_SIGNAL(MethodInfo("selected")); + ADD_SIGNAL(MethodInfo("deselected")); ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx"))); ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to"))); ADD_SIGNAL(MethodInfo("raise_request")); diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 9c8f926403..e66b0cfc20 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -78,15 +78,17 @@ private: Vector<int> cache_y; - struct ConnCache { - Vector2 pos; + struct PortCache { + Vector2 position; + int height; + + int slot_idx; int type = 0; Color color; - int height; }; - Vector<ConnCache> conn_input_cache; - Vector<ConnCache> conn_output_cache; + Vector<PortCache> left_port_cache; + Vector<PortCache> right_port_cache; HashMap<int, Slot> slot_info; @@ -165,16 +167,18 @@ public: bool is_close_button_visible() const; int get_connection_input_count(); - int get_connection_input_height(int p_idx); - Vector2 get_connection_input_position(int p_idx); - int get_connection_input_type(int p_idx); - Color get_connection_input_color(int p_idx); + int get_connection_input_height(int p_port); + Vector2 get_connection_input_position(int p_port); + int get_connection_input_type(int p_port); + Color get_connection_input_color(int p_port); + int get_connection_input_slot(int p_port); int get_connection_output_count(); - int get_connection_output_height(int p_idx); - Vector2 get_connection_output_position(int p_idx); - int get_connection_output_type(int p_idx); - Color get_connection_output_color(int p_idx); + int get_connection_output_height(int p_port); + Vector2 get_connection_output_position(int p_port); + int get_connection_output_type(int p_port); + Color get_connection_output_color(int p_port); + int get_connection_output_slot(int p_port); void set_overlay(Overlay p_overlay); Overlay get_overlay() const; diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index 3163d17846..8dc890eccb 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -31,6 +31,13 @@ #include "grid_container.h" #include "core/templates/rb_set.h" +void GridContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + theme_cache.v_separation = get_theme_constant(SNAME("v_separation")); +} + void GridContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { @@ -39,9 +46,6 @@ void GridContainer::_notification(int p_what) { RBSet<int> col_expanded; // Columns which have the SIZE_EXPAND flag set. RBSet<int> row_expanded; // Rows which have the SIZE_EXPAND flag set. - int hsep = get_theme_constant(SNAME("h_separation")); - int vsep = get_theme_constant(SNAME("v_separation")); - // Compute the per-column/per-row data. int valid_controls_index = 0; for (int i = 0; i < get_child_count(); i++) { @@ -98,8 +102,8 @@ void GridContainer::_notification(int p_what) { remaining_space.height -= E.value; } } - remaining_space.height -= vsep * MAX(max_row - 1, 0); - remaining_space.width -= hsep * MAX(max_col - 1, 0); + remaining_space.height -= theme_cache.v_separation * MAX(max_row - 1, 0); + remaining_space.width -= theme_cache.h_separation * MAX(max_col - 1, 0); bool can_fit = false; while (!can_fit && col_expanded.size() > 0) { @@ -202,7 +206,7 @@ void GridContainer::_notification(int p_what) { col_ofs = 0; } if (row > 0) { - row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + vsep; + row_ofs += (row_expanded.has(row - 1) ? row_expand : row_minh[row - 1]) + theme_cache.v_separation; if (row_expanded.has(row - 1) && row - 1 < row_remaining_pixel_index) { // Apply the remaining pixel of the previous row. @@ -224,11 +228,11 @@ void GridContainer::_notification(int p_what) { if (rtl) { Point2 p(col_ofs - s.width, row_ofs); fit_child_in_rect(c, Rect2(p, s)); - col_ofs -= s.width + hsep; + col_ofs -= s.width + theme_cache.h_separation; } else { Point2 p(col_ofs, row_ofs); fit_child_in_rect(c, Rect2(p, s)); - col_ofs += s.width + hsep; + col_ofs += s.width + theme_cache.h_separation; } } } break; @@ -271,9 +275,6 @@ Size2 GridContainer::get_minimum_size() const { RBMap<int, int> col_minw; RBMap<int, int> row_minh; - int hsep = get_theme_constant(SNAME("h_separation")); - int vsep = get_theme_constant(SNAME("v_separation")); - int max_row = 0; int max_col = 0; @@ -313,8 +314,8 @@ Size2 GridContainer::get_minimum_size() const { ms.height += E.value; } - ms.height += vsep * max_row; - ms.width += hsep * max_col; + ms.height += theme_cache.v_separation * max_row; + ms.width += theme_cache.h_separation * max_col; return ms; } diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h index 9d77f90ab3..522046f694 100644 --- a/scene/gui/grid_container.h +++ b/scene/gui/grid_container.h @@ -38,7 +38,14 @@ class GridContainer : public Container { int columns = 1; + struct ThemeCache { + int h_separation = 0; + int v_separation = 0; + } theme_cache; + protected: + virtual void _update_theme_item_cache() override; + void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 086f729603..008109da65 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -43,9 +43,9 @@ void ItemList::_shape(int p_idx) { } else { item.text_buf->set_direction((TextServer::Direction)item.text_direction); } - item.text_buf->add_string(item.text, get_theme_font(SNAME("font")), get_theme_font_size(SNAME("font_size")), item.language); + item.text_buf->add_string(item.text, theme_cache.font, theme_cache.font_size, item.language); if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { - item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND); + item.text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES); } else { item.text_buf->set_break_flags(TextServer::BREAK_NONE); } @@ -63,7 +63,7 @@ int ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bo _shape(items.size() - 1); - update(); + queue_redraw(); shape_changed = true; notify_property_list_changed(); return item_id; @@ -76,7 +76,7 @@ int ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) { items.push_back(item); int item_id = items.size() - 1; - update(); + queue_redraw(); shape_changed = true; notify_property_list_changed(); return item_id; @@ -94,7 +94,7 @@ void ItemList::set_item_text(int p_idx, const String &p_text) { items.write[p_idx].text = p_text; _shape(p_idx); - update(); + queue_redraw(); shape_changed = true; } @@ -112,7 +112,7 @@ void ItemList::set_item_text_direction(int p_idx, Control::TextDirection p_text_ if (items[p_idx].text_direction != p_text_direction) { items.write[p_idx].text_direction = p_text_direction; _shape(p_idx); - update(); + queue_redraw(); } } @@ -129,7 +129,7 @@ void ItemList::set_item_language(int p_idx, const String &p_language) { if (items[p_idx].language != p_language) { items.write[p_idx].language = p_language; _shape(p_idx); - update(); + queue_redraw(); } } @@ -162,7 +162,7 @@ void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) { } items.write[p_idx].tooltip = p_tooltip; - update(); + queue_redraw(); shape_changed = true; } @@ -182,7 +182,7 @@ void ItemList::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { } items.write[p_idx].icon = p_icon; - update(); + queue_redraw(); shape_changed = true; } @@ -203,7 +203,7 @@ void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) { } items.write[p_idx].icon_transposed = p_transposed; - update(); + queue_redraw(); shape_changed = true; } @@ -224,7 +224,7 @@ void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) { } items.write[p_idx].icon_region = p_region; - update(); + queue_redraw(); shape_changed = true; } @@ -245,7 +245,7 @@ void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) { } items.write[p_idx].icon_modulate = p_modulate; - update(); + queue_redraw(); } Color ItemList::get_item_icon_modulate(int p_idx) const { @@ -265,7 +265,7 @@ void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_colo } items.write[p_idx].custom_bg = p_custom_bg_color; - update(); + queue_redraw(); } Color ItemList::get_item_custom_bg_color(int p_idx) const { @@ -285,7 +285,7 @@ void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_colo } items.write[p_idx].custom_fg = p_custom_fg_color; - update(); + queue_redraw(); } Color ItemList::get_item_custom_fg_color(int p_idx) const { @@ -305,7 +305,7 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) { } items.write[p_idx].tag_icon = p_tag_icon; - update(); + queue_redraw(); shape_changed = true; } @@ -340,7 +340,7 @@ void ItemList::set_item_disabled(int p_idx, bool p_disabled) { } items.write[p_idx].disabled = p_disabled; - update(); + queue_redraw(); } bool ItemList::is_item_disabled(int p_idx) const { @@ -359,7 +359,7 @@ void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) { } items.write[p_idx].metadata = p_metadata; - update(); + queue_redraw(); shape_changed = true; } @@ -387,7 +387,7 @@ void ItemList::select(int p_idx, bool p_single) { items.write[p_idx].selected = true; } } - update(); + queue_redraw(); } void ItemList::deselect(int p_idx) { @@ -399,7 +399,7 @@ void ItemList::deselect(int p_idx) { } else { items.write[p_idx].selected = false; } - update(); + queue_redraw(); } void ItemList::deselect_all() { @@ -411,7 +411,7 @@ void ItemList::deselect_all() { items.write[i].selected = false; } current = -1; - update(); + queue_redraw(); } bool ItemList::is_selected(int p_idx) const { @@ -431,7 +431,7 @@ void ItemList::set_current(int p_current) { select(p_current, true); } else { current = p_current; - update(); + queue_redraw(); } } @@ -451,7 +451,7 @@ void ItemList::move_item(int p_from_idx, int p_to_idx) { items.remove_at(p_from_idx); items.insert(p_to_idx, item); - update(); + queue_redraw(); shape_changed = true; notify_property_list_changed(); } @@ -464,7 +464,7 @@ void ItemList::set_item_count(int p_count) { } items.resize(p_count); - update(); + queue_redraw(); shape_changed = true; notify_property_list_changed(); } @@ -480,7 +480,7 @@ void ItemList::remove_item(int p_idx) { if (current == p_idx) { current = -1; } - update(); + queue_redraw(); shape_changed = true; defer_select_single = -1; notify_property_list_changed(); @@ -490,7 +490,7 @@ void ItemList::clear() { items.clear(); current = -1; ensure_selected_visible = false; - update(); + queue_redraw(); shape_changed = true; defer_select_single = -1; notify_property_list_changed(); @@ -504,7 +504,7 @@ void ItemList::set_fixed_column_width(int p_size) { } fixed_column_width = p_size; - update(); + queue_redraw(); shape_changed = true; } @@ -518,7 +518,7 @@ void ItemList::set_same_column_width(bool p_enable) { } same_column_width = p_enable; - update(); + queue_redraw(); shape_changed = true; } @@ -532,14 +532,14 @@ void ItemList::set_max_text_lines(int p_lines) { max_text_lines = p_lines; for (int i = 0; i < items.size(); i++) { if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { - items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND); + items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES); items.write[i].text_buf->set_max_lines_visible(p_lines); } else { items.write[i].text_buf->set_break_flags(TextServer::BREAK_NONE); } } shape_changed = true; - update(); + queue_redraw(); } } @@ -555,7 +555,7 @@ void ItemList::set_max_columns(int p_amount) { } max_columns = p_amount; - update(); + queue_redraw(); shape_changed = true; } @@ -569,7 +569,7 @@ void ItemList::set_select_mode(SelectMode p_mode) { } select_mode = p_mode; - update(); + queue_redraw(); } ItemList::SelectMode ItemList::get_select_mode() const { @@ -582,13 +582,13 @@ void ItemList::set_icon_mode(IconMode p_mode) { icon_mode = p_mode; for (int i = 0; i < items.size(); i++) { if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { - items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND); + items.write[i].text_buf->set_break_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_TRIM_EDGE_SPACES); } else { items.write[i].text_buf->set_break_flags(TextServer::BREAK_NONE); } } shape_changed = true; - update(); + queue_redraw(); } } @@ -596,16 +596,16 @@ ItemList::IconMode ItemList::get_icon_mode() const { return icon_mode; } -void ItemList::set_fixed_icon_size(const Size2 &p_size) { +void ItemList::set_fixed_icon_size(const Size2i &p_size) { if (fixed_icon_size == p_size) { return; } fixed_icon_size = p_size; - update(); + queue_redraw(); } -Size2 ItemList::get_fixed_icon_size() const { +Size2i ItemList::get_fixed_icon_size() const { return fixed_icon_size; } @@ -655,8 +655,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid() && mb->is_pressed()) { search_string = ""; //any mousepress cancels Vector2 pos = mb->get_position(); - Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg")); - pos -= bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y += scroll_bar->get_value(); if (is_layout_rtl()) { @@ -680,7 +679,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { if (closest != -1 && (mb->get_button_index() == MouseButton::LEFT || (allow_rmb_select && mb->get_button_index() == MouseButton::RIGHT))) { int i = closest; - if (select_mode == SELECT_MULTI && items[i].selected && mb->is_command_pressed()) { + if (select_mode == SELECT_MULTI && items[i].selected && mb->is_command_or_control_pressed()) { deselect(i); emit_signal(SNAME("multi_selected"), i, false); @@ -703,13 +702,13 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { emit_signal(SNAME("item_clicked"), i, get_local_mouse_position(), mb->get_button_index()); } else { - if (!mb->is_double_click() && !mb->is_command_pressed() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MouseButton::LEFT) { + if (!mb->is_double_click() && !mb->is_command_or_control_pressed() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MouseButton::LEFT) { defer_select_single = i; return; } if (!items[i].selected || allow_reselect) { - select(i, select_mode == SELECT_SINGLE || !mb->is_command_pressed()); + select(i, select_mode == SELECT_SINGLE || !mb->is_command_or_control_pressed()); if (select_mode == SELECT_SINGLE) { emit_signal(SNAME("item_selected"), i); @@ -961,7 +960,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { void ItemList::ensure_current_is_visible() { ensure_selected_visible = true; - update(); + queue_redraw(); } static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) { @@ -980,11 +979,36 @@ static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) { return Rect2(ofs_x, ofs_y, tex_width, tex_height); } +void ItemList::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + theme_cache.v_separation = get_theme_constant(SNAME("v_separation")); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); + theme_cache.focus_style = get_theme_stylebox(SNAME("focus")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color")); + theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + + theme_cache.line_separation = get_theme_constant(SNAME("line_separation")); + theme_cache.icon_margin = get_theme_constant(SNAME("icon_margin")); + theme_cache.selected_style = get_theme_stylebox(SNAME("selected")); + theme_cache.selected_focus_style = get_theme_stylebox(SNAME("selected_focus")); + theme_cache.cursor_style = get_theme_stylebox(SNAME("cursor_unfocused")); + theme_cache.cursor_focus_style = get_theme_stylebox(SNAME("cursor")); + theme_cache.guide_color = get_theme_color(SNAME("guide_color")); +} + void ItemList::_notification(int p_what) { switch (p_what) { case NOTIFICATION_RESIZED: { shape_changed = true; - update(); + queue_redraw(); } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: @@ -994,41 +1018,36 @@ void ItemList::_notification(int p_what) { _shape(i); } shape_changed = true; - update(); + queue_redraw(); } break; case 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)); + scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, theme_cache.panel_style->get_margin(SIDE_TOP)); + scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -theme_cache.panel_style->get_margin(SIDE_BOTTOM)); Size2 size = get_size(); - int width = size.width - bg->get_minimum_size().width; + int width = size.width - theme_cache.panel_style->get_minimum_size().width; - draw_style_box(bg, Rect2(Point2(), size)); + draw_style_box(theme_cache.panel_style, Rect2(Point2(), size)); - int hseparation = get_theme_constant(SNAME("h_separation")); - int vseparation = get_theme_constant(SNAME("v_separation")); - 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; + Ref<StyleBox> cursor; - 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")); + if (has_focus()) { + sbsel = theme_cache.selected_focus_style; + cursor = theme_cache.cursor_focus_style; + } else { + sbsel = theme_cache.selected_style; + cursor = theme_cache.cursor_style; + } 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")); - 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)); + draw_style_box(theme_cache.focus_style, Rect2(Point2(), size)); RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false); } @@ -1047,9 +1066,9 @@ void ItemList::_notification(int p_what) { if (!items[i].text.is_empty()) { if (icon_mode == ICON_MODE_TOP) { - minsize.y += icon_margin; + minsize.y += theme_cache.icon_margin; } else { - minsize.x += icon_margin; + minsize.x += theme_cache.icon_margin; } } } @@ -1067,7 +1086,7 @@ void ItemList::_notification(int p_what) { 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; + minsize.y += s.height + theme_cache.line_separation * max_text_lines; } else { minsize.y += s.height; } @@ -1084,13 +1103,13 @@ void ItemList::_notification(int p_what) { max_column_width = MAX(max_column_width, minsize.x); // elements need to adapt to the selected size - minsize.y += vseparation; - minsize.x += hseparation; + minsize.y += theme_cache.v_separation; + minsize.x += theme_cache.h_separation; items.write[i].rect_cache.size = minsize; items.write[i].min_rect_cache.size = minsize; } - int fit_size = size.x - bg->get_minimum_size().width - mw; + int fit_size = size.x - theme_cache.panel_style->get_minimum_size().width - mw; //2-attempt best fit current_columns = 0x7FFFFFFF; @@ -1118,11 +1137,11 @@ void ItemList::_notification(int p_what) { } 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; + ofs.x += items[i].rect_cache.size.x + theme_cache.h_separation; col++; if (col == current_columns) { if (i < items.size() - 1) { - separators.push_back(ofs.y + max_h + vseparation / 2); + separators.push_back(ofs.y + max_h + theme_cache.v_separation / 2); } for (int j = i; j >= 0 && col > 0; j--, col--) { @@ -1130,7 +1149,7 @@ void ItemList::_notification(int p_what) { } ofs.x = 0; - ofs.y += max_h + vseparation; + ofs.y += max_h + theme_cache.v_separation; col = 0; max_h = 0; } @@ -1141,10 +1160,10 @@ void ItemList::_notification(int p_what) { } if (all_fit) { - float page = MAX(0, size.height - bg->get_minimum_size().height); + float page = MAX(0, size.height - theme_cache.panel_style->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; + auto_height_value = ofs.y + max_h + theme_cache.panel_style->get_minimum_size().height; } scroll_bar->set_max(max); scroll_bar->set_page(page); @@ -1185,7 +1204,7 @@ void ItemList::_notification(int p_what) { ensure_selected_visible = false; - Vector2 base_ofs = bg->get_offset(); + Vector2 base_ofs = theme_cache.panel_style->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 @@ -1229,10 +1248,10 @@ void ItemList::_notification(int p_what) { 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; + r.position.y -= theme_cache.v_separation / 2; + r.size.y += theme_cache.v_separation; + r.position.x -= theme_cache.h_separation / 2; + r.size.x += theme_cache.h_separation; if (rtl) { r.position.x = size.width - r.position.x - r.size.x; @@ -1245,10 +1264,10 @@ void ItemList::_notification(int p_what) { 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; + r.position.y -= theme_cache.v_separation / 2; + r.size.y += theme_cache.v_separation; + r.position.x -= theme_cache.h_separation / 2; + r.size.x += theme_cache.h_separation; if (rtl) { r.position.x = size.width - r.position.x - r.size.x; @@ -1274,11 +1293,11 @@ void ItemList::_notification(int p_what) { 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; + pos.y += theme_cache.icon_margin; + text_ofs.y = icon_size.height + theme_cache.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; + text_ofs.x = icon_size.width + theme_cache.icon_margin; } Rect2 draw_rect = Rect2(pos, icon_size); @@ -1329,7 +1348,7 @@ void ItemList::_notification(int p_what) { max_len = size2.x; } - Color modulate = items[i].selected ? font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color); + Color modulate = items[i].selected ? theme_cache.font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : theme_cache.font_color); if (items[i].disabled) { modulate.a *= 0.5; } @@ -1344,8 +1363,8 @@ void ItemList::_notification(int p_what) { items.write[i].text_buf->set_alignment(HORIZONTAL_ALIGNMENT_CENTER); - 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 (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { + items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color); } items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate); @@ -1375,8 +1394,8 @@ void ItemList::_notification(int p_what) { 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 (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { + items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, theme_cache.font_outline_size, theme_cache.font_outline_color); } if (width - text_ofs.x > 0) { @@ -1388,10 +1407,10 @@ void ItemList::_notification(int p_what) { 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; + r.position.y -= theme_cache.v_separation / 2; + r.size.y += theme_cache.v_separation; + r.position.x -= theme_cache.h_separation / 2; + r.size.x += theme_cache.h_separation; if (rtl) { r.position.x = size.width - r.position.x - r.size.x; @@ -1423,20 +1442,19 @@ void ItemList::_notification(int p_what) { } const int y = base_ofs.y + separators[i]; - draw_line(Vector2(bg->get_margin(SIDE_LEFT), y), Vector2(width, y), guide_color); + draw_line(Vector2(theme_cache.panel_style->get_margin(SIDE_LEFT), y), Vector2(width, y), theme_cache.guide_color); } } break; } } void ItemList::_scroll_changed(double) { - update(); + queue_redraw(); } int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const { Vector2 pos = p_pos; - Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg")); - pos -= bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y += scroll_bar->get_value(); if (is_layout_rtl()) { @@ -1473,8 +1491,7 @@ bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const { } Vector2 pos = p_pos; - Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg")); - pos -= bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y += scroll_bar->get_value(); if (is_layout_rtl()) { @@ -1505,7 +1522,7 @@ String ItemList::get_tooltip(const Point2 &p_pos) const { void ItemList::sort_items_by_text() { items.sort(); - update(); + queue_redraw(); shape_changed = true; if (select_mode == SELECT_SINGLE) { @@ -1593,7 +1610,7 @@ void ItemList::set_auto_height(bool p_enable) { auto_height = p_enable; shape_changed = true; - update(); + queue_redraw(); } bool ItemList::has_auto_height() const { @@ -1607,7 +1624,7 @@ void ItemList::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) items.write[i].text_buf->set_text_overrun_behavior(p_behavior); } shape_changed = true; - update(); + queue_redraw(); } } @@ -1813,7 +1830,7 @@ void ItemList::_bind_methods() { ADD_GROUP("Icon", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_mode", PROPERTY_HINT_ENUM, "Top,Left"), "set_icon_mode", "get_icon_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "icon_scale"), "set_icon_scale", "get_icon_scale"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fixed_icon_size", PROPERTY_HINT_NONE, "suffix:px"), "set_fixed_icon_size", "get_fixed_icon_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "fixed_icon_size", PROPERTY_HINT_NONE, "suffix:px"), "set_fixed_icon_size", "get_fixed_icon_size"); BIND_ENUM_CONSTANT(ICON_MODE_TOP); BIND_ENUM_CONSTANT(ICON_MODE_LEFT); diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 21bd22759c..4b1b9d9282 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -109,23 +109,45 @@ private: int max_columns = 1; Size2 fixed_icon_size; - Size2 max_item_size_cache; int defer_select_single = -1; - bool allow_rmb_select = false; - bool allow_reselect = false; real_t icon_scale = 1.0; bool do_autoscroll_to_bottom = false; + struct ThemeCache { + int h_separation = 0; + int v_separation = 0; + + Ref<StyleBox> panel_style; + Ref<StyleBox> focus_style; + + Ref<Font> font; + int font_size = 0; + Color font_color; + Color font_selected_color; + int font_outline_size = 0; + Color font_outline_color; + + int line_separation = 0; + int icon_margin = 0; + Ref<StyleBox> selected_style; + Ref<StyleBox> selected_focus_style; + Ref<StyleBox> cursor_style; + Ref<StyleBox> cursor_focus_style; + Color guide_color; + } theme_cache; + void _scroll_changed(double); void _shape(int p_idx); protected: + virtual void _update_theme_item_cache() override; + void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -222,8 +244,8 @@ public: void set_icon_mode(IconMode p_mode); IconMode get_icon_mode() const; - void set_fixed_icon_size(const Size2 &p_size); - Size2 get_fixed_icon_size() const; + void set_fixed_icon_size(const Size2i &p_size); + Size2i get_fixed_icon_size() const; void set_allow_rmb_select(bool p_allow); bool get_allow_rmb_select() const; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index fa7d4195cb..306ca3d340 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -44,7 +44,7 @@ void Label::set_autowrap_mode(TextServer::AutowrapMode p_mode) { autowrap_mode = p_mode; lines_dirty = true; - update(); + queue_redraw(); if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { update_minimum_size(); @@ -63,7 +63,7 @@ void Label::set_uppercase(bool p_uppercase) { uppercase = p_uppercase; dirty = true; - update(); + queue_redraw(); } bool Label::is_uppercase() const { @@ -71,7 +71,7 @@ bool Label::is_uppercase() const { } int Label::get_line_height(int p_line) const { - Ref<Font> font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); + Ref<Font> font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font; if (p_line >= 0 && p_line < lines_rid.size()) { return TS->shaped_text_get_size(lines_rid[p_line]).y; } else if (lines_rid.size() > 0) { @@ -81,13 +81,13 @@ int Label::get_line_height(int p_line) const { } return h; } else { - int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size")); + int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size; return font->get_height(font_size); } } void Label::_shape() { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label")); + Ref<StyleBox> style = theme_cache.normal_style; int width = (get_size().width - style->get_minimum_size().width); if (dirty || font_dirty) { @@ -99,8 +99,8 @@ void Label::_shape() { } else { TS->shaped_text_set_direction(text_rid, (TextServer::Direction)text_direction); } - const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); - int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size")); + const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font; + int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size; ERR_FAIL_COND(font.is_null()); String text = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text; if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) { @@ -143,8 +143,9 @@ void Label::_shape() { case TextServer::AUTOWRAP_OFF: break; } - PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags); + autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES; + PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags); for (int i = 0; i < line_breaks.size(); i = i + 2) { RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]); lines_rid.push_back(line); @@ -231,8 +232,8 @@ void Label::_shape() { } void Label::_update_visible() { - int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing"), SNAME("Label")); - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"), SNAME("Label")); + int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing; + Ref<StyleBox> style = theme_cache.normal_style; int lines_visible = lines_rid.size(); if (max_lines_visible >= 0 && lines_visible > max_lines_visible) { @@ -271,6 +272,22 @@ inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Col } } +void Label::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.normal_style = get_theme_stylebox(SNAME("normal")); + theme_cache.font = get_theme_font(SNAME("font")); + + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.line_spacing = get_theme_constant(SNAME("line_spacing")); + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color")); + theme_cache.font_shadow_offset = Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y"))); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size")); +} + void Label::_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { @@ -284,11 +301,11 @@ void Label::_notification(int p_what) { } dirty = true; - update(); + queue_redraw(); } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - update(); + queue_redraw(); } break; case NOTIFICATION_DRAW: { @@ -306,15 +323,15 @@ void Label::_notification(int p_what) { Size2 string_size; Size2 size = get_size(); - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - Ref<Font> font = (has_settings && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); - Color font_color = has_settings ? settings->get_font_color() : get_theme_color(SNAME("font_color")); - Color font_shadow_color = has_settings ? settings->get_shadow_color() : get_theme_color(SNAME("font_shadow_color")); - Point2 shadow_ofs = has_settings ? settings->get_shadow_offset() : Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y"))); - int line_spacing = has_settings ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing")); - Color font_outline_color = has_settings ? settings->get_outline_color() : get_theme_color(SNAME("font_outline_color")); - int outline_size = has_settings ? settings->get_outline_size() : get_theme_constant(SNAME("outline_size")); - int shadow_outline_size = has_settings ? settings->get_shadow_size() : get_theme_constant(SNAME("shadow_outline_size")); + Ref<StyleBox> style = theme_cache.normal_style; + Ref<Font> font = (has_settings && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font; + Color font_color = has_settings ? settings->get_font_color() : theme_cache.font_color; + Color font_shadow_color = has_settings ? settings->get_shadow_color() : theme_cache.font_shadow_color; + Point2 shadow_ofs = has_settings ? settings->get_shadow_offset() : theme_cache.font_shadow_offset; + int line_spacing = has_settings ? settings->get_line_spacing() : theme_cache.line_spacing; + Color font_outline_color = has_settings ? settings->get_outline_color() : theme_cache.font_outline_color; + int outline_size = has_settings ? settings->get_outline_size() : theme_cache.font_outline_size; + int shadow_outline_size = has_settings ? settings->get_shadow_size() : theme_cache.font_shadow_outline_size; bool rtl = (TS->shaped_text_get_inferred_direction(text_rid) == TextServer::DIRECTION_RTL); bool rtl_layout = is_layout_rtl(); @@ -544,7 +561,7 @@ void Label::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { font_dirty = true; - update(); + queue_redraw(); } break; case NOTIFICATION_RESIZED: { @@ -561,12 +578,12 @@ Size2 Label::get_minimum_size() const { Size2 min_size = minsize; - const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : get_theme_font(SNAME("font")); - int font_size = settings.is_valid() ? settings->get_font_size() : get_theme_font_size(SNAME("font_size")); + const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font; + int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size; min_size.height = MAX(min_size.height, font->get_height(font_size) + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM)); - Size2 min_style = get_theme_stylebox(SNAME("normal"))->get_minimum_size(); + Size2 min_style = theme_cache.normal_style->get_minimum_size(); if (autowrap_mode != TextServer::AUTOWRAP_OFF) { return Size2(1, (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) ? 1 : min_size.height) + min_style; } else { @@ -589,8 +606,8 @@ int Label::get_line_count() const { } int Label::get_visible_line_count() const { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - int line_spacing = settings.is_valid() ? settings->get_line_spacing() : get_theme_constant(SNAME("line_spacing")); + Ref<StyleBox> style = theme_cache.normal_style; + int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing; int lines_visible = 0; float total_h = 0.0; for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { @@ -623,7 +640,7 @@ void Label::set_horizontal_alignment(HorizontalAlignment p_alignment) { } horizontal_alignment = p_alignment; - update(); + queue_redraw(); } HorizontalAlignment Label::get_horizontal_alignment() const { @@ -638,7 +655,7 @@ void Label::set_vertical_alignment(VerticalAlignment p_alignment) { } vertical_alignment = p_alignment; - update(); + queue_redraw(); } VerticalAlignment Label::get_vertical_alignment() const { @@ -655,13 +672,13 @@ void Label::set_text(const String &p_string) { if (visible_ratio < 1) { visible_chars = get_total_character_count() * visible_ratio; } - update(); + queue_redraw(); update_minimum_size(); } void Label::_invalidate() { font_dirty = true; - update(); + queue_redraw(); } void Label::set_label_settings(const Ref<LabelSettings> &p_settings) { @@ -686,7 +703,7 @@ void Label::set_text_direction(Control::TextDirection p_text_direction) { if (text_direction != p_text_direction) { text_direction = p_text_direction; font_dirty = true; - update(); + queue_redraw(); } } @@ -694,7 +711,7 @@ void Label::set_structured_text_bidi_override(TextServer::StructuredTextParser p if (st_parser != p_parser) { st_parser = p_parser; dirty = true; - update(); + queue_redraw(); } } @@ -709,7 +726,7 @@ void Label::set_structured_text_bidi_override_options(Array p_args) { st_args = p_args; dirty = true; - update(); + queue_redraw(); } Array Label::get_structured_text_bidi_override_options() const { @@ -724,7 +741,7 @@ void Label::set_language(const String &p_language) { if (language != p_language) { language = p_language; dirty = true; - update(); + queue_redraw(); } } @@ -738,7 +755,7 @@ void Label::set_clip_text(bool p_clip) { } clip = p_clip; - update(); + queue_redraw(); update_minimum_size(); } @@ -753,7 +770,7 @@ void Label::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) { overrun_behavior = p_behavior; lines_dirty = true; - update(); + queue_redraw(); if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { update_minimum_size(); } @@ -778,7 +795,7 @@ void Label::set_visible_characters(int p_amount) { if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) { dirty = true; } - update(); + queue_redraw(); } } @@ -788,10 +805,10 @@ int Label::get_visible_characters() const { void Label::set_visible_ratio(float p_ratio) { if (visible_ratio != p_ratio) { - if (visible_ratio >= 1.0) { + if (p_ratio >= 1.0) { visible_chars = -1; visible_ratio = 1.0; - } else if (visible_ratio < 0.0) { + } else if (p_ratio < 0.0) { visible_chars = 0; visible_ratio = 0.0; } else { @@ -802,7 +819,7 @@ void Label::set_visible_ratio(float p_ratio) { if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) { dirty = true; } - update(); + queue_redraw(); } } @@ -818,7 +835,7 @@ void Label::set_visible_characters_behavior(TextServer::VisibleCharactersBehavio if (visible_chars_behavior != p_behavior) { visible_chars_behavior = p_behavior; dirty = true; - update(); + queue_redraw(); } } @@ -831,7 +848,7 @@ void Label::set_lines_skipped(int p_lines) { lines_skipped = p_lines; _update_visible(); - update(); + queue_redraw(); } int Label::get_lines_skipped() const { @@ -845,7 +862,7 @@ void Label::set_max_lines_visible(int p_lines) { max_lines_visible = p_lines; _update_visible(); - update(); + queue_redraw(); } int Label::get_max_lines_visible() const { diff --git a/scene/gui/label.h b/scene/gui/label.h index 65831cab6e..b79c94a5ba 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -67,13 +67,28 @@ private: Ref<LabelSettings> settings; + struct ThemeCache { + Ref<StyleBox> normal_style; + Ref<Font> font; + + int font_size = 0; + int line_spacing = 0; + Color font_color; + Color font_shadow_color; + Point2 font_shadow_offset; + Color font_outline_color; + int font_outline_size; + int font_shadow_outline_size; + } theme_cache; + void _update_visible(); void _shape(); void _invalidate(); protected: - void _notification(int p_what); + virtual void _update_theme_item_cache() override; + void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 34a60b907c..be94337c89 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -51,7 +51,7 @@ void LineEdit::_swap_current_input_direction() { input_direction = TEXT_DIRECTION_LTR; } set_caret_column(get_caret_column()); - update(); + queue_redraw(); } void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) { @@ -285,7 +285,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { if (!text.is_empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; - update(); + queue_redraw(); return; } @@ -348,7 +348,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { } } - update(); + queue_redraw(); } else { if (selection.enabled && !pass && b->get_button_index() == MouseButton::LEFT && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { @@ -375,7 +375,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { show_virtual_keyboard(); } - update(); + queue_redraw(); } Ref<InputEventMouseMotion> m = p_event; @@ -385,7 +385,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { bool last_press_inside = clear_button_status.pressing_inside; clear_button_status.pressing_inside = clear_button_status.press_attempt && _is_over_clear_button(m->get_position()); if (last_press_inside != clear_button_status.pressing_inside) { - update(); + queue_redraw(); } } @@ -448,7 +448,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { if (context_menu_enabled) { if (k->is_action("ui_menu", true)) { _ensure_menu(); - Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")))) / 2); + Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2); menu->set_position(get_screen_position() + pos); menu->reset_size(); menu->popup(); @@ -589,7 +589,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { // Allow unicode handling if: // * No Modifiers are pressed (except shift) - bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed()); + bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed()); if (allow_unicode_handling && editable && k->get_unicode() >= 32) { // Handle Unicode (if no modifiers active) @@ -613,7 +613,7 @@ void LineEdit::set_horizontal_alignment(HorizontalAlignment p_alignment) { alignment = p_alignment; _shape(); - update(); + queue_redraw(); } HorizontalAlignment LineEdit::get_horizontal_alignment() const { @@ -681,7 +681,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { } text_changed_dirty = true; } - update(); + queue_redraw(); } } @@ -696,18 +696,45 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { if (!clear_button_enabled || !has_point(p_pos)) { return false; } - Ref<Texture2D> icon = Control::get_theme_icon(SNAME("clear")); - int x_ofs = get_theme_stylebox(SNAME("normal"))->get_margin(SIDE_RIGHT); + Ref<Texture2D> icon = theme_cache.clear_icon; + int x_ofs = theme_cache.normal->get_margin(SIDE_RIGHT); return p_pos.x > get_size().width - icon->get_width() - x_ofs; } +void LineEdit::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.normal = get_theme_stylebox(SNAME("normal")); + theme_cache.read_only = get_theme_stylebox(SNAME("read_only")); + theme_cache.focus = get_theme_stylebox(SNAME("focus")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_uneditable_color = get_theme_color(SNAME("font_uneditable_color")); + theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color")); + theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + theme_cache.font_placeholder_color = get_theme_color(SNAME("font_placeholder_color")); + theme_cache.caret_width = get_theme_constant(SNAME("caret_width")); + theme_cache.caret_color = get_theme_color(SNAME("caret_color")); + theme_cache.minimum_character_width = get_theme_constant(SNAME("minimum_character_width")); + theme_cache.selection_color = get_theme_color(SNAME("selection_color")); + + theme_cache.clear_icon = get_theme_icon(SNAME("clear")); + theme_cache.clear_button_color = get_theme_color(SNAME("clear_button_color")); + theme_cache.clear_button_color_pressed = get_theme_color(SNAME("clear_button_color_pressed")); + + theme_cache.base_scale = get_theme_default_base_scale(); +} + void LineEdit::_notification(int p_what) { switch (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_GET("text_editor/appearance/caret/caret_blink")); - set_caret_blink_speed(EDITOR_GET("text_editor/appearance/caret/caret_blink_speed")); + set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval")); 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)); @@ -725,32 +752,32 @@ void LineEdit::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_THEME_CHANGED: { _shape(); - update(); + queue_redraw(); } break; case NOTIFICATION_TRANSLATION_CHANGED: { placeholder_translated = atr(placeholder); _shape(); - update(); + queue_redraw(); } break; case NOTIFICATION_WM_WINDOW_FOCUS_IN: { window_has_focus = true; draw_caret = true; - update(); + queue_redraw(); } break; case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { window_has_focus = false; draw_caret = false; - update(); + queue_redraw(); } break; case NOTIFICATION_INTERNAL_PROCESS: { if (caret_blinking) { caret_blink_timer += get_process_delta_time(); - if (caret_blink_timer >= caret_blink_speed) { + if (caret_blink_timer >= caret_blink_interval) { caret_blink_timer = 0.0; _toggle_draw_caret(); } @@ -771,19 +798,19 @@ void LineEdit::_notification(int p_what) { RID ci = get_canvas_item(); - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; if (!is_editable()) { - style = get_theme_stylebox(SNAME("read_only")); + style = theme_cache.read_only; draw_caret = false; } - Ref<Font> font = get_theme_font(SNAME("font")); + Ref<Font> font = theme_cache.font; if (!flat) { style->draw(ci, Rect2(Point2(), size)); } if (has_focus()) { - get_theme_stylebox(SNAME("focus"))->draw(ci, Rect2(Point2(), size)); + theme_cache.focus->draw(ci, Rect2(Point2(), size)); } int x_ofs = 0; @@ -821,25 +848,30 @@ void LineEdit::_notification(int p_what) { int y_area = height - style->get_minimum_size().height; int y_ofs = style->get_offset().y + (y_area - text_height) / 2; - Color selection_color = get_theme_color(SNAME("selection_color")); - Color font_color = get_theme_color(is_editable() ? SNAME("font_color") : SNAME("font_uneditable_color")); - Color font_selected_color = get_theme_color(SNAME("font_selected_color")); - Color caret_color = get_theme_color(SNAME("caret_color")); + Color selection_color = theme_cache.selection_color; + Color font_color; + if (is_editable()) { + font_color = theme_cache.font_color; + } else { + font_color = theme_cache.font_uneditable_color; + } + Color font_selected_color = theme_cache.font_selected_color; + Color caret_color = theme_cache.caret_color; // Draw placeholder color. if (using_placeholder) { - font_color = get_theme_color(SNAME("font_placeholder_color")); + font_color = theme_cache.font_placeholder_color; } bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; + Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; Color color_icon(1, 1, 1, !is_editable() ? .5 * .9 : .9); if (display_clear_icon) { if (clear_button_status.press_attempt && clear_button_status.pressing_inside) { - color_icon = get_theme_color(SNAME("clear_button_color_pressed")); + color_icon = theme_cache.clear_button_color_pressed; } else { - color_icon = get_theme_color(SNAME("clear_button_color")); + color_icon = theme_cache.clear_button_color; } } @@ -879,8 +911,8 @@ void LineEdit::_notification(int p_what) { // Draw text. ofs.y += TS->shaped_text_get_ascent(text_rid); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); + Color font_outline_color = theme_cache.font_outline_color; + int outline_size = theme_cache.font_outline_size; if (outline_size > 0 && font_outline_color.a > 0) { Vector2 oofs = ofs; for (int i = 0; i < gl_size; i++) { @@ -918,7 +950,7 @@ void LineEdit::_notification(int p_what) { ofs.x = x_ofs + scroll_offset; if (draw_caret || drag_caret_force_displayed) { // 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()); + const int caret_width = theme_cache.caret_width * MAX(1, theme_cache.base_scale); if (ime_text.length() == 0) { // Normal caret. @@ -926,7 +958,7 @@ void LineEdit::_notification(int p_what) { if (caret.l_caret == Rect2() && caret.t_caret == Rect2()) { // No carets, add one at the start. - int h = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size"))); + int h = theme_cache.font->get_height(theme_cache.font_size); int y = style->get_offset().y + (y_area - h) / 2; if (rtl) { caret.l_dir = TextServer::DIRECTION_RTL; @@ -1052,7 +1084,7 @@ void LineEdit::_notification(int p_what) { _shape(); set_caret_column(caret_column); // Update scroll_offset - update(); + queue_redraw(); } } break; @@ -1193,7 +1225,7 @@ void LineEdit::shift_selection_check_post(bool p_shift) { } void LineEdit::set_caret_at_pixel_pos(int p_x) { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; bool rtl = is_layout_rtl(); int x_ofs = 0; @@ -1226,7 +1258,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) { bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; + Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); @@ -1241,7 +1273,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) { } Vector2 LineEdit::get_caret_pixel_pos() { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; bool rtl = is_layout_rtl(); int x_ofs = 0; @@ -1274,7 +1306,7 @@ Vector2 LineEdit::get_caret_pixel_pos() { bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; + Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); @@ -1357,16 +1389,16 @@ bool LineEdit::is_caret_force_displayed() const { void LineEdit::set_caret_force_displayed(const bool p_enabled) { caret_force_displayed = p_enabled; set_caret_blink_enabled(caret_blink_enabled); - update(); + queue_redraw(); } -float LineEdit::get_caret_blink_speed() const { - return caret_blink_speed; +float LineEdit::get_caret_blink_interval() const { + return caret_blink_interval; } -void LineEdit::set_caret_blink_speed(const float p_speed) { - ERR_FAIL_COND(p_speed <= 0); - caret_blink_speed = p_speed; +void LineEdit::set_caret_blink_interval(const float p_interval) { + ERR_FAIL_COND(p_interval <= 0); + caret_blink_interval = p_interval; } void LineEdit::_reset_caret_blink_timer() { @@ -1374,7 +1406,7 @@ void LineEdit::_reset_caret_blink_timer() { draw_caret = true; if (has_focus()) { caret_blink_timer = 0.0; - update(); + queue_redraw(); } } } @@ -1382,7 +1414,7 @@ void LineEdit::_reset_caret_blink_timer() { void LineEdit::_toggle_draw_caret() { draw_caret = !draw_caret; if (is_visible_in_tree() && ((has_focus() && window_has_focus) || caret_force_displayed)) { - update(); + queue_redraw(); } } @@ -1425,7 +1457,7 @@ void LineEdit::set_text(String p_text) { insert_text_at_caret(p_text); _create_undo_state(); - update(); + queue_redraw(); caret_column = 0; scroll_offset = 0.0; } @@ -1445,7 +1477,7 @@ void LineEdit::set_text_direction(Control::TextDirection p_text_direction) { menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); } - update(); + queue_redraw(); } } @@ -1457,7 +1489,7 @@ void LineEdit::set_language(const String &p_language) { if (language != p_language) { language = p_language; _shape(); - update(); + queue_redraw(); } } @@ -1472,7 +1504,7 @@ void LineEdit::set_draw_control_chars(bool p_draw_control_chars) { menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars); } _shape(); - update(); + queue_redraw(); } } @@ -1484,7 +1516,7 @@ void LineEdit::set_structured_text_bidi_override(TextServer::StructuredTextParse if (st_parser != p_parser) { st_parser = p_parser; _shape(); - update(); + queue_redraw(); } } @@ -1495,7 +1527,7 @@ TextServer::StructuredTextParser LineEdit::get_structured_text_bidi_override() c void LineEdit::set_structured_text_bidi_override_options(Array p_args) { st_args = p_args; _shape(); - update(); + queue_redraw(); } Array LineEdit::get_structured_text_bidi_override_options() const { @@ -1534,7 +1566,7 @@ void LineEdit::set_placeholder(String p_text) { placeholder = p_text; placeholder_translated = atr(placeholder); _shape(); - update(); + queue_redraw(); } String LineEdit::get_placeholder() const { @@ -1559,7 +1591,7 @@ void LineEdit::set_caret_column(int p_column) { return; } - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; bool rtl = is_layout_rtl(); int x_ofs = 0; @@ -1593,7 +1625,7 @@ void LineEdit::set_caret_column(int p_column) { bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; + Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); @@ -1614,7 +1646,7 @@ void LineEdit::set_caret_column(int p_column) { } scroll_offset = MIN(0, scroll_offset); - update(); + queue_redraw(); } int LineEdit::get_caret_column() const { @@ -1660,19 +1692,19 @@ void LineEdit::clear_internal() { undo_text = ""; text = ""; _shape(); - update(); + queue_redraw(); } Size2 LineEdit::get_minimum_size() const { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); + Ref<StyleBox> style = theme_cache.normal; + Ref<Font> font = theme_cache.font; + int font_size = theme_cache.font_size; Size2 min_size; // Minimum size of text. float em_space_size = font->get_char_size('M', font_size).x; - min_size.width = get_theme_constant(SNAME("minimum_character_width")) * em_space_size; + min_size.width = theme_cache.minimum_character_width * em_space_size; if (expand_to_text_length) { // Add a space because some fonts are too exact, and because caret needs a bit more when at the end. @@ -1688,9 +1720,8 @@ Size2 LineEdit::get_minimum_size() const { icon_max_width = right_icon->get_width(); } if (clear_button_enabled) { - Ref<Texture2D> clear_icon = Control::get_theme_icon(SNAME("clear")); - min_size.height = MAX(min_size.height, clear_icon->get_height()); - icon_max_width = MAX(icon_max_width, clear_icon->get_width()); + min_size.height = MAX(min_size.height, theme_cache.clear_icon->get_height()); + icon_max_width = MAX(icon_max_width, theme_cache.clear_icon->get_width()); } min_size.width += icon_max_width; @@ -1704,7 +1735,7 @@ void LineEdit::deselect() { selection.enabled = false; selection.creating = false; selection.double_click = false; - update(); + queue_redraw(); } bool LineEdit::has_selection() const { @@ -1768,7 +1799,7 @@ void LineEdit::select_all() { selection.begin = 0; selection.end = text.length(); selection.enabled = true; - update(); + queue_redraw(); } void LineEdit::set_editable(bool p_editable) { @@ -1779,7 +1810,7 @@ void LineEdit::set_editable(bool p_editable) { editable = p_editable; update_minimum_size(); - update(); + queue_redraw(); } bool LineEdit::is_editable() const { @@ -1793,7 +1824,7 @@ void LineEdit::set_secret(bool p_secret) { pass = p_secret; _shape(); - update(); + queue_redraw(); } bool LineEdit::is_secret() const { @@ -1811,7 +1842,7 @@ void LineEdit::set_secret_character(const String &p_string) { secret_character = p_string; _shape(); - update(); + queue_redraw(); } String LineEdit::get_secret_character() const { @@ -1848,7 +1879,7 @@ void LineEdit::select(int p_from, int p_to) { selection.end = p_to; selection.creating = false; selection.double_click = false; - update(); + queue_redraw(); } bool LineEdit::is_text_field() const { @@ -2006,7 +2037,7 @@ PopupMenu *LineEdit::get_menu() const { void LineEdit::_editor_settings_changed() { #ifdef TOOLS_ENABLED 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")); + set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval")); #endif } @@ -2027,7 +2058,7 @@ void LineEdit::set_clear_button_enabled(bool p_enabled) { clear_button_enabled = p_enabled; _fit_to_width(); update_minimum_size(); - update(); + queue_redraw(); } bool LineEdit::is_clear_button_enabled() const { @@ -2104,7 +2135,7 @@ void LineEdit::set_right_icon(const Ref<Texture2D> &p_icon) { right_icon = p_icon; _fit_to_width(); update_minimum_size(); - update(); + queue_redraw(); } Ref<Texture2D> LineEdit::get_right_icon() { @@ -2114,7 +2145,7 @@ Ref<Texture2D> LineEdit::get_right_icon() { void LineEdit::set_flat(bool p_enabled) { if (flat != p_enabled) { flat = p_enabled; - update(); + queue_redraw(); } } @@ -2155,8 +2186,8 @@ void LineEdit::_shape() { } TS->shaped_text_set_preserve_control(text_rid, draw_control_chars); - const Ref<Font> &font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); + const Ref<Font> &font = theme_cache.font; + int font_size = theme_cache.font_size; ERR_FAIL_COND(font.is_null()); TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language); for (int i = 0; i < TextServer::SPACING_MAX; i++) { @@ -2176,12 +2207,12 @@ void LineEdit::_shape() { void LineEdit::_fit_to_width() { if (alignment == HORIZONTAL_ALIGNMENT_FILL) { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; int t_width = get_size().width - style->get_margin(SIDE_RIGHT) - style->get_margin(SIDE_LEFT); bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { - Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon; + Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; t_width -= r_icon->get_width(); } TS->shaped_text_fit_to_width(text_rid, MAX(t_width, full_width)); @@ -2243,7 +2274,7 @@ Key LineEdit::_get_menu_action_accelerator(const String &p_action) { } void LineEdit::_validate_property(PropertyInfo &p_property) const { - if (!caret_blink_enabled && p_property.name == "caret_blink_speed") { + if (!caret_blink_enabled && p_property.name == "caret_blink_interval") { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } @@ -2286,8 +2317,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled"), &LineEdit::is_caret_mid_grapheme_enabled); ClassDB::bind_method(D_METHOD("set_caret_force_displayed", "enabled"), &LineEdit::set_caret_force_displayed); ClassDB::bind_method(D_METHOD("is_caret_force_displayed"), &LineEdit::is_caret_force_displayed); - ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &LineEdit::set_caret_blink_speed); - ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &LineEdit::get_caret_blink_speed); + ClassDB::bind_method(D_METHOD("set_caret_blink_interval", "interval"), &LineEdit::set_caret_blink_interval); + ClassDB::bind_method(D_METHOD("get_caret_blink_interval"), &LineEdit::get_caret_blink_interval); ClassDB::bind_method(D_METHOD("set_max_length", "chars"), &LineEdit::set_max_length); ClassDB::bind_method(D_METHOD("get_max_length"), &LineEdit::get_max_length); ClassDB::bind_method(D_METHOD("insert_text_at_caret", "text"), &LineEdit::insert_text_at_caret); @@ -2388,7 +2419,7 @@ void LineEdit::_bind_methods() { ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_interval", "get_caret_blink_interval"); ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column", PROPERTY_HINT_RANGE, "0,1000,1,or_greater"), "set_caret_column", "get_caret_column"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "set_caret_force_displayed", "is_caret_force_displayed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled"); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index dabdaa3395..a4d5205f81 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -170,10 +170,35 @@ private: bool caret_blink_enabled = false; bool caret_force_displayed = false; bool draw_caret = true; - float caret_blink_speed = 0.65; + float caret_blink_interval = 0.65; double caret_blink_timer = 0.0; bool caret_blinking = false; + struct ThemeCache { + Ref<StyleBox> normal; + Ref<StyleBox> read_only; + Ref<StyleBox> focus; + + Ref<Font> font; + int font_size = 0; + Color font_color; + Color font_uneditable_color; + Color font_selected_color; + int font_outline_size; + Color font_outline_color; + Color font_placeholder_color; + int caret_width = 0; + Color caret_color; + int minimum_character_width = 0; + Color selection_color; + + Ref<Texture2D> clear_icon; + Color clear_button_color; + Color clear_button_color_pressed; + + float base_scale = 1.0; + } theme_cache; + bool _is_over_clear_button(const Point2 &p_pos) const; void _clear_undo_stack(); @@ -215,6 +240,7 @@ private: void _ensure_menu(); protected: + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override; @@ -285,8 +311,8 @@ public: bool is_caret_blink_enabled() const; void set_caret_blink_enabled(const bool p_enabled); - float get_caret_blink_speed() const; - void set_caret_blink_speed(const float p_speed); + float get_caret_blink_interval() const; + void set_caret_blink_interval(const float p_interval); void set_caret_force_displayed(const bool p_enabled); bool is_caret_force_displayed() const; diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index ee3f64e0e5..7219e86f52 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -33,8 +33,8 @@ #include "core/string/translation.h" void LinkButton::_shape() { - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); + Ref<Font> font = theme_cache.font; + int font_size = theme_cache.font_size; text_buf->clear(); if (text_direction == Control::TEXT_DIRECTION_INHERITED) { @@ -54,7 +54,7 @@ void LinkButton::set_text(const String &p_text) { xl_text = atr(text); _shape(); update_minimum_size(); - update(); + queue_redraw(); } String LinkButton::get_text() const { @@ -65,7 +65,7 @@ void LinkButton::set_structured_text_bidi_override(TextServer::StructuredTextPar if (st_parser != p_parser) { st_parser = p_parser; _shape(); - update(); + queue_redraw(); } } @@ -76,7 +76,7 @@ TextServer::StructuredTextParser LinkButton::get_structured_text_bidi_override() void LinkButton::set_structured_text_bidi_override_options(Array p_args) { st_args = p_args; _shape(); - update(); + queue_redraw(); } Array LinkButton::get_structured_text_bidi_override_options() const { @@ -88,7 +88,7 @@ void LinkButton::set_text_direction(Control::TextDirection p_text_direction) { if (text_direction != p_text_direction) { text_direction = p_text_direction; _shape(); - update(); + queue_redraw(); } } @@ -100,7 +100,7 @@ void LinkButton::set_language(const String &p_language) { if (language != p_language) { language = p_language; _shape(); - update(); + queue_redraw(); } } @@ -114,7 +114,7 @@ void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) { } underline_mode = p_underline_mode; - update(); + queue_redraw(); } LinkButton::UnderlineMode LinkButton::get_underline_mode() const { @@ -125,23 +125,43 @@ Size2 LinkButton::get_minimum_size() const { return text_buf->get_size(); } +void LinkButton::_update_theme_item_cache() { + BaseButton::_update_theme_item_cache(); + + theme_cache.focus = get_theme_stylebox(SNAME("focus")); + + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color")); + theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color")); + theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color")); + theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color")); + theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + + theme_cache.underline_spacing = get_theme_constant(SNAME("underline_spacing")); +} + void LinkButton::_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { xl_text = atr(text); _shape(); update_minimum_size(); - update(); + queue_redraw(); } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - update(); + queue_redraw(); } break; case NOTIFICATION_THEME_CHANGED: { _shape(); update_minimum_size(); - update(); + queue_redraw(); } break; case NOTIFICATION_DRAW: { @@ -153,9 +173,9 @@ void LinkButton::_notification(int p_what) { switch (get_draw_mode()) { case DRAW_NORMAL: { if (has_focus()) { - color = get_theme_color(SNAME("font_focus_color")); + color = theme_cache.font_focus_color; } else { - color = get_theme_color(SNAME("font_color")); + color = theme_cache.font_color; } do_underline = underline_mode == UNDERLINE_MODE_ALWAYS; @@ -163,35 +183,35 @@ void LinkButton::_notification(int p_what) { case DRAW_HOVER_PRESSED: case DRAW_PRESSED: { if (has_theme_color(SNAME("font_pressed_color"))) { - color = get_theme_color(SNAME("font_pressed_color")); + color = theme_cache.font_pressed_color; } else { - color = get_theme_color(SNAME("font_color")); + color = theme_cache.font_color; } do_underline = underline_mode != UNDERLINE_MODE_NEVER; } break; case DRAW_HOVER: { - color = get_theme_color(SNAME("font_hover_color")); + color = theme_cache.font_hover_color; do_underline = underline_mode != UNDERLINE_MODE_NEVER; } break; case DRAW_DISABLED: { - color = get_theme_color(SNAME("font_disabled_color")); + color = theme_cache.font_disabled_color; do_underline = underline_mode == UNDERLINE_MODE_ALWAYS; } break; } if (has_focus()) { - Ref<StyleBox> style = get_theme_stylebox(SNAME("focus")); + Ref<StyleBox> style = theme_cache.focus; style->draw(ci, Rect2(Point2(), size)); } int width = text_buf->get_line_width(); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); + Color font_outline_color = theme_cache.font_outline_color; + int outline_size = theme_cache.outline_size; if (is_layout_rtl()) { if (outline_size > 0 && font_outline_color.a > 0) { text_buf->draw_outline(get_canvas_item(), Vector2(size.width - width, 0), outline_size, font_outline_color); @@ -205,7 +225,7 @@ void LinkButton::_notification(int p_what) { } if (do_underline) { - int underline_spacing = get_theme_constant(SNAME("underline_spacing")) + text_buf->get_line_underline_position(); + int underline_spacing = theme_cache.underline_spacing + text_buf->get_line_underline_position(); int y = text_buf->get_line_ascent() + underline_spacing; if (is_layout_rtl()) { diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index 12a6a7618f..accd848163 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -55,10 +55,29 @@ private: TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT; Array st_args; + struct ThemeCache { + Ref<StyleBox> focus; + + Color font_color; + Color font_focus_color; + Color font_pressed_color; + Color font_hover_color; + Color font_hover_pressed_color; + Color font_disabled_color; + + Ref<Font> font; + int font_size = 0; + int outline_size = 0; + Color font_outline_color; + + int underline_spacing = 0; + } theme_cache; + void _shape(); protected: virtual Size2 get_minimum_size() const override; + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index fac37a8634..60fe681824 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -30,12 +30,16 @@ #include "margin_container.h" -Size2 MarginContainer::get_minimum_size() const { - int margin_left = get_theme_constant(SNAME("margin_left")); - int margin_top = get_theme_constant(SNAME("margin_top")); - int margin_right = get_theme_constant(SNAME("margin_right")); - int margin_bottom = get_theme_constant(SNAME("margin_bottom")); +void MarginContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.margin_left = get_theme_constant(SNAME("margin_left")); + theme_cache.margin_top = get_theme_constant(SNAME("margin_top")); + theme_cache.margin_right = get_theme_constant(SNAME("margin_right")); + theme_cache.margin_bottom = get_theme_constant(SNAME("margin_bottom")); +} +Size2 MarginContainer::get_minimum_size() const { Size2 max; for (int i = 0; i < get_child_count(); i++) { @@ -59,8 +63,8 @@ Size2 MarginContainer::get_minimum_size() const { } } - max.width += (margin_left + margin_right); - max.height += (margin_top + margin_bottom); + max.width += (theme_cache.margin_left + theme_cache.margin_right); + max.height += (theme_cache.margin_top + theme_cache.margin_bottom); return max; } @@ -86,11 +90,6 @@ Vector<int> MarginContainer::get_allowed_size_flags_vertical() const { void MarginContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { - int margin_left = get_theme_constant(SNAME("margin_left")); - int margin_top = get_theme_constant(SNAME("margin_top")); - int margin_right = get_theme_constant(SNAME("margin_right")); - int margin_bottom = get_theme_constant(SNAME("margin_bottom")); - Size2 s = get_size(); for (int i = 0; i < get_child_count(); i++) { @@ -102,9 +101,9 @@ void MarginContainer::_notification(int p_what) { continue; } - int w = s.width - margin_left - margin_right; - int h = s.height - margin_top - margin_bottom; - fit_child_in_rect(c, Rect2(margin_left, margin_top, w, h)); + int w = s.width - theme_cache.margin_left - theme_cache.margin_right; + int h = s.height - theme_cache.margin_top - theme_cache.margin_bottom; + fit_child_in_rect(c, Rect2(theme_cache.margin_left, theme_cache.margin_top, w, h)); } } break; diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h index f8a3c5bb11..5c33785170 100644 --- a/scene/gui/margin_container.h +++ b/scene/gui/margin_container.h @@ -36,7 +36,16 @@ class MarginContainer : public Container { GDCLASS(MarginContainer, Container); + struct ThemeCache { + int margin_left = 0; + int margin_top = 0; + int margin_right = 0; + int margin_bottom = 0; + } theme_cache; + protected: + virtual void _update_theme_item_cache() override; + void _notification(int p_what); public: diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 9b7b67d83e..d6bf84ea5a 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -95,7 +95,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) { selected_menu = focused_menu; } if (selected_menu != old_sel) { - update(); + queue_redraw(); } } @@ -137,22 +137,18 @@ void MenuBar::_open_popup(int p_index, bool p_focus_item) { if (p_focus_item) { for (int i = 0; i < pm->get_item_count(); i++) { if (!pm->is_item_disabled(i)) { - pm->set_current_index(i); + pm->set_focused_item(i); break; } } } - update(); + queue_redraw(); } void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (is_native_menu()) { - return; - } - if (!_is_focus_owner_in_shortcut_context()) { return; } @@ -212,7 +208,7 @@ void MenuBar::_popup_visibility_changed(bool p_visible) { active_menu = -1; focused_menu = -1; set_process_internal(false); - update(); + queue_redraw(); return; } @@ -253,7 +249,7 @@ void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) { DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, p_child->get_item_text(i), p_menu_name + "/" + itos(i)); _update_submenu(p_menu_name + "/" + itos(i), pm); } else { - int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, p_child->get_item_text(i), callable_mp(p_child, &PopupMenu::activate_item), i); + int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, p_child->get_item_text(i), callable_mp(p_child, &PopupMenu::activate_item), Callable(), i); if (p_child->is_item_checkable(i)) { DisplayServer::get_singleton()->global_menu_set_item_checkable(p_menu_name, index, true); @@ -337,7 +333,36 @@ void MenuBar::_update_menu() { } } update_minimum_size(); - update(); + queue_redraw(); +} + +void MenuBar::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.normal = get_theme_stylebox(SNAME("normal")); + theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored")); + theme_cache.disabled = get_theme_stylebox(SNAME("disabled")); + theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored")); + theme_cache.pressed = get_theme_stylebox(SNAME("pressed")); + theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored")); + theme_cache.hover = get_theme_stylebox(SNAME("hover")); + theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored")); + theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed")); + theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color")); + theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color")); + theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color")); + theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color")); + theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color")); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); } void MenuBar::_notification(int p_what) { @@ -352,7 +377,7 @@ void MenuBar::_notification(int p_what) { } break; case NOTIFICATION_MOUSE_EXIT: { focused_menu = -1; - update(); + queue_redraw(); } break; case NOTIFICATION_TRANSLATION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: @@ -376,12 +401,24 @@ void MenuBar::_notification(int p_what) { case NOTIFICATION_INTERNAL_PROCESS: { MutexLock lock(mutex); + if (is_native_menu()) { + // Handled by OS. + return; + } + Vector2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted - get_global_position(); + if (pos == old_mouse_pos) { + return; + } + old_mouse_pos = pos; + int index = _get_index_at_point(pos); if (index >= 0 && index != active_menu) { selected_menu = index; focused_menu = selected_menu; - get_menu_popup(active_menu)->hide(); + if (active_menu >= 0) { + get_menu_popup(active_menu)->hide(); + } _open_popup(index); } } break; @@ -389,8 +426,7 @@ void MenuBar::_notification(int p_what) { } int MenuBar::_get_index_at_point(const Point2 &p_point) const { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - int hsep = get_theme_constant(SNAME("h_separation")); + Ref<StyleBox> style = theme_cache.normal; int offset = 0; for (int i = 0; i < menu_cache.size(); i++) { if (menu_cache[i].hidden) { @@ -402,7 +438,7 @@ int MenuBar::_get_index_at_point(const Point2 &p_point) const { return i; } } - offset += size.x + hsep; + offset += size.x + theme_cache.h_separation; } return -1; } @@ -410,8 +446,7 @@ int MenuBar::_get_index_at_point(const Point2 &p_point) const { Rect2 MenuBar::_get_menu_item_rect(int p_index) const { ERR_FAIL_INDEX_V(p_index, menu_cache.size(), Rect2()); - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - int hsep = get_theme_constant(SNAME("h_separation")); + Ref<StyleBox> style = theme_cache.normal; int offset = 0; for (int i = 0; i < p_index; i++) { @@ -419,7 +454,7 @@ Rect2 MenuBar::_get_menu_item_rect(int p_index) const { continue; } Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size(); - offset += size.x + hsep; + offset += size.x + theme_cache.h_separation; } return Rect2(Point2(offset, 0), menu_cache[p_index].text_buf->get_size() + style->get_minimum_size()); @@ -438,76 +473,76 @@ void MenuBar::_draw_menu_item(int p_index) { } Color color; - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; Rect2 item_rect = _get_menu_item_rect(p_index); if (menu_cache[p_index].disabled) { if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) { - style = get_theme_stylebox(SNAME("disabled_mirrored")); + style = theme_cache.disabled_mirrored; } else { - style = get_theme_stylebox(SNAME("disabled")); + style = theme_cache.disabled; } if (!flat) { style->draw(ci, item_rect); } - color = get_theme_color(SNAME("font_disabled_color")); + color = theme_cache.font_disabled_color; } else if (hovered && pressed && has_theme_stylebox("hover_pressed")) { if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) { - style = get_theme_stylebox(SNAME("hover_pressed_mirrored")); + style = theme_cache.hover_pressed_mirrored; } else { - style = get_theme_stylebox(SNAME("hover_pressed")); + style = theme_cache.hover_pressed; } if (!flat) { style->draw(ci, item_rect); } if (has_theme_color(SNAME("font_hover_pressed_color"))) { - color = get_theme_color(SNAME("font_hover_pressed_color")); + color = theme_cache.font_hover_pressed_color; } } else if (pressed) { if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) { - style = get_theme_stylebox(SNAME("pressed_mirrored")); + style = theme_cache.pressed_mirrored; } else { - style = get_theme_stylebox(SNAME("pressed")); + style = theme_cache.pressed; } if (!flat) { style->draw(ci, item_rect); } if (has_theme_color(SNAME("font_pressed_color"))) { - color = get_theme_color(SNAME("font_pressed_color")); + color = theme_cache.font_pressed_color; } else { - color = get_theme_color(SNAME("font_color")); + color = theme_cache.font_color; } } else if (hovered) { if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) { - style = get_theme_stylebox(SNAME("hover_mirrored")); + style = theme_cache.hover_mirrored; } else { - style = get_theme_stylebox(SNAME("hover")); + style = theme_cache.hover; } if (!flat) { style->draw(ci, item_rect); } - color = get_theme_color(SNAME("font_hover_color")); + color = theme_cache.font_hover_color; } else { if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) { - style = get_theme_stylebox(SNAME("normal_mirrored")); + style = theme_cache.normal_mirrored; } else { - style = get_theme_stylebox(SNAME("normal")); + style = theme_cache.normal; } if (!flat) { style->draw(ci, item_rect); } // Focus colors only take precedence over normal state. if (has_focus()) { - color = get_theme_color(SNAME("font_focus_color")); + color = theme_cache.font_focus_color; } else { - color = get_theme_color(SNAME("font_color")); + color = theme_cache.font_color; } } Point2 text_ofs = item_rect.position + Point2(style->get_margin(SIDE_LEFT), style->get_margin(SIDE_TOP)); - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); + Color font_outline_color = theme_cache.font_outline_color; + int outline_size = theme_cache.outline_size; if (outline_size > 0 && font_outline_color.a > 0) { menu_cache[p_index].text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color); } @@ -515,16 +550,13 @@ void MenuBar::_draw_menu_item(int p_index) { } void MenuBar::shape(Menu &p_menu) { - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); - p_menu.text_buf->clear(); if (text_direction == Control::TEXT_DIRECTION_INHERITED) { p_menu.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); } else { p_menu.text_buf->set_direction((TextServer::Direction)text_direction); } - p_menu.text_buf->add_string(p_menu.name, font, font_size, language); + p_menu.text_buf->add_string(p_menu.name, theme_cache.font, theme_cache.font_size, language); } void MenuBar::_refresh_menu_names() { @@ -716,7 +748,7 @@ String MenuBar::get_language() const { void MenuBar::set_flat(bool p_enabled) { if (flat != p_enabled) { flat = p_enabled; - update(); + queue_redraw(); } } @@ -754,7 +786,7 @@ Size2 MenuBar::get_minimum_size() const { return Size2(); } - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); + Ref<StyleBox> style = theme_cache.normal; Vector2 size; for (int i = 0; i < menu_cache.size(); i++) { @@ -766,7 +798,7 @@ Size2 MenuBar::get_minimum_size() const { size.x += sz.x; } if (menu_cache.size() > 1) { - size.x += get_theme_constant(SNAME("h_separation")) * (menu_cache.size() - 1); + size.x += theme_cache.h_separation * (menu_cache.size() - 1); } return size; } diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h index b7d9933ab2..f7ef19e98b 100644 --- a/scene/gui/menu_bar.h +++ b/scene/gui/menu_bar.h @@ -73,8 +73,36 @@ class MenuBar : public Control { int active_menu = -1; Vector2i mouse_pos_adjusted; + Vector2i old_mouse_pos; ObjectID shortcut_context; + struct ThemeCache { + Ref<StyleBox> normal; + Ref<StyleBox> normal_mirrored; + Ref<StyleBox> disabled; + Ref<StyleBox> disabled_mirrored; + Ref<StyleBox> pressed; + Ref<StyleBox> pressed_mirrored; + Ref<StyleBox> hover; + Ref<StyleBox> hover_mirrored; + Ref<StyleBox> hover_pressed; + Ref<StyleBox> hover_pressed_mirrored; + + Ref<Font> font; + int font_size = 0; + int outline_size = 0; + Color font_outline_color; + + Color font_color; + Color font_disabled_color; + Color font_pressed_color; + Color font_hover_color; + Color font_hover_pressed_color; + Color font_focus_color; + + int h_separation = 0; + } theme_cache; + int _get_index_at_point(const Point2 &p_point) const; Rect2 _get_menu_item_rect(int p_index) const; void _draw_menu_item(int p_index); @@ -95,6 +123,7 @@ class MenuBar : public Control { protected: virtual void shortcut_input(const Ref<InputEvent> &p_event) override; + virtual void _update_theme_item_cache() override; void _notification(int p_what); virtual void add_child_notify(Node *p_child) override; virtual void move_child_notify(Node *p_child) override; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index f779f87ae7..67a36240a2 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -107,7 +107,7 @@ void MenuButton::pressed() { if (!_was_pressed_by_mouse()) { for (int i = 0; i < popup->get_item_count(); i++) { if (!popup->is_item_disabled(i)) { - popup->set_current_index(i); + popup->set_focused_item(i); break; } } @@ -169,7 +169,7 @@ void MenuButton::_notification(int p_what) { menu_btn_other->pressed(); // As the popup wasn't triggered by a mouse click, the item focus needs to be removed manually. - menu_btn_other->get_popup()->set_current_index(-1); + menu_btn_other->get_popup()->set_focused_item(-1); } } break; } diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp index a7e86dd5de..6048916d7d 100644 --- a/scene/gui/nine_patch_rect.cpp +++ b/scene/gui/nine_patch_rect.cpp @@ -94,7 +94,7 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) { return; } texture = p_tex; - update(); + queue_redraw(); update_minimum_size(); emit_signal(SceneStringNames::get_singleton()->texture_changed); } @@ -111,7 +111,7 @@ void NinePatchRect::set_patch_margin(Side p_side, int p_size) { } margin[p_side] = p_size; - update(); + queue_redraw(); update_minimum_size(); } @@ -140,7 +140,7 @@ void NinePatchRect::set_draw_center(bool p_enabled) { } draw_center = p_enabled; - update(); + queue_redraw(); } bool NinePatchRect::is_draw_center_enabled() const { @@ -153,7 +153,7 @@ void NinePatchRect::set_h_axis_stretch_mode(AxisStretchMode p_mode) { } axis_h = p_mode; - update(); + queue_redraw(); } NinePatchRect::AxisStretchMode NinePatchRect::get_h_axis_stretch_mode() const { @@ -166,7 +166,7 @@ void NinePatchRect::set_v_axis_stretch_mode(AxisStretchMode p_mode) { } axis_v = p_mode; - update(); + queue_redraw(); } NinePatchRect::AxisStretchMode NinePatchRect::get_v_axis_stretch_mode() const { diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index a87c46e8ac..08f5e0bbfb 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -43,11 +43,11 @@ Size2 OptionButton::get_minimum_size() const { } if (has_theme_icon(SNAME("arrow"))) { - const Size2 padding = get_theme_stylebox(SNAME("normal"))->get_minimum_size(); - const Size2 arrow_size = Control::get_theme_icon(SNAME("arrow"))->get_size(); + const Size2 padding = theme_cache.normal->get_minimum_size(); + const Size2 arrow_size = theme_cache.arrow_icon->get_size(); Size2 content_size = minsize - padding; - content_size.width += arrow_size.width + MAX(0, get_theme_constant(SNAME("h_separation"))); + content_size.width += arrow_size.width + MAX(0, theme_cache.h_separation); content_size.height = MAX(content_size.height, arrow_size.height); minsize = content_size + padding; @@ -56,35 +56,63 @@ Size2 OptionButton::get_minimum_size() const { return minsize; } +void OptionButton::_update_theme_item_cache() { + Button::_update_theme_item_cache(); + + theme_cache.normal = get_theme_stylebox(SNAME("normal")); + + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color")); + theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color")); + theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color")); + theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color")); + theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color")); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + + theme_cache.arrow_icon = get_theme_icon(SNAME("arrow")); + theme_cache.arrow_margin = get_theme_constant(SNAME("arrow_margin")); + theme_cache.modulate_arrow = get_theme_constant(SNAME("modulate_arrow")); +} + void OptionButton::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + if (has_theme_icon(SNAME("arrow"))) { + if (is_layout_rtl()) { + _set_internal_margin(SIDE_LEFT, theme_cache.arrow_icon->get_width()); + } else { + _set_internal_margin(SIDE_RIGHT, theme_cache.arrow_icon->get_width()); + } + } + } break; + case NOTIFICATION_DRAW: { if (!has_theme_icon(SNAME("arrow"))) { return; } RID ci = get_canvas_item(); - Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow")); Color clr = Color(1, 1, 1); - if (get_theme_constant(SNAME("modulate_arrow"))) { + if (theme_cache.modulate_arrow) { switch (get_draw_mode()) { case DRAW_PRESSED: - clr = get_theme_color(SNAME("font_pressed_color")); + clr = theme_cache.font_pressed_color; break; case DRAW_HOVER: - clr = get_theme_color(SNAME("font_hover_color")); + clr = theme_cache.font_hover_color; break; case DRAW_HOVER_PRESSED: - clr = get_theme_color(SNAME("font_hover_pressed_color")); + clr = theme_cache.font_hover_pressed_color; break; case DRAW_DISABLED: - clr = get_theme_color(SNAME("font_disabled_color")); + clr = theme_cache.font_disabled_color; break; default: if (has_focus()) { - clr = get_theme_color(SNAME("font_focus_color")); + clr = theme_cache.font_focus_color; } else { - clr = get_theme_color(SNAME("font_color")); + clr = theme_cache.font_color; } } } @@ -93,11 +121,11 @@ void OptionButton::_notification(int p_what) { Point2 ofs; if (is_layout_rtl()) { - ofs = Point2(get_theme_constant(SNAME("arrow_margin")), int(Math::abs((size.height - arrow->get_height()) / 2))); + ofs = Point2(theme_cache.arrow_margin, int(Math::abs((size.height - theme_cache.arrow_icon->get_height()) / 2))); } else { - ofs = Point2(size.width - arrow->get_width() - get_theme_constant(SNAME("arrow_margin")), int(Math::abs((size.height - arrow->get_height()) / 2))); + ofs = Point2(size.width - theme_cache.arrow_icon->get_width() - theme_cache.arrow_margin, int(Math::abs((size.height - theme_cache.arrow_icon->get_height()) / 2))); } - arrow->draw(ci, ofs, clr); + theme_cache.arrow_icon->draw(ci, ofs, clr); } break; case NOTIFICATION_TRANSLATION_CHANGED: @@ -108,11 +136,11 @@ void OptionButton::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { if (has_theme_icon(SNAME("arrow"))) { if (is_layout_rtl()) { - _set_internal_margin(SIDE_LEFT, Control::get_theme_icon(SNAME("arrow"))->get_width()); + _set_internal_margin(SIDE_LEFT, theme_cache.arrow_icon->get_width()); _set_internal_margin(SIDE_RIGHT, 0.f); } else { _set_internal_margin(SIDE_LEFT, 0.f); - _set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width()); + _set_internal_margin(SIDE_RIGHT, theme_cache.arrow_icon->get_width()); } } _refresh_size_cache(); @@ -210,7 +238,7 @@ void OptionButton::pressed() { // If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused. if (current != NONE_SELECTED && !popup->is_item_disabled(current)) { if (!_was_pressed_by_mouse()) { - popup->set_current_index(current); + popup->set_focused_item(current); } else { popup->scroll_to_item(current); } @@ -218,7 +246,7 @@ void OptionButton::pressed() { for (int i = 0; i < popup->get_item_count(); i++) { if (!popup->is_item_disabled(i)) { if (!_was_pressed_by_mouse()) { - popup->set_current_index(i); + popup->set_focused_item(i); } else { popup->scroll_to_item(i); } @@ -540,15 +568,6 @@ OptionButton::OptionButton(const String &p_text) : Button(p_text) { set_toggle_mode(true); set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT); - if (is_layout_rtl()) { - if (has_theme_icon(SNAME("arrow"))) { - _set_internal_margin(SIDE_LEFT, Control::get_theme_icon(SNAME("arrow"))->get_width()); - } - } else { - if (has_theme_icon(SNAME("arrow"))) { - _set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width()); - } - } set_action_mode(ACTION_MODE_BUTTON_PRESS); popup = memnew(PopupMenu); diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index cd709b8f5f..2c7e0510f5 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -43,6 +43,23 @@ class OptionButton : public Button { Vector2 _cached_size; bool cache_refresh_pending = false; + struct ThemeCache { + Ref<StyleBox> normal; + + Color font_color; + Color font_focus_color; + Color font_pressed_color; + Color font_hover_color; + Color font_hover_pressed_color; + Color font_disabled_color; + + int h_separation = 0; + + Ref<Texture2D> arrow_icon; + int arrow_margin = 0; + int modulate_arrow = 0; + } theme_cache; + void _focused(int p_which); void _selected(int p_which); void _select(int p_which, bool p_emit = false); @@ -54,6 +71,7 @@ class OptionButton : public Button { protected: Size2 get_minimum_size() const override; + virtual void _update_theme_item_cache() override; void _notification(int p_what); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp index 1ac6cf57ab..09bc295513 100644 --- a/scene/gui/panel.cpp +++ b/scene/gui/panel.cpp @@ -30,12 +30,17 @@ #include "panel.h" +void Panel::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); +} + void Panel::_notification(int p_what) { 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())); + theme_cache.panel_style->draw(ci, Rect2(Point2(), get_size())); } break; } } diff --git a/scene/gui/panel.h b/scene/gui/panel.h index 5d2e912680..f9bd721681 100644 --- a/scene/gui/panel.h +++ b/scene/gui/panel.h @@ -36,7 +36,13 @@ class Panel : public Control { GDCLASS(Panel, Control); + struct ThemeCache { + Ref<StyleBox> panel_style; + } theme_cache; + protected: + virtual void _update_theme_item_cache() override; + void _notification(int p_what); public: diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index fe01712a89..eeaded1788 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -31,14 +31,6 @@ #include "panel_container.h" Size2 PanelContainer::get_minimum_size() const { - Ref<StyleBox> style; - - if (has_theme_stylebox(SNAME("panel"))) { - style = get_theme_stylebox(SNAME("panel")); - } else { - style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer")); - } - Size2 ms; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); @@ -54,8 +46,8 @@ Size2 PanelContainer::get_minimum_size() const { ms.height = MAX(ms.height, minsize.height); } - if (style.is_valid()) { - ms += style->get_minimum_size(); + if (theme_cache.panel_style.is_valid()) { + ms += theme_cache.panel_style->get_minimum_size(); } return ms; } @@ -78,35 +70,25 @@ Vector<int> PanelContainer::get_allowed_size_flags_vertical() const { return flags; } +void PanelContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); +} + void PanelContainer::_notification(int p_what) { 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")); - } - - style->draw(ci, Rect2(Point2(), get_size())); + theme_cache.panel_style->draw(ci, Rect2(Point2(), get_size())); } break; case NOTIFICATION_SORT_CHILDREN: { - Ref<StyleBox> style; - - if (has_theme_stylebox(SNAME("panel"))) { - style = get_theme_stylebox(SNAME("panel")); - } else { - style = get_theme_stylebox(SNAME("panel"), SNAME("PanelContainer")); - } - Size2 size = get_size(); Point2 ofs; - if (style.is_valid()) { - size -= style->get_minimum_size(); - ofs += style->get_offset(); + if (theme_cache.panel_style.is_valid()) { + size -= theme_cache.panel_style->get_minimum_size(); + ofs += theme_cache.panel_style->get_offset(); } for (int i = 0; i < get_child_count(); i++) { diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h index 8f07ce38eb..97d0cdc872 100644 --- a/scene/gui/panel_container.h +++ b/scene/gui/panel_container.h @@ -36,7 +36,12 @@ class PanelContainer : public Container { GDCLASS(PanelContainer, Container); + struct ThemeCache { + Ref<StyleBox> panel_style; + } theme_cache; + protected: + virtual void _update_theme_item_cache() override; void _notification(int p_what); public: diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index c4396f636a..ceae3791f3 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -68,6 +68,12 @@ void Popup::_deinitialize_visible_parents() { } } +void Popup::_update_theme_item_cache() { + Window::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); +} + void Popup::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { @@ -186,8 +192,6 @@ Popup::~Popup() { } Size2 PopupPanel::_get_contents_minimum_size() const { - Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name()); - Size2 ms; for (int i = 0; i < get_child_count(); i++) { @@ -205,14 +209,12 @@ Size2 PopupPanel::_get_contents_minimum_size() const { ms.y = MAX(cms.y, ms.y); } - return ms + p->get_minimum_size(); + return ms + theme_cache.panel_style->get_minimum_size(); } void PopupPanel::_update_child_rects() { - Ref<StyleBox> p = get_theme_stylebox(SNAME("panel"), get_class_name()); - - Vector2 cpos(p->get_offset()); - Vector2 csize(get_size() - p->get_minimum_size()); + Vector2 cpos(theme_cache.panel_style->get_offset()); + Vector2 csize(get_size() - theme_cache.panel_style->get_minimum_size()); for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); @@ -234,15 +236,17 @@ void PopupPanel::_update_child_rects() { } } +void PopupPanel::_update_theme_item_cache() { + Popup::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); +} + void PopupPanel::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_READY: 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())); + panel->add_theme_style_override("panel", theme_cache.panel_style); _update_child_rects(); } break; diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 70eb8722d0..0d6ca25c18 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -43,6 +43,10 @@ class Popup : public Window { LocalVector<Window *> visible_parents; bool popped_up = false; + struct ThemeCache { + Ref<StyleBox> panel_style; + } theme_cache; + void _input_from_window(const Ref<InputEvent> &p_event); void _initialize_visible_parents(); @@ -52,6 +56,7 @@ protected: void _close_pressed(); virtual Rect2i _popup_adjust_rect() const override; + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); @@ -69,8 +74,14 @@ class PopupPanel : public Popup { Panel *panel = nullptr; + struct ThemeCache { + Ref<StyleBox> panel_style; + } theme_cache; + protected: void _update_child_rects(); + + virtual void _update_theme_item_cache() override; void _notification(int p_what); virtual Size2 _get_contents_minimum_size() const override; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index c8bb9fd530..d4a4efd578 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -48,15 +48,12 @@ String PopupMenu::_get_accel_text(const Item &p_item) const { } Size2 PopupMenu::_get_contents_minimum_size() const { - int vseparation = get_theme_constant(SNAME("v_separation")); - int hseparation = get_theme_constant(SNAME("h_separation")); - - Size2 minsize = get_theme_stylebox(SNAME("panel"))->get_minimum_size(); // Accounts for margin in the margin container + Size2 minsize = theme_cache.panel_style->get_minimum_size(); // Accounts for margin in the margin container minsize.x += scroll_container->get_v_scroll_bar()->get_size().width * 2; // Adds a buffer so that the scrollbar does not render over the top of content float max_w = 0.0; float icon_w = 0.0; - int check_w = MAX(get_theme_icon(SNAME("checked"))->get_width(), get_theme_icon(SNAME("radio_checked"))->get_width()) + hseparation; + int check_w = MAX(theme_cache.checked->get_width(), theme_cache.radio_checked->get_width()) + theme_cache.h_separation; int accel_max_w = 0; bool has_check = false; @@ -67,23 +64,23 @@ Size2 PopupMenu::_get_contents_minimum_size() const { size.height = _get_item_height(i); icon_w = MAX(icon_size.width, icon_w); - size.width += items[i].indent * get_theme_constant(SNAME("indent")); + size.width += items[i].indent * theme_cache.indent; if (items[i].checkable_type && !items[i].separator) { has_check = true; } size.width += items[i].text_buf->get_size().x; - size.height += vseparation; + size.height += theme_cache.v_separation; if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) { - int accel_w = hseparation * 2; + int accel_w = theme_cache.h_separation * 2; accel_w += items[i].accel_text_buf->get_size().x; accel_max_w = MAX(accel_w, accel_max_w); } if (!items[i].submenu.is_empty()) { - size.width += get_theme_icon(SNAME("submenu"))->get_width(); + size.width += theme_cache.submenu->get_width(); } max_w = MAX(max_w, size.width); @@ -91,7 +88,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const { minsize.height += size.height; } - int item_side_padding = get_theme_constant(SNAME("item_start_padding")) + get_theme_constant(SNAME("item_end_padding")); + int item_side_padding = theme_cache.item_start_padding + theme_cache.item_end_padding; minsize.width += max_w + icon_w + accel_max_w + item_side_padding; if (has_check) { @@ -113,33 +110,31 @@ int PopupMenu::_get_item_height(int p_item) const { int icon_height = items[p_item].get_icon_size().height; if (items[p_item].checkable_type && !items[p_item].separator) { - icon_height = MAX(icon_height, MAX(get_theme_icon(SNAME("checked"))->get_height(), get_theme_icon(SNAME("radio_checked"))->get_height())); + icon_height = MAX(icon_height, MAX(theme_cache.checked->get_height(), theme_cache.radio_checked->get_height())); } int text_height = items[p_item].text_buf->get_size().height; if (text_height == 0 && !items[p_item].separator) { - text_height = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size"))); + text_height = theme_cache.font->get_height(theme_cache.font_size); } int separator_height = 0; if (items[p_item].separator) { - separator_height = MAX(get_theme_stylebox(SNAME("separator"))->get_minimum_size().height, MAX(get_theme_stylebox(SNAME("labeled_separator_left"))->get_minimum_size().height, get_theme_stylebox(SNAME("labeled_separator_right"))->get_minimum_size().height)); + separator_height = MAX(theme_cache.separator_style->get_minimum_size().height, MAX(theme_cache.labeled_separator_left->get_minimum_size().height, theme_cache.labeled_separator_right->get_minimum_size().height)); } return MAX(separator_height, MAX(text_height, icon_height)); } int PopupMenu::_get_items_total_height() const { - int vsep = get_theme_constant(SNAME("v_separation")); - // Get total height of all items by taking max of icon height and font height int items_total_height = 0; for (int i = 0; i < items.size(); i++) { - items_total_height += _get_item_height(i) + vsep; + items_total_height += _get_item_height(i) + theme_cache.v_separation; } // Subtract a separator which is not needed for the last item. - return items_total_height - vsep; + return items_total_height - theme_cache.v_separation; } int PopupMenu::_get_mouse_over(const Point2 &p_over) const { @@ -147,18 +142,15 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { return -1; } - Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); // Accounts for margin in the margin container - - int vseparation = get_theme_constant(SNAME("v_separation")); - - Point2 ofs = style->get_offset() + Point2(0, vseparation / 2); + // Accounts for margin in the margin container + Point2 ofs = theme_cache.panel_style->get_offset() + Point2(0, theme_cache.v_separation / 2); if (ofs.y > p_over.y) { return -1; } for (int i = 0; i < items.size(); i++) { - ofs.y += i > 0 ? vseparation : (float)vseparation / 2; + ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2; ofs.y += _get_item_height(i); @@ -179,9 +171,6 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { return; // Already visible. } - Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); - int vsep = get_theme_constant(SNAME("v_separation")); - Point2 this_pos = get_position(); Rect2 this_rect(this_pos, get_size()); @@ -220,7 +209,7 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { if (p_by_keyboard) { for (int i = 0; i < submenu_pum->get_item_count(); i++) { if (!submenu_pum->is_item_disabled(i)) { - submenu_pum->set_current_index(i); + submenu_pum->set_focused_item(i); break; } } @@ -231,7 +220,7 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { // 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.position.y += items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 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); @@ -240,11 +229,11 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { // Autohide area above the submenu item. submenu_pum->clear_autohide_areas(); - submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + style->get_offset().height - vsep / 2)); + submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y, this_rect.size.x, items[p_over]._ofs_cache + scroll_offset + theme_cache.panel_style->get_offset().height - theme_cache.v_separation / 2)); // If there is an area below the submenu item, add an autohide area there. if (items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset <= control->get_size().height) { - int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + vsep / 2 + style->get_offset().height; + int from = items[p_over]._ofs_cache + items[p_over]._height_cache + scroll_offset + theme_cache.v_separation / 2 + theme_cache.panel_style->get_offset().height; submenu_pum->add_autohide_area(Rect2(this_rect.position.x, this_rect.position.y + from, this_rect.size.x, this_rect.size.y - from)); } } @@ -296,7 +285,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; emit_signal(SNAME("id_focused"), i); scroll_to_item(i); - control->update(); + control->queue_redraw(); set_input_as_handled(); match_found = true; break; @@ -310,7 +299,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; emit_signal(SNAME("id_focused"), i); scroll_to_item(i); - control->update(); + control->queue_redraw(); set_input_as_handled(); break; } @@ -328,7 +317,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; emit_signal(SNAME("id_focused"), i); scroll_to_item(i); - control->update(); + control->queue_redraw(); set_input_as_handled(); match_found = true; break; @@ -342,7 +331,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; emit_signal(SNAME("id_focused"), i); scroll_to_item(i); - control->update(); + control->queue_redraw(); set_input_as_handled(); break; } @@ -442,7 +431,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { - if (m->get_velocity().is_equal_approx(Vector2())) { + if (m->get_velocity().is_zero_approx()) { return; } activated_by_keyboard = false; @@ -463,7 +452,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { if (id < 0) { mouse_over = -1; - control->update(); + control->queue_redraw(); return; } @@ -474,7 +463,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { if (over != mouse_over) { mouse_over = over; - control->update(); + control->queue_redraw(); } } @@ -511,7 +500,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { mouse_over = i; emit_signal(SNAME("id_focused"), i); scroll_to_item(i); - control->update(); + control->queue_redraw(); set_input_as_handled(); break; } @@ -528,34 +517,17 @@ void PopupMenu::_draw_items() { margin_size.height = margin_container->get_theme_constant(SNAME("margin_top")) + margin_container->get_theme_constant(SNAME("margin_bottom")); // Space between the item content and the sides of popup menu. - int item_start_padding = get_theme_constant(SNAME("item_start_padding")); - int item_end_padding = get_theme_constant(SNAME("item_end_padding")); - bool rtl = control->is_layout_rtl(); - Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); - Ref<StyleBox> hover = get_theme_stylebox(SNAME("hover")); // In Item::checkable_type enum order (less the non-checkable member), with disabled repeated at the end. - Ref<Texture2D> check[] = { get_theme_icon(SNAME("checked")), get_theme_icon(SNAME("radio_checked")), get_theme_icon(SNAME("checked_disabled")), get_theme_icon(SNAME("radio_checked_disabled")) }; - Ref<Texture2D> uncheck[] = { get_theme_icon(SNAME("unchecked")), get_theme_icon(SNAME("radio_unchecked")), get_theme_icon(SNAME("unchecked_disabled")), get_theme_icon(SNAME("radio_unchecked_disabled")) }; + Ref<Texture2D> check[] = { theme_cache.checked, theme_cache.radio_checked, theme_cache.checked_disabled, theme_cache.radio_checked_disabled }; + Ref<Texture2D> uncheck[] = { theme_cache.unchecked, theme_cache.radio_unchecked, theme_cache.unchecked_disabled, theme_cache.radio_unchecked_disabled }; Ref<Texture2D> submenu; if (rtl) { - submenu = get_theme_icon(SNAME("submenu_mirrored")); + submenu = theme_cache.submenu_mirrored; } else { - submenu = get_theme_icon(SNAME("submenu")); + submenu = theme_cache.submenu; } - Ref<StyleBox> separator = get_theme_stylebox(SNAME("separator")); - Ref<StyleBox> labeled_separator_left = get_theme_stylebox(SNAME("labeled_separator_left")); - Ref<StyleBox> labeled_separator_right = get_theme_stylebox(SNAME("labeled_separator_right")); - - int vseparation = get_theme_constant(SNAME("v_separation")); - int hseparation = get_theme_constant(SNAME("h_separation")); - Color font_color = get_theme_color(SNAME("font_color")); - Color font_disabled_color = get_theme_color(SNAME("font_disabled_color")); - Color font_accelerator_color = get_theme_color(SNAME("font_accelerator_color")); - Color font_hover_color = get_theme_color(SNAME("font_hover_color")); - Color font_separator_color = get_theme_color(SNAME("font_separator_color")); - float scroll_width = scroll_container->get_v_scroll_bar()->is_visible_in_tree() ? scroll_container->get_v_scroll_bar()->get_size().width : 0; float display_width = control->get_size().width - scroll_width; @@ -574,7 +546,7 @@ void PopupMenu::_draw_items() { } } if (icon_ofs > 0.0) { - icon_ofs += hseparation; + icon_ofs += theme_cache.h_separation; } float check_ofs = 0.0; @@ -583,7 +555,7 @@ void PopupMenu::_draw_items() { check_ofs = MAX(check_ofs, check[i]->get_width()); check_ofs = MAX(check_ofs, uncheck[i]->get_width()); } - check_ofs += hseparation; + check_ofs += theme_cache.h_separation; } Point2 ofs = Point2(); @@ -591,7 +563,7 @@ void PopupMenu::_draw_items() { // Loop through all items and draw each. for (int i = 0; i < items.size(); i++) { // For the first item only add half a separation. For all other items, add a whole separation to the offset. - ofs.y += i > 0 ? vseparation : (float)vseparation / 2; + ofs.y += i > 0 ? theme_cache.v_separation : (float)theme_cache.v_separation / 2; _shape_item(i); @@ -601,47 +573,47 @@ void PopupMenu::_draw_items() { if (i == mouse_over) { if (rtl) { - hover->draw(ci, Rect2(item_ofs + Point2(scroll_width, -vseparation / 2), Size2(display_width, h + vseparation))); + theme_cache.hover_style->draw(ci, Rect2(item_ofs + Point2(scroll_width, -theme_cache.v_separation / 2), Size2(display_width, h + theme_cache.v_separation))); } else { - hover->draw(ci, Rect2(item_ofs + Point2(0, -vseparation / 2), Size2(display_width, h + vseparation))); + theme_cache.hover_style->draw(ci, Rect2(item_ofs + Point2(0, -theme_cache.v_separation / 2), Size2(display_width, h + theme_cache.v_separation))); } } String text = items[i].xl_text; // Separator - item_ofs.x += items[i].indent * get_theme_constant(SNAME("indent")); + item_ofs.x += items[i].indent * theme_cache.indent; if (items[i].separator) { if (!text.is_empty() || !items[i].icon.is_null()) { - int content_size = items[i].text_buf->get_size().width + hseparation * 2; + int content_size = items[i].text_buf->get_size().width + theme_cache.h_separation * 2; if (!items[i].icon.is_null()) { - content_size += icon_size.width + hseparation; + content_size += icon_size.width + theme_cache.h_separation; } int content_center = display_width / 2; int content_left = content_center - content_size / 2; int content_right = content_center + content_size / 2; if (content_left > item_ofs.x) { - int sep_h = labeled_separator_left->get_center_size().height + labeled_separator_left->get_minimum_size().height; + int sep_h = theme_cache.labeled_separator_left->get_center_size().height + theme_cache.labeled_separator_left->get_minimum_size().height; int sep_ofs = Math::floor((h - sep_h) / 2.0); - labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h))); + theme_cache.labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, content_left - item_ofs.x), sep_h))); } if (content_right < display_width) { - int sep_h = labeled_separator_right->get_center_size().height + labeled_separator_right->get_minimum_size().height; + int sep_h = theme_cache.labeled_separator_right->get_center_size().height + theme_cache.labeled_separator_right->get_minimum_size().height; int sep_ofs = Math::floor((h - sep_h) / 2.0); - labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h))); + theme_cache.labeled_separator_right->draw(ci, Rect2(Point2(content_right, item_ofs.y + sep_ofs), Size2(MAX(0, display_width - content_right), sep_h))); } } else { - int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; + int sep_h = theme_cache.separator_style->get_center_size().height + theme_cache.separator_style->get_minimum_size().height; int sep_ofs = Math::floor((h - sep_h) / 2.0); - separator->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h))); + theme_cache.separator_style->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h))); } } Color icon_color(1, 1, 1, items[i].disabled && !items[i].separator ? 0.5 : 1); // For non-separator items, add some padding for the content. - item_ofs.x += item_start_padding; + item_ofs.x += theme_cache.item_start_padding; // Checkboxes if (items[i].checkable_type && !items[i].separator) { @@ -659,7 +631,7 @@ void PopupMenu::_draw_items() { // Icon if (!items[i].icon.is_null()) { if (items[i].separator) { - separator_ofs -= (icon_size.width + hseparation) / 2; + separator_ofs -= (icon_size.width + theme_cache.h_separation) / 2; if (rtl) { items[i].icon->draw(ci, Size2(control->get_size().width - item_ofs.x - separator_ofs - icon_size.width, item_ofs.y) + Point2(0, Math::floor((h - icon_size.height) / 2.0)), icon_color); @@ -678,61 +650,55 @@ void PopupMenu::_draw_items() { // Submenu arrow on right hand side. if (!items[i].submenu.is_empty()) { if (rtl) { - submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); + submenu->draw(ci, Point2(scroll_width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); } else { - submenu->draw(ci, Point2(display_width - style->get_margin(SIDE_RIGHT) - submenu->get_width() - item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); + submenu->draw(ci, Point2(display_width - theme_cache.panel_style->get_margin(SIDE_RIGHT) - submenu->get_width() - theme_cache.item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); } } - Color font_outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); - // Text if (items[i].separator) { - Color font_separator_outline_color = get_theme_color(SNAME("font_separator_outline_color")); - int separator_outline_size = get_theme_constant(SNAME("separator_outline_size")); - if (!text.is_empty()) { Vector2 text_pos = Point2(separator_ofs, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); if (!rtl && !items[i].icon.is_null()) { - text_pos.x += icon_size.width + hseparation; + text_pos.x += icon_size.width + theme_cache.h_separation; } - if (separator_outline_size > 0 && font_separator_outline_color.a > 0) { - items[i].text_buf->draw_outline(ci, text_pos, separator_outline_size, font_separator_outline_color); + if (theme_cache.font_separator_outline_size > 0 && theme_cache.font_separator_outline_color.a > 0) { + items[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_separator_outline_size, theme_cache.font_separator_outline_color); } - items[i].text_buf->draw(ci, text_pos, font_separator_color); + items[i].text_buf->draw(ci, text_pos, theme_cache.font_separator_color); } } else { item_ofs.x += icon_ofs + check_ofs; if (rtl) { Vector2 text_pos = Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); - if (outline_size > 0 && font_outline_color.a > 0) { - items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { + items[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color); } - items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color)); + items[i].text_buf->draw(ci, text_pos, items[i].disabled ? theme_cache.font_disabled_color : (i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_color)); } else { Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); - if (outline_size > 0 && font_outline_color.a > 0) { - items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { + items[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color); } - items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color)); + items[i].text_buf->draw(ci, text_pos, items[i].disabled ? theme_cache.font_disabled_color : (i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_color)); } } // Accelerator / Shortcut if (items[i].accel != Key::NONE || (items[i].shortcut.is_valid() && items[i].shortcut->has_valid_event())) { if (rtl) { - item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding; + item_ofs.x = scroll_width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.item_end_padding; } else { - item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - item_end_padding; + item_ofs.x = display_width - theme_cache.panel_style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - theme_cache.item_end_padding; } Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); - if (outline_size > 0 && font_outline_color.a > 0) { - items[i].accel_text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { + items[i].accel_text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color); } - items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? font_hover_color : font_accelerator_color); + items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? theme_cache.font_hover_color : theme_cache.font_accelerator_color); } // Cache the item vertical offset from the first item and the height. @@ -744,9 +710,8 @@ void PopupMenu::_draw_items() { } void PopupMenu::_draw_background() { - Ref<StyleBox> style = get_theme_stylebox(SNAME("panel")); RID ci2 = margin_container->get_canvas_item(); - style->draw(ci2, Rect2(Point2(), margin_container->get_size())); + theme_cache.panel_style->draw(ci2, Rect2(Point2(), margin_container->get_size())); } void PopupMenu::_minimum_lifetime_timeout() { @@ -778,8 +743,8 @@ void PopupMenu::_shape_item(int p_item) { if (items.write[p_item].dirty) { items.write[p_item].text_buf->clear(); - Ref<Font> font = get_theme_font(items[p_item].separator ? SNAME("font_separator") : SNAME("font")); - int font_size = get_theme_font_size(items[p_item].separator ? SNAME("font_separator_size") : SNAME("font_size")); + Ref<Font> font = items[p_item].separator ? theme_cache.font_separator : theme_cache.font; + int font_size = items[p_item].separator ? theme_cache.font_separator_size : theme_cache.font_size; if (items[p_item].text_direction == Control::TEXT_DIRECTION_INHERITED) { items.write[p_item].text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); @@ -821,6 +786,51 @@ void PopupMenu::remove_child_notify(Node *p_child) { _menu_changed(); } +void PopupMenu::_update_theme_item_cache() { + Popup::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); + theme_cache.hover_style = get_theme_stylebox(SNAME("hover")); + + theme_cache.separator_style = get_theme_stylebox(SNAME("separator")); + theme_cache.labeled_separator_left = get_theme_stylebox(SNAME("labeled_separator_left")); + theme_cache.labeled_separator_right = get_theme_stylebox(SNAME("labeled_separator_right")); + + theme_cache.v_separation = get_theme_constant(SNAME("v_separation")); + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + theme_cache.indent = get_theme_constant(SNAME("indent")); + theme_cache.item_start_padding = get_theme_constant(SNAME("item_start_padding")); + theme_cache.item_end_padding = get_theme_constant(SNAME("item_end_padding")); + + theme_cache.checked = get_theme_icon(SNAME("checked")); + theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled")); + theme_cache.unchecked = get_theme_icon(SNAME("unchecked")); + theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled")); + theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked")); + theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled")); + theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked")); + theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled")); + + theme_cache.submenu = get_theme_icon(SNAME("submenu")); + theme_cache.submenu_mirrored = get_theme_icon(SNAME("submenu_mirrored")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.font_separator = get_theme_font(SNAME("font_separator")); + theme_cache.font_separator_size = get_theme_font_size(SNAME("font_separator_size")); + + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color")); + theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color")); + theme_cache.font_accelerator_color = get_theme_color(SNAME("font_accelerator_color")); + theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + + theme_cache.font_separator_color = get_theme_color(SNAME("font_separator_color")); + theme_cache.font_separator_outline_size = get_theme_constant(SNAME("separator_outline_size")); + theme_cache.font_separator_outline_color = get_theme_color(SNAME("font_separator_outline_color")); +} + void PopupMenu::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -843,7 +853,7 @@ void PopupMenu::_notification(int p_what) { child_controls_changed(); _menu_changed(); - control->update(); + control->queue_redraw(); } break; case NOTIFICATION_WM_MOUSE_ENTER: { @@ -853,7 +863,7 @@ void PopupMenu::_notification(int p_what) { case NOTIFICATION_WM_MOUSE_EXIT: { if (mouse_over >= 0 && (items[mouse_over].submenu.is_empty() || submenu_over != -1)) { mouse_over = -1; - control->update(); + control->queue_redraw(); } } break; @@ -881,7 +891,7 @@ void PopupMenu::_notification(int p_what) { if (!is_visible()) { if (mouse_over >= 0) { mouse_over = -1; - control->update(); + control->queue_redraw(); } for (int i = 0; i < items.size(); i++) { @@ -909,11 +919,10 @@ void PopupMenu::_notification(int p_what) { } // Set margin on the margin container - Ref<StyleBox> panel_style = get_theme_stylebox(SNAME("panel")); - margin_container->add_theme_constant_override("margin_left", panel_style->get_margin(Side::SIDE_LEFT)); - margin_container->add_theme_constant_override("margin_top", panel_style->get_margin(Side::SIDE_TOP)); - margin_container->add_theme_constant_override("margin_right", panel_style->get_margin(Side::SIDE_RIGHT)); - margin_container->add_theme_constant_override("margin_bottom", panel_style->get_margin(Side::SIDE_BOTTOM)); + margin_container->add_theme_constant_override("margin_left", theme_cache.panel_style->get_margin(Side::SIDE_LEFT)); + margin_container->add_theme_constant_override("margin_top", theme_cache.panel_style->get_margin(Side::SIDE_TOP)); + margin_container->add_theme_constant_override("margin_right", theme_cache.panel_style->get_margin(Side::SIDE_RIGHT)); + margin_container->add_theme_constant_override("margin_bottom", theme_cache.panel_style->get_margin(Side::SIDE_BOTTOM)); } } break; } @@ -934,7 +943,7 @@ void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) { ITEM_SETUP_WITH_ACCEL(p_label, p_id, p_accel); items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); notify_property_list_changed(); _menu_changed(); @@ -946,7 +955,7 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe item.icon = p_icon; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); notify_property_list_changed(); _menu_changed(); @@ -958,7 +967,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) { item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -970,7 +979,7 @@ void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String & item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); } @@ -980,7 +989,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, Key p_acce item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -992,7 +1001,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1004,7 +1013,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int item.state = p_default_state; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1023,7 +1032,7 @@ void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_g ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global); items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1034,7 +1043,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortc item.icon = p_icon; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1045,7 +1054,7 @@ void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bo item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1057,7 +1066,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref< item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1068,7 +1077,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_ item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1080,7 +1089,7 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons item.checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1093,7 +1102,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, item.submenu = p_submenu; items.push_back(item); _shape_item(items.size() - 1); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1116,7 +1125,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) { items.write[p_idx].dirty = true; _shape_item(p_idx); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1130,7 +1139,7 @@ void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_tex if (items[p_item].text_direction != p_text_direction) { items.write[p_item].text_direction = p_text_direction; items.write[p_item].dirty = true; - control->update(); + control->queue_redraw(); } } @@ -1142,7 +1151,7 @@ void PopupMenu::set_item_language(int p_item, const String &p_language) { if (items[p_item].language != p_language) { items.write[p_item].language = p_language; items.write[p_item].dirty = true; - control->update(); + control->queue_redraw(); } } @@ -1158,7 +1167,7 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) { items.write[p_idx].icon = p_icon; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1175,7 +1184,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { items.write[p_idx].checked = p_checked; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1192,7 +1201,7 @@ void PopupMenu::set_item_id(int p_idx, int p_id) { items.write[p_idx].id = p_id; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1210,7 +1219,7 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) { items.write[p_idx].accel = p_accel; items.write[p_idx].dirty = true; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1226,7 +1235,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { } items.write[p_idx].metadata = p_meta; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1242,7 +1251,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { } items.write[p_idx].disabled = p_disabled; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1258,7 +1267,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { } items.write[p_idx].submenu = p_submenu; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1266,7 +1275,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { void PopupMenu::toggle_item_checked(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].checked = !items[p_idx].checked; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1377,7 +1386,7 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) { } items.write[p_idx].separator = p_separator; - control->update(); + control->queue_redraw(); } bool PopupMenu::is_item_separator(int p_idx) const { @@ -1397,7 +1406,7 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) { } items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE; - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1413,7 +1422,7 @@ void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) { } items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE; - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1428,7 +1437,7 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) { } items.write[p_idx].tooltip = p_tooltip; - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1453,7 +1462,7 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo _ref_shortcut(items[p_idx].shortcut); } - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1468,7 +1477,7 @@ void PopupMenu::set_item_indent(int p_idx, int p_indent) { } items.write[p_idx].indent = p_indent; - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1484,7 +1493,7 @@ void PopupMenu::set_item_multistate(int p_idx, int p_state) { } items.write[p_idx].state = p_state; - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1499,7 +1508,7 @@ void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) { } items.write[p_idx].shortcut_is_disabled = p_disabled; - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1514,7 +1523,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) { items.write[p_idx].state = 0; } - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1538,7 +1547,7 @@ bool PopupMenu::is_item_shortcut_disabled(int p_idx) const { return items[p_idx].shortcut_is_disabled; } -void PopupMenu::set_current_index(int p_idx) { +void PopupMenu::set_focused_item(int p_idx) { if (p_idx != -1) { ERR_FAIL_INDEX(p_idx, items.size()); } @@ -1552,10 +1561,10 @@ void PopupMenu::set_current_index(int p_idx) { scroll_to_item(mouse_over); } - control->update(); + control->queue_redraw(); } -int PopupMenu::get_current_index() const { +int PopupMenu::get_focused_item() const { return mouse_over; } @@ -1575,7 +1584,7 @@ void PopupMenu::set_item_count(int p_count) { } } - control->update(); + control->queue_redraw(); child_controls_changed(); notify_property_list_changed(); _menu_changed(); @@ -1718,7 +1727,7 @@ void PopupMenu::remove_item(int p_idx) { } items.remove_at(p_idx); - control->update(); + control->queue_redraw(); child_controls_changed(); _menu_changed(); } @@ -1732,7 +1741,7 @@ void PopupMenu::add_separator(const String &p_text, int p_id) { sep.xl_text = atr(p_text); } items.push_back(sep); - control->update(); + control->queue_redraw(); _menu_changed(); } @@ -1744,7 +1753,7 @@ void PopupMenu::clear() { } items.clear(); mouse_over = -1; - control->update(); + control->queue_redraw(); child_controls_changed(); notify_property_list_changed(); _menu_changed(); @@ -1753,7 +1762,7 @@ void PopupMenu::clear() { void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) { if (!shortcut_refcount.has(p_sc)) { shortcut_refcount[p_sc] = 1; - p_sc->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); + p_sc->connect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); } else { shortcut_refcount[p_sc] += 1; } @@ -1763,7 +1772,7 @@ void PopupMenu::_unref_shortcut(Ref<Shortcut> p_sc) { ERR_FAIL_COND(!shortcut_refcount.has(p_sc)); shortcut_refcount[p_sc]--; if (shortcut_refcount[p_sc] == 0) { - p_sc->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::update)); + p_sc->disconnect("changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw)); shortcut_refcount.erase(p_sc); } } @@ -2048,8 +2057,8 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut); ClassDB::bind_method(D_METHOD("get_item_indent", "index"), &PopupMenu::get_item_indent); - ClassDB::bind_method(D_METHOD("set_current_index", "index"), &PopupMenu::set_current_index); - ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index); + ClassDB::bind_method(D_METHOD("set_focused_item", "index"), &PopupMenu::set_focused_item); + ClassDB::bind_method(D_METHOD("get_focused_item"), &PopupMenu::get_focused_item); ClassDB::bind_method(D_METHOD("set_item_count", "count"), &PopupMenu::set_item_count); ClassDB::bind_method(D_METHOD("get_item_count"), &PopupMenu::get_item_count); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index d3ad0762e4..ad7909842e 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -129,6 +129,49 @@ class PopupMenu : public Popup { ScrollContainer *scroll_container = nullptr; Control *control = nullptr; + struct ThemeCache { + Ref<StyleBox> panel_style; + Ref<StyleBox> hover_style; + + Ref<StyleBox> separator_style; + Ref<StyleBox> labeled_separator_left; + Ref<StyleBox> labeled_separator_right; + + int v_separation = 0; + int h_separation = 0; + int indent = 0; + int item_start_padding = 0; + int item_end_padding = 0; + + Ref<Texture2D> checked; + Ref<Texture2D> checked_disabled; + Ref<Texture2D> unchecked; + Ref<Texture2D> unchecked_disabled; + Ref<Texture2D> radio_checked; + Ref<Texture2D> radio_checked_disabled; + Ref<Texture2D> radio_unchecked; + Ref<Texture2D> radio_unchecked_disabled; + + Ref<Texture2D> submenu; + Ref<Texture2D> submenu_mirrored; + + Ref<Font> font; + int font_size = 0; + Ref<Font> font_separator; + int font_separator_size = 0; + + Color font_color; + Color font_hover_color; + Color font_disabled_color; + Color font_accelerator_color; + int font_outline_size = 0; + Color font_outline_color; + + Color font_separator_color; + int font_separator_outline_size = 0; + Color font_separator_outline_color; + } theme_cache; + void _draw_items(); void _draw_background(); @@ -137,6 +180,8 @@ class PopupMenu : public Popup { void _menu_changed(); protected: + virtual void _update_theme_item_cache() override; + virtual void add_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; void _notification(int p_what); @@ -216,8 +261,8 @@ public: int get_item_max_states(int p_idx) const; int get_item_state(int p_idx) const; - void set_current_index(int p_idx); - int get_current_index() const; + void set_focused_item(int p_idx); + int get_focused_item() const; void set_item_count(int p_count); int get_item_count() const; diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index 80859e8eb9..8369eaa227 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -33,18 +33,13 @@ #include "scene/resources/text_line.h" Size2 ProgressBar::get_minimum_size() const { - 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")); - - Size2 minimum_size = bg->get_minimum_size(); - minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height); - minimum_size.width = MAX(minimum_size.width, fg->get_minimum_size().width); - if (percent_visible) { + Size2 minimum_size = theme_cache.background_style->get_minimum_size(); + minimum_size.height = MAX(minimum_size.height, theme_cache.fill_style->get_minimum_size().height); + minimum_size.width = MAX(minimum_size.width, theme_cache.fill_style->get_minimum_size().width); + if (show_percentage) { String txt = "100%"; - TextLine tl = TextLine(txt, font, font_size); - minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + tl.get_size().y); + TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size); + minimum_size.height = MAX(minimum_size.height, theme_cache.background_style->get_minimum_size().height + tl.get_size().y); } else { // this is needed, else the progressbar will collapse minimum_size.width = MAX(minimum_size.width, 1); minimum_size.height = MAX(minimum_size.height, 1); @@ -52,23 +47,30 @@ Size2 ProgressBar::get_minimum_size() const { return minimum_size; } +void ProgressBar::_update_theme_item_cache() { + Range::_update_theme_item_cache(); + + theme_cache.background_style = get_theme_stylebox(SNAME("background")); + theme_cache.fill_style = get_theme_stylebox(SNAME("fill")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); +} + void ProgressBar::_notification(int p_what) { 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())); + draw_style_box(theme_cache.background_style, Rect2(Point2(), get_size())); float r = get_as_ratio(); switch (mode) { case FILL_BEGIN_TO_END: case FILL_END_TO_BEGIN: { - int mp = fg->get_minimum_size().width; + int mp = theme_cache.fill_style->get_minimum_size().width; int p = round(r * (get_size().width - mp)); // We want FILL_BEGIN_TO_END to map to right to left when UI layout is RTL, // and left to right otherwise. And likewise for FILL_END_TO_BEGIN. @@ -76,23 +78,23 @@ void ProgressBar::_notification(int p_what) { if (p > 0) { if (right_to_left) { int p_remaining = round((1.0 - r) * (get_size().width - mp)); - draw_style_box(fg, Rect2(Point2(p_remaining, 0), Size2(p + fg->get_minimum_size().width, get_size().height))); + draw_style_box(theme_cache.fill_style, Rect2(Point2(p_remaining, 0), Size2(p + theme_cache.fill_style->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(theme_cache.fill_style, Rect2(Point2(0, 0), Size2(p + theme_cache.fill_style->get_minimum_size().width, get_size().height))); } } } break; case FILL_TOP_TO_BOTTOM: case FILL_BOTTOM_TO_TOP: { - int mp = fg->get_minimum_size().height; + int mp = theme_cache.fill_style->get_minimum_size().height; int p = round(r * (get_size().height - mp)); if (p > 0) { if (mode == FILL_TOP_TO_BOTTOM) { - draw_style_box(fg, Rect2(Point2(0, 0), Size2(get_size().width, p + fg->get_minimum_size().height))); + draw_style_box(theme_cache.fill_style, Rect2(Point2(0, 0), Size2(get_size().width, p + theme_cache.fill_style->get_minimum_size().height))); } else { int p_remaining = round((1.0 - r) * (get_size().height - mp)); - draw_style_box(fg, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + fg->get_minimum_size().height))); + draw_style_box(theme_cache.fill_style, Rect2(Point2(0, p_remaining), Size2(get_size().width, p + theme_cache.fill_style->get_minimum_size().height))); } } } break; @@ -100,16 +102,16 @@ void ProgressBar::_notification(int p_what) { break; } - if (percent_visible) { + if (show_percentage) { String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign(); - TextLine tl = TextLine(txt, font, font_size); + TextLine tl = TextLine(txt, theme_cache.font, theme_cache.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 (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { + tl.draw_outline(get_canvas_item(), text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color); } - tl.draw(get_canvas_item(), text_pos, font_color); + + tl.draw(get_canvas_item(), text_pos, theme_cache.font_color); } } break; } @@ -118,34 +120,34 @@ void ProgressBar::_notification(int p_what) { void ProgressBar::set_fill_mode(int p_fill) { ERR_FAIL_INDEX(p_fill, FILL_MODE_MAX); mode = (FillMode)p_fill; - update(); + queue_redraw(); } int ProgressBar::get_fill_mode() { return mode; } -void ProgressBar::set_percent_visible(bool p_visible) { - if (percent_visible == p_visible) { +void ProgressBar::set_show_percentage(bool p_visible) { + if (show_percentage == p_visible) { return; } - percent_visible = p_visible; + show_percentage = p_visible; update_minimum_size(); - update(); + queue_redraw(); } -bool ProgressBar::is_percent_visible() const { - return percent_visible; +bool ProgressBar::is_percentage_shown() const { + return show_percentage; } void ProgressBar::_bind_methods() { ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &ProgressBar::set_fill_mode); ClassDB::bind_method(D_METHOD("get_fill_mode"), &ProgressBar::get_fill_mode); - ClassDB::bind_method(D_METHOD("set_percent_visible", "visible"), &ProgressBar::set_percent_visible); - ClassDB::bind_method(D_METHOD("is_percent_visible"), &ProgressBar::is_percent_visible); + ClassDB::bind_method(D_METHOD("set_show_percentage", "visible"), &ProgressBar::set_show_percentage); + ClassDB::bind_method(D_METHOD("is_percentage_shown"), &ProgressBar::is_percentage_shown); ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Begin to End,End to Begin,Top to Bottom,Bottom to Top"), "set_fill_mode", "get_fill_mode"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "percent_visible"), "set_percent_visible", "is_percent_visible"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_percentage"), "set_show_percentage", "is_percentage_shown"); BIND_ENUM_CONSTANT(FILL_BEGIN_TO_END); BIND_ENUM_CONSTANT(FILL_END_TO_BEGIN); diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h index 5ba21ad7d5..b6d7d2c7cf 100644 --- a/scene/gui/progress_bar.h +++ b/scene/gui/progress_bar.h @@ -36,9 +36,22 @@ class ProgressBar : public Range { GDCLASS(ProgressBar, Range); - bool percent_visible = true; + bool show_percentage = true; + + struct ThemeCache { + Ref<StyleBox> background_style; + Ref<StyleBox> fill_style; + + Ref<Font> font; + int font_size = 0; + Color font_color; + int font_outline_size = 0; + Color font_outline_color; + } theme_cache; protected: + virtual void _update_theme_item_cache() override; + void _notification(int p_what); static void _bind_methods(); @@ -54,8 +67,8 @@ public: void set_fill_mode(int p_fill); int get_fill_mode(); - void set_percent_visible(bool p_visible); - bool is_percent_visible() const; + void set_show_percentage(bool p_visible); + bool is_percentage_shown() const; Size2 get_minimum_size() const override; ProgressBar(); diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 0fb1f27802..1eb412abaf 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -46,7 +46,7 @@ void Range::_value_changed(double p_value) { void Range::_value_changed_notify() { _value_changed(shared->val); emit_signal(SNAME("value_changed"), shared->val); - update(); + queue_redraw(); } void Range::Shared::emit_value_changed() { @@ -61,7 +61,7 @@ void Range::Shared::emit_value_changed() { void Range::_changed_notify(const char *p_what) { emit_signal(SNAME("changed")); - update(); + queue_redraw(); } void Range::_validate_values() { diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp index 05dfe4b118..fa5ac5b864 100644 --- a/scene/gui/reference_rect.cpp +++ b/scene/gui/reference_rect.cpp @@ -51,7 +51,7 @@ void ReferenceRect::set_border_color(const Color &p_color) { } border_color = p_color; - update(); + queue_redraw(); } Color ReferenceRect::get_border_color() const { @@ -65,7 +65,7 @@ void ReferenceRect::set_border_width(float p_width) { } border_width = width_max; - update(); + queue_redraw(); } float ReferenceRect::get_border_width() const { @@ -78,7 +78,7 @@ void ReferenceRect::set_editor_only(const bool &p_enabled) { } editor_only = p_enabled; - update(); + queue_redraw(); } bool ReferenceRect::get_editor_only() const { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 8ce8663091..64a0402149 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -134,8 +134,7 @@ RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) co } Rect2 RichTextLabel::_get_text_rect() { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - return Rect2(style->get_offset(), get_size() - style->get_minimum_size()); + return Rect2(theme_cache.normal_style->get_offset(), get_size() - theme_cache.normal_style->get_minimum_size()); } RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item_from, RichTextLabel::Item *p_item_to, int p_position) { @@ -287,8 +286,6 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font switch (it->type) { case ITEM_TABLE: { ItemTable *table = static_cast<ItemTable *>(it); - int hseparation = get_theme_constant(SNAME("table_h_separation")); - int vseparation = get_theme_constant(SNAME("table_v_separation")); int col_count = table->columns.size(); for (int i = 0; i < col_count; i++) { @@ -309,12 +306,12 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font } // Compute minimum width for each cell. - const int available_width = p_width - hseparation * (col_count - 1); + const int available_width = p_width - theme_cache.table_h_separation * (col_count - 1); // Compute available width and total ratio (for expanders). int total_ratio = 0; int remaining_width = available_width; - table->total_width = hseparation; + table->total_width = theme_cache.table_h_separation; for (int i = 0; i < col_count; i++) { remaining_width -= table->columns[i].min_width; @@ -332,7 +329,7 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) { table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; } - table->total_width += table->columns[i].width + hseparation; + table->total_width += table->columns[i].width + theme_cache.table_h_separation; } // Resize to max_width if needed and distribute the remaining space. @@ -394,9 +391,9 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font frame->lines[i].offset.y = prev_h; frame->lines[i].offset += offset; - float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * get_theme_constant(SNAME("line_separation")); + float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * theme_cache.line_separation; if (i > 0) { - h += get_theme_constant(SNAME("line_separation")); + h += theme_cache.line_separation; } if (frame->min_size_over.y > 0) { h = MAX(h, frame->min_size_over.y); @@ -405,15 +402,15 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font h = MIN(h, frame->max_size_over.y); } yofs += h; - prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * theme_cache.line_separation; } yofs += frame->padding.size.y; - offset.x += table->columns[column].width + hseparation + frame->padding.size.x; + offset.x += table->columns[column].width + theme_cache.table_h_separation + frame->padding.size.x; row_height = MAX(yofs, row_height); if (column == col_count - 1) { offset.x = 0; - row_height += vseparation; + row_height += theme_cache.table_v_separation; table->total_height += row_height; offset.y += row_height; table->rows.push_back(row_height); @@ -453,6 +450,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> case TextServer::AUTOWRAP_OFF: break; } + autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES; // Clear cache. l.text_buf->clear(); @@ -550,8 +548,6 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> } break; case ITEM_TABLE: { ItemTable *table = static_cast<ItemTable *>(it); - int hseparation = get_theme_constant(SNAME("table_h_separation")); - int vseparation = get_theme_constant(SNAME("table_v_separation")); int col_count = table->columns.size(); int t_char_count = 0; // Set minimums to zero. @@ -561,7 +557,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> table->columns[i].width = 0; } // Compute minimum width for each cell. - const int available_width = p_width - hseparation * (col_count - 1); + const int available_width = p_width - theme_cache.table_h_separation * (col_count - 1); int idx = 0; for (Item *E : table->subitems) { @@ -590,7 +586,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> // Compute available width and total ratio (for expanders). int total_ratio = 0; int remaining_width = available_width; - table->total_width = hseparation; + table->total_width = theme_cache.table_h_separation; for (int i = 0; i < col_count; i++) { remaining_width -= table->columns[i].min_width; @@ -608,7 +604,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> if (table->columns[i].expand && total_ratio > 0 && remaining_width > 0) { table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio; } - table->total_width += table->columns[i].width + hseparation; + table->total_width += table->columns[i].width + theme_cache.table_h_separation; } // Resize to max_width if needed and distribute the remaining space. @@ -671,9 +667,9 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> frame->lines[i].offset.y = prev_h; frame->lines[i].offset += offset; - float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * get_theme_constant(SNAME("line_separation")); + float h = frame->lines[i].text_buf->get_size().y + (frame->lines[i].text_buf->get_line_count() - 1) * theme_cache.line_separation; if (i > 0) { - h += get_theme_constant(SNAME("line_separation")); + h += theme_cache.line_separation; } if (frame->min_size_over.y > 0) { h = MAX(h, frame->min_size_over.y); @@ -682,16 +678,16 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> h = MIN(h, frame->max_size_over.y); } yofs += h; - prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + prev_h = frame->lines[i].offset.y + frame->lines[i].text_buf->get_size().y + frame->lines[i].text_buf->get_line_count() * theme_cache.line_separation; } yofs += frame->padding.size.y; - offset.x += table->columns[column].width + hseparation + frame->padding.size.x; + offset.x += table->columns[column].width + theme_cache.table_h_separation + frame->padding.size.x; row_height = MAX(yofs, row_height); // Add row height after last column of the row or last cell of the table. if (column == col_count - 1 || E->next() == nullptr) { offset.x = 0; - row_height += vseparation; + row_height += theme_cache.table_v_separation; table->total_height += row_height; offset.y += row_height; table->rows.push_back(row_height); @@ -722,7 +718,6 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), 0); Vector2 off; - int line_spacing = get_theme_constant(SNAME("line_separation")); Line &l = p_frame->lines[p_line]; MutexLock lock(l.text_buf->get_mutex()); @@ -774,8 +769,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } } if (!prefix.is_empty()) { - Ref<Font> font = get_theme_font(SNAME("normal_font")); - int font_size = get_theme_font_size(SNAME("normal_font_size")); + Ref<Font> font = theme_cache.normal_font; + int font_size = theme_cache.normal_font_size; ItemFont *font_it = _find_font(l.from); if (font_it) { @@ -818,7 +813,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o // Draw text. for (int line = 0; line < l.text_buf->get_line_count(); line++) { if (line > 0) { - off.y += line_spacing; + off.y += theme_cache.line_separation; } if (p_ofs.y + off.y >= ctrl_size.height) { @@ -893,10 +888,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } break; case ITEM_TABLE: { ItemTable *table = static_cast<ItemTable *>(it); - Color odd_row_bg = get_theme_color(SNAME("table_odd_row_bg")); - Color even_row_bg = get_theme_color(SNAME("table_even_row_bg")); - Color border = get_theme_color(SNAME("table_border")); - int hseparation = get_theme_constant(SNAME("table_h_separation")); + Color odd_row_bg = theme_cache.table_odd_row_bg; + Color even_row_bg = theme_cache.table_even_row_bg; + Color border = theme_cache.table_border; + int hseparation = theme_cache.table_h_separation; + int col_count = table->columns.size(); int row_count = table->rows.size(); @@ -1032,8 +1028,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start); uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start); uint64_t max_rand = 2147483647; - double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); - double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double current_offset = Math::remap(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double previous_offset = Math::remap(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate)); n_time = (n_time > 1.0) ? 1.0 : n_time; item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f; @@ -1092,8 +1088,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o _draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 0); // Draw main text. - Color selection_fg = get_theme_color(SNAME("font_selected_color")); - Color selection_bg = get_theme_color(SNAME("selection_color")); + Color selection_fg = theme_cache.font_selected_color; + Color selection_bg = theme_cache.selection_color; int sel_start = -1; int sel_end = -1; @@ -1135,7 +1131,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (ul_started) { ul_started = false; float y_off = TS->shaped_text_get_underline_position(rid); - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width); } if (_find_hint(it, nullptr) && underline_hint) { @@ -1148,7 +1144,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (dot_ul_started) { dot_ul_started = false; float y_off = TS->shaped_text_get_underline_position(rid); - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2); } if (_find_strikethrough(it)) { @@ -1161,7 +1157,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } else if (st_started) { st_started = false; float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2; - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width); } @@ -1247,8 +1243,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start); uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start); uint64_t max_rand = 2147483647; - double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); - double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double current_offset = Math::remap(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); + double previous_offset = Math::remap(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI); double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate)); n_time = (n_time > 1.0) ? 1.0 : n_time; item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f; @@ -1300,19 +1296,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o if (ul_started) { ul_started = false; float y_off = TS->shaped_text_get_underline_position(rid); - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width); } if (dot_ul_started) { dot_ul_started = false; float y_off = TS->shaped_text_get_underline_position(rid); - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2); } if (st_started) { st_started = false; float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2; - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width); } } @@ -1322,19 +1318,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o if (ul_started) { ul_started = false; float y_off = TS->shaped_text_get_underline_position(rid); - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width); } if (dot_ul_started) { dot_ul_started = false; float y_off = TS->shaped_text_get_underline_position(rid); - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, underline_width * 2); } if (st_started) { st_started = false; float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2; - float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale(); + float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale; draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width); } // Draw foreground color box @@ -1370,7 +1366,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item while (ofs.y < size.height && from_line < to_line) { MutexLock lock(main->lines[from_line].text_buf->get_mutex()); _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char, false, p_meta); - ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * theme_cache.line_separation; if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) { if (r_outside != nullptr) { *r_outside = false; @@ -1448,9 +1444,6 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (p_click.y >= rect.position.y && p_click.y <= rect.position.y + rect.size.y) { switch (it->type) { case ITEM_TABLE: { - int hseparation = get_theme_constant(SNAME("table_h_separation")); - int vseparation = get_theme_constant(SNAME("table_v_separation")); - ItemTable *table = static_cast<ItemTable *>(it); int idx = 0; @@ -1468,7 +1461,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (rtl) { coff.x = rect.size.width - table->columns[col].width - coff.x; } - Rect2 crect = Rect2(rect.position + coff - frame->padding.position, Size2(table->columns[col].width + hseparation, table->rows[row] + vseparation) + frame->padding.position + frame->padding.size); + Rect2 crect = Rect2(rect.position + coff - frame->padding.position, Size2(table->columns[col].width + theme_cache.table_h_separation, table->rows[row] + theme_cache.table_v_separation) + frame->padding.position + frame->padding.size); if (col == col_count - 1) { if (rtl) { crect.size.x = crect.position.x + crect.size.x; @@ -1507,7 +1500,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V } Rect2 rect = Rect2(p_ofs + off - Vector2(0, TS->shaped_text_get_ascent(rid)) - p_frame->padding.position, TS->shaped_text_get_size(rid) + p_frame->padding.position + p_frame->padding.size); if (p_table) { - rect.size.y += get_theme_constant(SNAME("table_v_separation")); + rect.size.y += theme_cache.table_v_separation; } if (p_click.y >= rect.position.y && p_click.y <= rect.position.y + rect.size.y) { @@ -1546,7 +1539,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V return table_offy; } - off.y += TS->shaped_text_get_descent(rid) + get_theme_constant(SNAME("line_separation")); + off.y += TS->shaped_text_get_descent(rid) + theme_cache.line_separation; } // Text line hit. @@ -1561,8 +1554,8 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V int stop = text_rect_begin; *r_click_item = _find_indentable(it); while (*r_click_item) { - Ref<Font> font = get_theme_font(SNAME("normal_font")); - int font_size = get_theme_font_size(SNAME("normal_font_size")); + Ref<Font> font = theme_cache.normal_font; + int font_size = theme_cache.normal_font_size; ItemFont *font_it = _find_font(*r_click_item); if (font_it) { if (font_it->font.is_valid()) { @@ -1621,7 +1614,7 @@ void RichTextLabel::_scroll_changed(double) { scroll_updated = true; - update(); + queue_redraw(); } void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, double p_delta_time) { @@ -1671,11 +1664,52 @@ int RichTextLabel::_find_first_line(int p_from, int p_to, int p_vofs) const { r = m; } } - return l; + return MIN(l, (int)main->lines.size() - 1); } _FORCE_INLINE_ float RichTextLabel::_calculate_line_vertical_offset(const RichTextLabel::Line &line) const { - return line.get_height(get_theme_constant(SNAME("line_separation"))); + return line.get_height(theme_cache.line_separation); +} + +void RichTextLabel::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.normal_style = get_theme_stylebox(SNAME("normal")); + theme_cache.focus_style = get_theme_stylebox(SNAME("focus")); + theme_cache.progress_bg_style = get_theme_stylebox(SNAME("background"), SNAME("ProgressBar")); + theme_cache.progress_fg_style = get_theme_stylebox(SNAME("fill"), SNAME("ProgressBar")); + + theme_cache.line_separation = get_theme_constant(SNAME("line_separation")); + + theme_cache.normal_font = get_theme_font(SNAME("normal_font")); + theme_cache.normal_font_size = get_theme_font_size(SNAME("normal_font_size")); + + theme_cache.default_color = get_theme_color(SNAME("default_color")); + theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color")); + theme_cache.selection_color = get_theme_color(SNAME("selection_color")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color")); + theme_cache.shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size")); + theme_cache.shadow_offset_x = get_theme_constant(SNAME("shadow_offset_x")); + theme_cache.shadow_offset_y = get_theme_constant(SNAME("shadow_offset_y")); + theme_cache.outline_size = get_theme_constant(SNAME("outline_size")); + + theme_cache.bold_font = get_theme_font(SNAME("bold_font")); + theme_cache.bold_font_size = get_theme_font_size(SNAME("bold_font_size")); + theme_cache.bold_italics_font = get_theme_font(SNAME("bold_italics_font")); + theme_cache.bold_italics_font_size = get_theme_font_size(SNAME("bold_italics_font_size")); + theme_cache.italics_font = get_theme_font(SNAME("italics_font")); + theme_cache.italics_font_size = get_theme_font_size(SNAME("italics_font_size")); + theme_cache.mono_font = get_theme_font(SNAME("mono_font")); + theme_cache.mono_font_size = get_theme_font_size(SNAME("mono_font_size")); + + theme_cache.table_h_separation = get_theme_constant(SNAME("table_h_separation")); + theme_cache.table_v_separation = get_theme_constant(SNAME("table_v_separation")); + theme_cache.table_odd_row_bg = get_theme_color(SNAME("table_odd_row_bg")); + theme_cache.table_even_row_bg = get_theme_color(SNAME("table_even_row_bg")); + theme_cache.table_border = get_theme_color(SNAME("table_border")); + + theme_cache.base_scale = get_theme_default_base_scale(); } void RichTextLabel::_notification(int p_what) { @@ -1685,20 +1719,20 @@ void RichTextLabel::_notification(int p_what) { meta_hovering = nullptr; emit_signal(SNAME("meta_hover_ended"), current_meta); current_meta = false; - update(); + queue_redraw(); } } break; case NOTIFICATION_RESIZED: { _stop_thread(); main->first_resized_line.store(0); //invalidate ALL - update(); + queue_redraw(); } break; case NOTIFICATION_THEME_CHANGED: { _stop_thread(); main->first_invalid_font_line.store(0); //invalidate ALL - update(); + queue_redraw(); } break; case NOTIFICATION_ENTER_TREE: { @@ -1708,7 +1742,7 @@ void RichTextLabel::_notification(int p_what) { } main->first_invalid_line.store(0); //invalidate ALL - update(); + queue_redraw(); } break; case NOTIFICATION_PREDELETE: @@ -1720,22 +1754,22 @@ void RichTextLabel::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { _stop_thread(); main->first_invalid_line.store(0); //invalidate ALL - update(); + queue_redraw(); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - update(); + queue_redraw(); } break; case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); Size2 size = get_size(); - draw_style_box(get_theme_stylebox(SNAME("normal")), Rect2(Point2(), size)); + draw_style_box(theme_cache.normal_style, Rect2(Point2(), size)); if (has_focus()) { RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, true); - draw_style_box(get_theme_stylebox(SNAME("focus")), Rect2(Point2(), size)); + draw_style_box(theme_cache.focus_style, Rect2(Point2(), size)); RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false); } @@ -1745,24 +1779,20 @@ void RichTextLabel::_notification(int p_what) { } else { // Draw loading progress bar. if ((progress_delay > 0) && (OS::get_singleton()->get_ticks_msec() - loading_started >= (uint64_t)progress_delay)) { - Ref<StyleBox> bg = get_theme_stylebox(SNAME("bg"), SNAME("ProgressBar")); - Ref<StyleBox> fg = get_theme_stylebox(SNAME("fg"), SNAME("ProgressBar")); - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - - Vector2 p_size = Vector2(size.width - (style->get_offset().x + vscroll->get_combined_minimum_size().width) * 2, vscroll->get_combined_minimum_size().width); - Vector2 p_pos = Vector2(style->get_offset().x, size.height - style->get_offset().y - vscroll->get_combined_minimum_size().width); + Vector2 p_size = Vector2(size.width - (theme_cache.normal_style->get_offset().x + vscroll->get_combined_minimum_size().width) * 2, vscroll->get_combined_minimum_size().width); + Vector2 p_pos = Vector2(theme_cache.normal_style->get_offset().x, size.height - theme_cache.normal_style->get_offset().y - vscroll->get_combined_minimum_size().width); - draw_style_box(bg, Rect2(p_pos, p_size)); + draw_style_box(theme_cache.progress_bg_style, Rect2(p_pos, p_size)); bool right_to_left = is_layout_rtl(); double r = loaded.load(); - int mp = fg->get_minimum_size().width; + int mp = theme_cache.progress_fg_style->get_minimum_size().width; int p = round(r * (p_size.width - mp)); if (right_to_left) { int p_remaining = round((1.0 - r) * (p_size.width - mp)); - draw_style_box(fg, Rect2(p_pos + Point2(p_remaining, 0), Size2(p + fg->get_minimum_size().width, p_size.height))); + draw_style_box(theme_cache.progress_fg_style, Rect2(p_pos + Point2(p_remaining, 0), Size2(p + theme_cache.progress_fg_style->get_minimum_size().width, p_size.height))); } else { - draw_style_box(fg, Rect2(p_pos, Size2(p + fg->get_minimum_size().width, p_size.height))); + draw_style_box(theme_cache.progress_fg_style, Rect2(p_pos, Size2(p + theme_cache.progress_fg_style->get_minimum_size().width, p_size.height))); } } } @@ -1775,13 +1805,7 @@ void RichTextLabel::_notification(int p_what) { int to_line = main->first_invalid_line.load(); int from_line = _find_first_line(0, to_line, vofs); - Ref<Font> base_font = get_theme_font(SNAME("normal_font")); - Color base_color = get_theme_color(SNAME("default_color")); - Color outline_color = get_theme_color(SNAME("font_outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); - Color font_shadow_color = get_theme_color(SNAME("font_shadow_color")); - int shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size")); - Point2 shadow_ofs(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y"))); + Point2 shadow_ofs(theme_cache.shadow_offset_x, theme_cache.shadow_offset_y); visible_paragraph_count = 0; visible_line_count = 0; @@ -1793,8 +1817,8 @@ void RichTextLabel::_notification(int p_what) { MutexLock lock(main->lines[from_line].text_buf->get_mutex()); visible_paragraph_count++; - visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_shadow_color, shadow_outline_size, shadow_ofs, processed_glyphs); - ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, theme_cache.default_color, theme_cache.outline_size, theme_cache.font_outline_color, theme_cache.font_shadow_color, theme_cache.shadow_outline_size, shadow_ofs, processed_glyphs); + ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * theme_cache.line_separation; from_line++; } } break; @@ -1806,7 +1830,7 @@ void RichTextLabel::_notification(int p_what) { } double dt = get_process_delta_time(); _update_fx(main, dt); - update(); + queue_redraw(); } } break; @@ -1918,7 +1942,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text()); } - update(); + queue_redraw(); break; } } @@ -2002,11 +2026,11 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { handled = true; } if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() - get_theme_font(SNAME("normal_font"))->get_height(get_theme_font_size(SNAME("normal_font_size")))); + vscroll->set_value(vscroll->get_value() - theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() + get_theme_font(SNAME("normal_font"))->get_height(get_theme_font_size(SNAME("normal_font_size")))); + vscroll->set_value(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) { @@ -2084,7 +2108,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { } selection.active = true; - update(); + queue_redraw(); } Variant meta; @@ -2539,9 +2563,11 @@ bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) { void RichTextLabel::_thread_function(void *self) { RichTextLabel *rtl = reinterpret_cast<RichTextLabel *>(self); + rtl->set_physics_process_internal(true); rtl->_process_line_caches(); + rtl->set_physics_process_internal(false); rtl->updating.store(false); - rtl->call_deferred(SNAME("update")); + rtl->call_deferred(SNAME("queue_redraw")); } void RichTextLabel::_stop_thread() { @@ -2562,7 +2588,7 @@ void RichTextLabel::set_threaded(bool p_threaded) { if (threaded != p_threaded) { _stop_thread(); threaded = p_threaded; - update(); + queue_redraw(); } } @@ -2586,14 +2612,12 @@ bool RichTextLabel::_validate_line_caches() { MutexLock data_lock(data_mutex); Rect2 text_rect = _get_text_rect(); - Ref<Font> base_font = get_theme_font(SNAME("normal_font")); - int base_font_size = get_theme_font_size(SNAME("normal_font_size")); int ctrl_height = get_size().height; // Update fonts. if (main->first_invalid_font_line.load() != (int)main->lines.size()) { for (int i = main->first_invalid_font_line.load(); i < (int)main->lines.size(); i++) { - _update_line_font(main, i, base_font, base_font_size); + _update_line_font(main, i, theme_cache.normal_font, theme_cache.normal_font_size); } main->first_resized_line.store(main->first_invalid_font_line.load()); main->first_invalid_font_line.store(main->lines.size()); @@ -2608,7 +2632,7 @@ bool RichTextLabel::_validate_line_caches() { float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]); for (int i = fi; i < (int)main->lines.size(); i++) { - total_height = _resize_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height); + total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height); updating_scroll = true; bool exceeds = total_height > ctrl_height && scroll_active; @@ -2628,7 +2652,7 @@ bool RichTextLabel::_validate_line_caches() { total_height = 0; for (int j = 0; j <= i; j++) { - total_height = _resize_line(main, j, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height); + total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height); main->first_resized_line.store(j); } @@ -2657,11 +2681,10 @@ bool RichTextLabel::_validate_line_caches() { loaded.store(true); thread.start(RichTextLabel::_thread_function, reinterpret_cast<void *>(this)); loading_started = OS::get_singleton()->get_ticks_msec(); - set_physics_process_internal(true); return false; } else { _process_line_caches(); - update(); + queue_redraw(); return true; } } @@ -2675,15 +2698,13 @@ void RichTextLabel::_process_line_caches() { MutexLock data_lock(data_mutex); Rect2 text_rect = _get_text_rect(); - int base_font_size = get_theme_font_size(SNAME("normal_font_size")); - Ref<Font> base_font = get_theme_font(SNAME("normal_font")); int ctrl_height = get_size().height; int fi = main->first_invalid_line.load(); int total_chars = (fi == 0) ? 0 : (main->lines[fi].char_offset + main->lines[fi].char_count); float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]); for (int i = fi; i < (int)main->lines.size(); i++) { - total_height = _shape_line(main, i, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars); + total_height = _shape_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars); updating_scroll = true; bool exceeds = total_height > ctrl_height && scroll_active; if (exceeds != scroll_visible) { @@ -2704,7 +2725,7 @@ void RichTextLabel::_process_line_caches() { // since scroll was added or removed we need to resize all lines total_height = 0; for (int j = 0; j <= i; j++) { - total_height = _resize_line(main, j, base_font, base_font_size, text_rect.get_size().width - scroll_w, total_height); + total_height = _resize_line(main, j, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height); main->first_invalid_line.store(j); main->first_resized_line.store(j); @@ -2799,7 +2820,7 @@ void RichTextLabel::add_text(const String &p_text) { pos = end + 1; } - update(); + queue_redraw(); } void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) { @@ -2837,7 +2858,7 @@ void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) if (fixed_width != -1) { update_minimum_size(); } - update(); + queue_redraw(); } void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_subitem_line) { @@ -2918,7 +2939,7 @@ void RichTextLabel::add_newline() { _add_item(item, false); current_frame->lines.resize(current_frame->lines.size() + 1); _invalidate_current_line(current_frame); - update(); + queue_redraw(); } bool RichTextLabel::remove_line(const int p_line) { @@ -2957,7 +2978,7 @@ bool RichTextLabel::remove_line(const int p_line) { } main->first_invalid_line.store(0); - update(); + queue_redraw(); return true; } @@ -2997,38 +3018,33 @@ void RichTextLabel::push_font(const Ref<Font> &p_font, int p_size) { } void RichTextLabel::push_normal() { - Ref<Font> normal_font = get_theme_font(SNAME("normal_font")); - ERR_FAIL_COND(normal_font.is_null()); + ERR_FAIL_COND(theme_cache.normal_font.is_null()); - push_font(normal_font, get_theme_font_size(SNAME("normal_font_size"))); + push_font(theme_cache.normal_font, theme_cache.normal_font_size); } void RichTextLabel::push_bold() { - Ref<Font> bold_font = get_theme_font(SNAME("bold_font")); - ERR_FAIL_COND(bold_font.is_null()); + ERR_FAIL_COND(theme_cache.bold_font.is_null()); - push_font(bold_font, get_theme_font_size(SNAME("bold_font_size"))); + push_font(theme_cache.bold_font, theme_cache.bold_font_size); } void RichTextLabel::push_bold_italics() { - Ref<Font> bold_italics_font = get_theme_font(SNAME("bold_italics_font")); - ERR_FAIL_COND(bold_italics_font.is_null()); + ERR_FAIL_COND(theme_cache.bold_italics_font.is_null()); - push_font(bold_italics_font, get_theme_font_size(SNAME("bold_italics_font_size"))); + push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size); } void RichTextLabel::push_italics() { - Ref<Font> italics_font = get_theme_font(SNAME("italics_font")); - ERR_FAIL_COND(italics_font.is_null()); + ERR_FAIL_COND(theme_cache.italics_font.is_null()); - push_font(italics_font, get_theme_font_size(SNAME("italics_font_size"))); + push_font(theme_cache.italics_font, theme_cache.italics_font_size); } void RichTextLabel::push_mono() { - Ref<Font> mono_font = get_theme_font(SNAME("mono_font")); - ERR_FAIL_COND(mono_font.is_null()); + ERR_FAIL_COND(theme_cache.mono_font.is_null()); - push_font(mono_font, get_theme_font_size(SNAME("mono_font_size"))); + push_font(theme_cache.mono_font, theme_cache.mono_font_size); } void RichTextLabel::push_font_size(int p_font_size) { @@ -3386,7 +3402,7 @@ void RichTextLabel::set_tab_size(int p_spaces) { tab_size = p_spaces; main->first_resized_line.store(0); - update(); + queue_redraw(); } int RichTextLabel::get_tab_size() const { @@ -3410,7 +3426,7 @@ void RichTextLabel::set_meta_underline(bool p_underline) { } underline_meta = p_underline; - update(); + queue_redraw(); } bool RichTextLabel::is_meta_underlined() const { @@ -3419,7 +3435,7 @@ bool RichTextLabel::is_meta_underlined() const { void RichTextLabel::set_hint_underline(bool p_underline) { underline_hint = p_underline; - update(); + queue_redraw(); } bool RichTextLabel::is_hint_underlined() const { @@ -3445,7 +3461,7 @@ void RichTextLabel::set_scroll_active(bool p_active) { scroll_active = p_active; vscroll->set_drag_node_enabled(p_active); - update(); + queue_redraw(); } bool RichTextLabel::is_scroll_active() const { @@ -3475,13 +3491,6 @@ void RichTextLabel::append_text(const String &p_bbcode) { int pos = 0; List<String> tag_stack; - Ref<Font> normal_font = get_theme_font(SNAME("normal_font")); - Ref<Font> bold_font = get_theme_font(SNAME("bold_font")); - Ref<Font> italics_font = get_theme_font(SNAME("italics_font")); - Ref<Font> bold_italics_font = get_theme_font(SNAME("bold_italics_font")); - Ref<Font> mono_font = get_theme_font(SNAME("mono_font")); - - Color base_color = get_theme_color(SNAME("default_color")); int indent_level = 0; @@ -3626,9 +3635,9 @@ void RichTextLabel::append_text(const String &p_bbcode) { //use bold font in_bold = true; if (in_italics) { - push_font(bold_italics_font, get_theme_font_size(SNAME("bold_italics_font_size"))); + push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size); } else { - push_font(bold_font, get_theme_font_size(SNAME("bold_font_size"))); + push_font(theme_cache.bold_font, theme_cache.bold_font_size); } pos = brk_end + 1; tag_stack.push_front(tag); @@ -3636,15 +3645,15 @@ void RichTextLabel::append_text(const String &p_bbcode) { //use italics font in_italics = true; if (in_bold) { - push_font(bold_italics_font, get_theme_font_size(SNAME("bold_italics_font_size"))); + push_font(theme_cache.bold_italics_font, theme_cache.bold_italics_font_size); } else { - push_font(italics_font, get_theme_font_size(SNAME("italics_font_size"))); + push_font(theme_cache.italics_font, theme_cache.italics_font_size); } pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag == "code") { //use monospace font - push_font(mono_font, get_theme_font_size(SNAME("mono_font_size"))); + push_font(theme_cache.mono_font, theme_cache.mono_font_size); pos = brk_end + 1; tag_stack.push_front(tag); } else if (tag.begins_with("table=")) { @@ -3929,11 +3938,11 @@ void RichTextLabel::append_text(const String &p_bbcode) { tag_stack.push_front("hint"); } else if (tag.begins_with("dropcap")) { Vector<String> subtag = tag.substr(5, tag.length()).split(" "); - int fs = get_theme_font_size(SNAME("normal_font_size")) * 3; - Ref<Font> f = get_theme_font(SNAME("normal_font")); - Color color = get_theme_color(SNAME("default_color")); - Color outline_color = get_theme_color(SNAME("outline_color")); - int outline_size = get_theme_constant(SNAME("outline_size")); + int fs = theme_cache.normal_font_size * 3; + Ref<Font> f = theme_cache.normal_font; + Color color = theme_cache.default_color; + Color outline_color = theme_cache.font_outline_color; + int outline_size = theme_cache.outline_size; Rect2 dropcap_margins = Rect2(); for (int i = 0; i < subtag.size(); i++) { @@ -4051,14 +4060,14 @@ void RichTextLabel::append_text(const String &p_bbcode) { tag_stack.push_front(bbcode_name); } else if (tag.begins_with("color=")) { String color_str = tag.substr(6, tag.length()); - Color color = Color::from_string(color_str, base_color); + Color color = Color::from_string(color_str, theme_cache.default_color); push_color(color); pos = brk_end + 1; tag_stack.push_front("color"); } else if (tag.begins_with("outline_color=")) { String color_str = tag.substr(14, tag.length()); - Color color = Color::from_string(color_str, base_color); + Color color = Color::from_string(color_str, theme_cache.default_color); push_outline_color(color); pos = brk_end + 1; tag_stack.push_front("outline_color"); @@ -4073,7 +4082,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { String fnt_ftr = tag.substr(18, tag.length()); Vector<String> subtag = fnt_ftr.split(","); if (subtag.size() > 0) { - Ref<Font> font = normal_font; + Ref<Font> font = theme_cache.normal_font; int font_size = 0; ItemFont *font_it = _find_font(current); if (font_it) { @@ -4285,7 +4294,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { } else if (tag.begins_with("bgcolor=")) { String color_str = tag.substr(8, tag.length()); - Color color = Color::from_string(color_str, base_color); + Color color = Color::from_string(color_str, theme_cache.default_color); push_bgcolor(color); pos = brk_end + 1; @@ -4293,7 +4302,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { } else if (tag.begins_with("fgcolor=")) { String color_str = tag.substr(8, tag.length()); - Color color = Color::from_string(color_str, base_color); + Color color = Color::from_string(color_str, theme_cache.default_color); push_fgcolor(color); pos = brk_end + 1; @@ -4355,16 +4364,18 @@ int RichTextLabel::get_visible_paragraph_count() const { if (!is_visible()) { return 0; } + + const_cast<RichTextLabel *>(this)->_validate_line_caches(); return visible_paragraph_count; } void RichTextLabel::scroll_to_line(int p_line) { - _validate_line_caches(); - if (p_line <= 0) { vscroll->set_value(0); return; } + _validate_line_caches(); + int line_count = 0; int to_line = main->first_invalid_line.load(); for (int i = 0; i < to_line; i++) { @@ -4372,7 +4383,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 + get_theme_constant(SNAME("line_separation")); + line_offset += main->lines[i].text_buf->get_line_size(j).y + theme_cache.line_separation; } vscroll->set_value(main->lines[i].offset.y + line_offset); return; @@ -4383,6 +4394,8 @@ void RichTextLabel::scroll_to_line(int p_line) { } float RichTextLabel::get_line_offset(int p_line) { + _validate_line_caches(); + int line_count = 0; int to_line = main->first_invalid_line.load(); for (int i = 0; i < to_line; i++) { @@ -4390,7 +4403,7 @@ float RichTextLabel::get_line_offset(int p_line) { 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")); + line_offset += main->lines[i].text_buf->get_line_size(j).y + theme_cache.line_separation; } return main->lines[i].offset.y + line_offset; } @@ -4400,6 +4413,8 @@ float RichTextLabel::get_line_offset(int p_line) { } float RichTextLabel::get_paragraph_offset(int p_paragraph) { + _validate_line_caches(); + int to_line = main->first_invalid_line.load(); if (0 <= p_paragraph && p_paragraph < to_line) { return main->lines[p_paragraph].offset.y; @@ -4408,6 +4423,8 @@ float RichTextLabel::get_paragraph_offset(int p_paragraph) { } int RichTextLabel::get_line_count() const { + const_cast<RichTextLabel *>(this)->_validate_line_caches(); + int line_count = 0; int to_line = main->first_invalid_line.load(); for (int i = 0; i < to_line; i++) { @@ -4421,6 +4438,8 @@ int RichTextLabel::get_visible_line_count() const { if (!is_visible()) { return 0; } + const_cast<RichTextLabel *>(this)->_validate_line_caches(); + return visible_line_count; } @@ -4570,7 +4589,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p if (!(p_search_previous && char_idx < 0) && _search_line(selection.from_frame, selection.from_line, p_string, char_idx, p_search_previous)) { scroll_to_line(selection.from_frame->line + selection.from_line); - update(); + queue_redraw(); return true; } char_idx = p_search_previous ? -1 : 0; @@ -4595,7 +4614,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p // Search for next element if (_search_table(parent_table, parent_element, p_string, p_search_previous)) { scroll_to_line(selection.from_frame->line + selection.from_line); - update(); + queue_redraw(); return true; } } @@ -4619,7 +4638,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p if (_search_line(main, current_line, p_string, char_idx, p_search_previous)) { scroll_to_line(current_line); - update(); + queue_redraw(); return true; } p_search_previous ? current_line-- : current_line++; @@ -4729,7 +4748,7 @@ String RichTextLabel::get_selected_text() const { void RichTextLabel::deselect() { selection.active = false; - update(); + queue_redraw(); } void RichTextLabel::selection_copy() { @@ -4784,7 +4803,7 @@ void RichTextLabel::select_all() { selection.to_char = to_frame->lines[to_line].char_count; selection.to_item = to_item; selection.active = true; - update(); + queue_redraw(); } bool RichTextLabel::is_selection_enabled() const { @@ -4835,7 +4854,14 @@ void RichTextLabel::set_use_bbcode(bool p_enable) { } use_bbcode = p_enable; notify_property_list_changed(); - set_text(text); + + const String current_text = text; + if (use_bbcode) { + parse_bbcode(current_text); + } else { // raw text + clear(); + add_text(current_text); + } } bool RichTextLabel::is_using_bbcode() const { @@ -4872,7 +4898,7 @@ void RichTextLabel::set_text_direction(Control::TextDirection p_text_direction) text_direction = p_text_direction; main->first_invalid_line.store(0); //invalidate ALL _validate_line_caches(); - update(); + queue_redraw(); } } @@ -4883,7 +4909,7 @@ void RichTextLabel::set_structured_text_bidi_override(TextServer::StructuredText st_parser = p_parser; main->first_invalid_line.store(0); //invalidate ALL _validate_line_caches(); - update(); + queue_redraw(); } } @@ -4898,7 +4924,7 @@ void RichTextLabel::set_structured_text_bidi_override_options(Array p_args) { st_args = p_args; main->first_invalid_line.store(0); //invalidate ALL _validate_line_caches(); - update(); + queue_redraw(); } } @@ -4917,7 +4943,7 @@ void RichTextLabel::set_language(const String &p_language) { language = p_language; main->first_invalid_line.store(0); //invalidate ALL _validate_line_caches(); - update(); + queue_redraw(); } } @@ -4932,7 +4958,7 @@ void RichTextLabel::set_autowrap_mode(TextServer::AutowrapMode p_mode) { autowrap_mode = p_mode; main->first_invalid_line = 0; //invalidate ALL _validate_line_caches(); - update(); + queue_redraw(); } } @@ -4944,10 +4970,10 @@ void RichTextLabel::set_visible_ratio(float p_ratio) { if (visible_ratio != p_ratio) { _stop_thread(); - if (visible_ratio >= 1.0) { + if (p_ratio >= 1.0) { visible_characters = -1; visible_ratio = 1.0; - } else if (visible_ratio < 0.0) { + } else if (p_ratio < 0.0) { visible_characters = 0; visible_ratio = 0.0; } else { @@ -4959,7 +4985,7 @@ void RichTextLabel::set_visible_ratio(float p_ratio) { main->first_invalid_line.store(0); // Invalidate ALL. _validate_line_caches(); } - update(); + queue_redraw(); } } @@ -4996,7 +5022,12 @@ int RichTextLabel::get_content_height() const { int to_line = main->first_invalid_line.load(); if (to_line) { MutexLock lock(main->lines[to_line - 1].text_buf->get_mutex()); - total_height = main->lines[to_line - 1].offset.y + main->lines[to_line - 1].text_buf->get_size().y + main->lines[to_line - 1].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation")); + if (theme_cache.line_separation < 0) { + // Do not apply to the last line to avoid cutting text. + total_height = main->lines[to_line - 1].offset.y + main->lines[to_line - 1].text_buf->get_size().y + (main->lines[to_line - 1].text_buf->get_line_count() - 1) * theme_cache.line_separation; + } else { + total_height = main->lines[to_line - 1].offset.y + main->lines[to_line - 1].text_buf->get_size().y + main->lines[to_line - 1].text_buf->get_line_count() * theme_cache.line_separation; + } } return total_height; } @@ -5259,7 +5290,7 @@ void RichTextLabel::set_visible_characters_behavior(TextServer::VisibleCharacter visible_chars_behavior = p_behavior; main->first_invalid_line.store(0); //invalidate ALL _validate_line_caches(); - update(); + queue_redraw(); } } @@ -5280,7 +5311,7 @@ void RichTextLabel::set_visible_characters(int p_visible) { main->first_invalid_line.store(0); //invalidate ALL _validate_line_caches(); } - update(); + queue_redraw(); } } @@ -5289,6 +5320,8 @@ int RichTextLabel::get_visible_characters() const { } int RichTextLabel::get_character_line(int p_char) { + _validate_line_caches(); + int line_count = 0; int to_line = main->first_invalid_line.load(); for (int i = 0; i < to_line; i++) { @@ -5309,6 +5342,8 @@ int RichTextLabel::get_character_line(int p_char) { } int RichTextLabel::get_character_paragraph(int p_char) { + _validate_line_caches(); + int para_count = 0; int to_line = main->first_invalid_line.load(); for (int i = 0; i < to_line; i++) { @@ -5340,6 +5375,8 @@ int RichTextLabel::get_total_character_count() const { } int RichTextLabel::get_total_glyph_count() const { + const_cast<RichTextLabel *>(this)->_validate_line_caches(); + int tg = 0; Item *it = main; while (it) { @@ -5366,8 +5403,7 @@ void RichTextLabel::set_fixed_size_to_width(int p_width) { } Size2 RichTextLabel::get_minimum_size() const { - Ref<StyleBox> style = get_theme_stylebox(SNAME("normal")); - Size2 size = style->get_minimum_size(); + Size2 size = theme_cache.normal_style->get_minimum_size(); if (fixed_width != -1) { size.x += fixed_width; diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 79f9c62539..8bc28a9ecf 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -83,6 +83,7 @@ public: }; protected: + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); @@ -512,6 +513,46 @@ private: bool fit_content_height = false; + struct ThemeCache { + Ref<StyleBox> normal_style; + Ref<StyleBox> focus_style; + Ref<StyleBox> progress_bg_style; + Ref<StyleBox> progress_fg_style; + + int line_separation; + + Ref<Font> normal_font; + int normal_font_size; + + Color default_color; + Color font_selected_color; + Color selection_color; + Color font_outline_color; + Color font_shadow_color; + int shadow_outline_size; + int shadow_offset_x; + int shadow_offset_y; + int outline_size; + Color outline_color; + + Ref<Font> bold_font; + int bold_font_size; + Ref<Font> bold_italics_font; + int bold_italics_font_size; + Ref<Font> italics_font; + int italics_font_size; + Ref<Font> mono_font; + int mono_font_size; + + int table_h_separation; + int table_v_separation; + Color table_odd_row_bg; + Color table_even_row_bg; + Color table_border; + + float base_scale = 1.0; + } theme_cache; + public: String get_parsed_text() const; void add_text(const String &p_text); diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 48c57d9b1b..6c05b171e3 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -70,8 +70,8 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { if (b->is_pressed()) { double ofs = orientation == VERTICAL ? b->get_position().y : b->get_position().x; - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); + Ref<Texture2D> decr = theme_cache.decrement_icon; + Ref<Texture2D> incr = theme_cache.increment_icon; double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width(); double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width(); @@ -82,14 +82,14 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { if (ofs < decr_size) { decr_active = true; set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); - update(); + queue_redraw(); return; } if (ofs > total - incr_size) { incr_active = true; set_value(get_value() + (custom_step >= 0 ? custom_step : get_step())); - update(); + queue_redraw(); return; } @@ -117,7 +117,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { drag.active = true; drag.pos_at_click = grabber_ofs + ofs; drag.value_at_click = get_as_ratio(); - update(); + queue_redraw(); } else { if (scrolling) { target_scroll = CLAMP(target_scroll + get_page(), get_min(), get_max() - get_page()); @@ -137,7 +137,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { incr_active = false; decr_active = false; drag.active = false; - update(); + queue_redraw(); } } @@ -146,7 +146,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { if (drag.active) { double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x; - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); + Ref<Texture2D> decr = theme_cache.decrement_icon; double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width(); ofs -= decr_size; @@ -156,8 +156,8 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { set_as_ratio(drag.value_at_click + diff); } else { double ofs = orientation == VERTICAL ? m->get_position().y : m->get_position().x; - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); + Ref<Texture2D> decr = theme_cache.decrement_icon; + Ref<Texture2D> incr = theme_cache.increment_icon; double decr_size = orientation == VERTICAL ? decr->get_height() : decr->get_width(); double incr_size = orientation == VERTICAL ? incr->get_height() : incr->get_width(); @@ -177,7 +177,7 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { if (new_hilite != highlight) { highlight = new_hilite; - update(); + queue_redraw(); } } } @@ -217,6 +217,24 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { } } +void ScrollBar::_update_theme_item_cache() { + Range::_update_theme_item_cache(); + + theme_cache.scroll_style = get_theme_stylebox(SNAME("scroll")); + theme_cache.scroll_focus_style = get_theme_stylebox(SNAME("scroll_focus")); + theme_cache.scroll_offset_style = get_theme_stylebox(SNAME("hscroll")); + theme_cache.grabber_style = get_theme_stylebox(SNAME("grabber")); + theme_cache.grabber_hl_style = get_theme_stylebox(SNAME("grabber_highlight")); + theme_cache.grabber_pressed_style = get_theme_stylebox(SNAME("grabber_pressed")); + + theme_cache.increment_icon = get_theme_icon(SNAME("increment")); + theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight")); + theme_cache.increment_pressed_icon = get_theme_icon(SNAME("increment_pressed")); + theme_cache.decrement_icon = get_theme_icon(SNAME("decrement")); + theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight")); + theme_cache.decrement_pressed_icon = get_theme_icon(SNAME("decrement_pressed")); +} + void ScrollBar::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { @@ -225,30 +243,30 @@ void ScrollBar::_notification(int p_what) { Ref<Texture2D> decr, incr; if (decr_active) { - decr = get_theme_icon(SNAME("decrement_pressed")); + decr = theme_cache.decrement_pressed_icon; } else if (highlight == HIGHLIGHT_DECR) { - decr = get_theme_icon(SNAME("decrement_highlight")); + decr = theme_cache.decrement_hl_icon; } else { - decr = get_theme_icon(SNAME("decrement")); + decr = theme_cache.decrement_icon; } if (incr_active) { - incr = get_theme_icon(SNAME("increment_pressed")); + incr = theme_cache.increment_pressed_icon; } else if (highlight == HIGHLIGHT_INCR) { - incr = get_theme_icon(SNAME("increment_highlight")); + incr = theme_cache.increment_hl_icon; } else { - incr = get_theme_icon(SNAME("increment")); + incr = theme_cache.increment_icon; } - Ref<StyleBox> bg = has_focus() ? get_theme_stylebox(SNAME("scroll_focus")) : get_theme_stylebox(SNAME("scroll")); + Ref<StyleBox> bg = has_focus() ? theme_cache.scroll_focus_style : theme_cache.scroll_style; Ref<StyleBox> grabber; if (drag.active) { - grabber = get_theme_stylebox(SNAME("grabber_pressed")); + grabber = theme_cache.grabber_pressed_style; } else if (highlight == HIGHLIGHT_RANGE) { - grabber = get_theme_stylebox(SNAME("grabber_highlight")); + grabber = theme_cache.grabber_hl_style; } else { - grabber = get_theme_stylebox(SNAME("grabber")); + grabber = theme_cache.grabber_style; } Point2 ofs; @@ -303,7 +321,7 @@ void ScrollBar::_notification(int p_what) { 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), CONNECT_ONESHOT); + drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT); } } break; @@ -408,13 +426,13 @@ void ScrollBar::_notification(int p_what) { case NOTIFICATION_MOUSE_EXIT: { highlight = HIGHLIGHT_NONE; - update(); + queue_redraw(); } break; } } double ScrollBar::get_grabber_min_size() const { - Ref<StyleBox> grabber = get_theme_stylebox(SNAME("grabber")); + Ref<StyleBox> grabber = theme_cache.grabber_style; Size2 gminsize = grabber->get_minimum_size() + grabber->get_center_size(); return (orientation == VERTICAL) ? gminsize.height : gminsize.width; } @@ -435,17 +453,17 @@ double ScrollBar::get_area_size() const { switch (orientation) { case VERTICAL: { double area = get_size().height; - area -= get_theme_stylebox(SNAME("scroll"))->get_minimum_size().height; - area -= get_theme_icon(SNAME("increment"))->get_height(); - area -= get_theme_icon(SNAME("decrement"))->get_height(); + area -= theme_cache.scroll_style->get_minimum_size().height; + area -= theme_cache.increment_icon->get_height(); + area -= theme_cache.decrement_icon->get_height(); area -= get_grabber_min_size(); return area; } break; case HORIZONTAL: { double area = get_size().width; - area -= get_theme_stylebox(SNAME("scroll"))->get_minimum_size().width; - area -= get_theme_icon(SNAME("increment"))->get_width(); - area -= get_theme_icon(SNAME("decrement"))->get_width(); + area -= theme_cache.scroll_style->get_minimum_size().width; + area -= theme_cache.increment_icon->get_width(); + area -= theme_cache.decrement_icon->get_width(); area -= get_grabber_min_size(); return area; } break; @@ -459,13 +477,13 @@ double ScrollBar::get_area_offset() const { double ofs = 0.0; if (orientation == VERTICAL) { - ofs += get_theme_stylebox(SNAME("hscroll"))->get_margin(SIDE_TOP); - ofs += get_theme_icon(SNAME("decrement"))->get_height(); + ofs += theme_cache.scroll_offset_style->get_margin(SIDE_TOP); + ofs += theme_cache.decrement_icon->get_height(); } if (orientation == HORIZONTAL) { - ofs += get_theme_stylebox(SNAME("hscroll"))->get_margin(SIDE_LEFT); - ofs += get_theme_icon(SNAME("decrement"))->get_width(); + ofs += theme_cache.scroll_offset_style->get_margin(SIDE_LEFT); + ofs += theme_cache.decrement_icon->get_width(); } return ofs; @@ -476,9 +494,9 @@ double ScrollBar::get_grabber_offset() const { } Size2 ScrollBar::get_minimum_size() const { - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - Ref<StyleBox> bg = get_theme_stylebox(SNAME("scroll")); + Ref<Texture2D> incr = theme_cache.increment_icon; + Ref<Texture2D> decr = theme_cache.decrement_icon; + Ref<StyleBox> bg = theme_cache.scroll_style; Size2 minsize; if (orientation == VERTICAL) { @@ -595,7 +613,7 @@ void ScrollBar::set_drag_node(const NodePath &p_path) { 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), CONNECT_ONESHOT); + drag_node->connect("tree_exiting", callable_mp(this, &ScrollBar::_drag_node_exit), CONNECT_ONE_SHOT); } } } diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h index 1823f86a67..13ca62d7ff 100644 --- a/scene/gui/scroll_bar.h +++ b/scene/gui/scroll_bar.h @@ -86,14 +86,31 @@ class ScrollBar : public Range { double target_scroll = 0.0; bool smooth_scroll_enabled = false; + struct ThemeCache { + Ref<StyleBox> scroll_style; + Ref<StyleBox> scroll_focus_style; + Ref<StyleBox> scroll_offset_style; + Ref<StyleBox> grabber_style; + Ref<StyleBox> grabber_hl_style; + Ref<StyleBox> grabber_pressed_style; + + Ref<Texture2D> increment_icon; + Ref<Texture2D> increment_hl_icon; + Ref<Texture2D> increment_pressed_icon; + Ref<Texture2D> decrement_icon; + Ref<Texture2D> decrement_hl_icon; + Ref<Texture2D> decrement_pressed_icon; + } theme_cache; + void _drag_node_exit(); void _drag_node_input(const Ref<InputEvent> &p_input); virtual void gui_input(const Ref<InputEvent> &p_event) override; protected: - void _notification(int p_what); + virtual void _update_theme_item_cache() override; + void _notification(int p_what); static void _bind_methods(); public: diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 8fd547813d..c12ac115b7 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -35,7 +35,6 @@ #include "scene/main/window.h" Size2 ScrollContainer::get_minimum_size() const { - Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); Size2 min_size; // Calculated in this function, as it needs to traverse all child controls once to calculate; @@ -77,10 +76,16 @@ Size2 ScrollContainer::get_minimum_size() const { min_size.x += v_scroll->get_minimum_size().x; } - min_size += sb->get_minimum_size(); + min_size += theme_cache.panel_style->get_minimum_size(); return min_size; } +void ScrollContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); +} + void ScrollContainer::_cancel_drag() { set_physics_process_internal(false); drag_touching_deaccel = false; @@ -271,9 +276,8 @@ void ScrollContainer::_reposition_children() { Size2 size = get_size(); Point2 ofs; - Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); - size -= sb->get_minimum_size(); - ofs += sb->get_offset(); + size -= theme_cache.panel_style->get_minimum_size(); + ofs += theme_cache.panel_style->get_offset(); bool rtl = is_layout_rtl(); if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons @@ -312,7 +316,7 @@ void ScrollContainer::_reposition_children() { fit_child_in_rect(c, r); } - update(); + queue_redraw(); } void ScrollContainer::_notification(int p_what) { @@ -337,8 +341,7 @@ void ScrollContainer::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); - draw_style_box(sb, Rect2(Vector2(), get_size())); + draw_style_box(theme_cache.panel_style, Rect2(Vector2(), get_size())); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -413,8 +416,7 @@ void ScrollContainer::_notification(int p_what) { void ScrollContainer::update_scrollbars() { Size2 size = get_size(); - Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg")); - size -= sb->get_minimum_size(); + size -= theme_cache.panel_style->get_minimum_size(); Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index bfa74cfd0f..f4899846f4 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -69,9 +69,14 @@ private: int deadzone = 0; bool follow_focus = false; + struct ThemeCache { + Ref<StyleBox> panel_style; + } theme_cache; + void _cancel_drag(); protected: + virtual void _update_theme_item_cache() override; Size2 get_minimum_size() const override; void _gui_focus_changed(Control *p_control); diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp index e3400d9c8f..8177c1e469 100644 --- a/scene/gui/separator.cpp +++ b/scene/gui/separator.cpp @@ -33,24 +33,30 @@ Size2 Separator::get_minimum_size() const { Size2 ms(3, 3); if (orientation == VERTICAL) { - ms.x = get_theme_constant(SNAME("separation")); + ms.x = theme_cache.separation; } else { // HORIZONTAL - ms.y = get_theme_constant(SNAME("separation")); + ms.y = theme_cache.separation; } return ms; } +void Separator::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.separation = get_theme_constant(SNAME("separation")); + theme_cache.separator_style = get_theme_stylebox(SNAME("separator")); +} + void Separator::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { Size2i size = get_size(); - Ref<StyleBox> style = get_theme_stylebox(SNAME("separator")); - Size2i ssize = style->get_minimum_size() + style->get_center_size(); + Size2i ssize = theme_cache.separator_style->get_minimum_size() + theme_cache.separator_style->get_center_size(); if (orientation == VERTICAL) { - style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y)); + theme_cache.separator_style->draw(get_canvas_item(), Rect2((size.x - ssize.x) / 2, 0, ssize.x, size.y)); } else { - style->draw(get_canvas_item(), Rect2(0, (size.y - ssize.y) / 2, size.x, ssize.y)); + theme_cache.separator_style->draw(get_canvas_item(), Rect2(0, (size.y - ssize.y) / 2, size.x, ssize.y)); } } break; } diff --git a/scene/gui/separator.h b/scene/gui/separator.h index e6578a4d04..44e18a3f00 100644 --- a/scene/gui/separator.h +++ b/scene/gui/separator.h @@ -35,8 +35,16 @@ class Separator : public Control { GDCLASS(Separator, Control); + struct ThemeCache { + int separation = 0; + Ref<StyleBox> separator_style; + } theme_cache; + protected: Orientation orientation = Orientation::HORIZONTAL; + + virtual void _update_theme_item_cache() override; + void _notification(int p_what); public: diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 2695ad1f14..ff3adfb9ac 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -33,11 +33,8 @@ #include "core/os/keyboard.h" Size2 Slider::get_minimum_size() const { - Ref<StyleBox> style = get_theme_stylebox(SNAME("slider")); - Size2i ss = style->get_minimum_size() + style->get_center_size(); - - Ref<Texture2D> grabber = get_theme_icon(SNAME("grabber")); - Size2i rs = grabber->get_size(); + Size2i ss = theme_cache.slider_style->get_minimum_size() + theme_cache.slider_style->get_center_size(); + Size2i rs = theme_cache.grabber_icon->get_size(); if (orientation == HORIZONTAL) { return Size2i(ss.width, MAX(ss.height, rs.height)); @@ -58,7 +55,13 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid()) { if (mb->get_button_index() == MouseButton::LEFT) { if (mb->is_pressed()) { - Ref<Texture2D> grabber = get_theme_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber"); + Ref<Texture2D> grabber; + if (mouse_inside || has_focus()) { + grabber = theme_cache.grabber_hl_icon; + } else { + grabber = theme_cache.grabber_icon; + } + grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x; double grab_width = (double)grabber->get_size().width; @@ -95,7 +98,7 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) { if (mm.is_valid()) { if (grab.active) { Size2i size = get_size(); - Ref<Texture2D> grabber = get_theme_icon(SNAME("grabber")); + Ref<Texture2D> grabber = theme_cache.grabber_icon; double motion = (orientation == VERTICAL ? mm->get_position().y : mm->get_position().x) - grab.pos; if (orientation == VERTICAL) { motion = -motion; @@ -145,21 +148,34 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) { } } +void Slider::_update_theme_item_cache() { + Range::_update_theme_item_cache(); + + theme_cache.slider_style = get_theme_stylebox(SNAME("slider")); + theme_cache.grabber_area_style = get_theme_stylebox(SNAME("grabber_area")); + theme_cache.grabber_area_hl_style = get_theme_stylebox(SNAME("grabber_area_highlight")); + + theme_cache.grabber_icon = get_theme_icon(SNAME("grabber")); + theme_cache.grabber_hl_icon = get_theme_icon(SNAME("grabber_highlight")); + theme_cache.grabber_disabled_icon = get_theme_icon(SNAME("grabber_disabled")); + theme_cache.tick_icon = get_theme_icon(SNAME("tick")); +} + void Slider::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { update_minimum_size(); - update(); + queue_redraw(); } break; case NOTIFICATION_MOUSE_ENTER: { mouse_inside = true; - update(); + queue_redraw(); } break; case NOTIFICATION_MOUSE_EXIT: { mouse_inside = false; - update(); + queue_redraw(); } break; case NOTIFICATION_VISIBILITY_CHANGED: @@ -171,13 +187,30 @@ void Slider::_notification(int p_what) { case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); Size2i size = get_size(); - Ref<StyleBox> style = get_theme_stylebox(SNAME("slider")); - bool highlighted = mouse_inside || has_focus(); - Ref<StyleBox> grabber_area = get_theme_stylebox(highlighted ? "grabber_area_highlight" : "grabber_area"); - Ref<Texture2D> grabber = get_theme_icon(editable ? (highlighted ? "grabber_highlight" : "grabber") : "grabber_disabled"); - Ref<Texture2D> tick = get_theme_icon(SNAME("tick")); double ratio = Math::is_nan(get_as_ratio()) ? 0 : get_as_ratio(); + Ref<StyleBox> style = theme_cache.slider_style; + Ref<Texture2D> tick = theme_cache.tick_icon; + + bool highlighted = mouse_inside || has_focus(); + Ref<Texture2D> grabber; + if (editable) { + if (highlighted) { + grabber = theme_cache.grabber_hl_icon; + } else { + grabber = theme_cache.grabber_icon; + } + } else { + grabber = theme_cache.grabber_disabled_icon; + } + + Ref<StyleBox> grabber_area; + if (highlighted) { + grabber_area = theme_cache.grabber_area_hl_style; + } else { + grabber_area = theme_cache.grabber_area_style; + } + if (orientation == VERTICAL) { int widget_width = style->get_minimum_size().width + style->get_center_size().width; double areasize = size.height - grabber->get_size().height; @@ -232,7 +265,7 @@ void Slider::set_ticks(int p_count) { } ticks = p_count; - update(); + queue_redraw(); } int Slider::get_ticks() const { @@ -249,7 +282,7 @@ void Slider::set_ticks_on_borders(bool _tob) { } ticks_on_borders = _tob; - update(); + queue_redraw(); } void Slider::set_editable(bool p_editable) { @@ -258,7 +291,7 @@ void Slider::set_editable(bool p_editable) { } editable = p_editable; - update(); + queue_redraw(); } bool Slider::is_editable() const { diff --git a/scene/gui/slider.h b/scene/gui/slider.h index 5abaee27aa..51adb354fb 100644 --- a/scene/gui/slider.h +++ b/scene/gui/slider.h @@ -49,11 +49,24 @@ class Slider : public Range { bool editable = true; bool scrollable = true; + struct ThemeCache { + Ref<StyleBox> slider_style; + Ref<StyleBox> grabber_area_style; + Ref<StyleBox> grabber_area_hl_style; + + Ref<Texture2D> grabber_icon; + Ref<Texture2D> grabber_hl_icon; + Ref<Texture2D> grabber_disabled_icon; + Ref<Texture2D> tick_icon; + } theme_cache; + protected: + bool ticks_on_borders = false; + virtual void gui_input(const Ref<InputEvent> &p_event) override; + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); - bool ticks_on_borders = false; public: virtual Size2 get_minimum_size() const override; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 65c4a09c84..fe14049d93 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -210,25 +210,29 @@ inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) { } } +void SpinBox::_update_theme_item_cache() { + Range::_update_theme_item_cache(); + + theme_cache.updown_icon = get_theme_icon(SNAME("updown")); +} + void SpinBox::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { - Ref<Texture2D> updown = get_theme_icon(SNAME("updown")); - - _adjust_width_for_icon(updown); + _adjust_width_for_icon(theme_cache.updown_icon); RID ci = get_canvas_item(); Size2i size = get_size(); if (is_layout_rtl()) { - updown->draw(ci, Point2i(0, (size.height - updown->get_height()) / 2)); + theme_cache.updown_icon->draw(ci, Point2i(0, (size.height - theme_cache.updown_icon->get_height()) / 2)); } else { - updown->draw(ci, Point2i(size.width - updown->get_width(), (size.height - updown->get_height()) / 2)); + theme_cache.updown_icon->draw(ci, Point2i(size.width - theme_cache.updown_icon->get_width(), (size.height - theme_cache.updown_icon->get_height()) / 2)); } } break; case NOTIFICATION_ENTER_TREE: { - _adjust_width_for_icon(get_theme_icon(SNAME("updown"))); + _adjust_width_for_icon(theme_cache.updown_icon); _value_changed(0); } break; @@ -238,7 +242,7 @@ void SpinBox::_notification(int p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { _value_changed(0); - update(); + queue_redraw(); } break; case NOTIFICATION_THEME_CHANGED: { @@ -247,7 +251,7 @@ void SpinBox::_notification(int p_what) { } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - update(); + queue_redraw(); } break; } } diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 3fcb85ac99..c2f2ac3f5a 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -69,9 +69,14 @@ class SpinBox : public Range { inline void _adjust_width_for_icon(const Ref<Texture2D> &icon); + struct ThemeCache { + Ref<Texture2D> updown_icon; + } theme_cache; + protected: virtual void gui_input(const Ref<InputEvent> &p_event) override; + virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 3e60db0846..2ca1d6239e 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -33,11 +33,99 @@ #include "label.h" #include "margin_container.h" +void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) { + ERR_FAIL_COND(p_event.is_null()); + + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + + if (sc->collapsed || !sc->_getch(0) || !sc->_getch(1) || sc->dragger_visibility != SplitContainer::DRAGGER_VISIBLE) { + return; + } + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid()) { + if (mb->get_button_index() == MouseButton::LEFT) { + if (mb->is_pressed()) { + sc->_compute_middle_sep(true); + dragging = true; + drag_ofs = sc->split_offset; + if (sc->vertical) { + drag_from = get_transform().xform(mb->get_position()).y; + } else { + drag_from = get_transform().xform(mb->get_position()).x; + } + } else { + dragging = false; + queue_redraw(); + } + } + } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid()) { + if (!dragging) { + return; + } + + Vector2i in_parent_pos = get_transform().xform(mm->get_position()); + if (!sc->vertical && is_layout_rtl()) { + sc->split_offset = drag_ofs - ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from); + } else { + sc->split_offset = drag_ofs + ((sc->vertical ? in_parent_pos.y : in_parent_pos.x) - drag_from); + } + sc->_compute_middle_sep(true); + sc->queue_sort(); + sc->emit_signal(SNAME("dragged"), sc->get_split_offset()); + } +} + +Control::CursorShape SplitContainerDragger::get_cursor_shape(const Point2 &p_pos) const { + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + + if (!sc->collapsed && sc->dragger_visibility == SplitContainer::DRAGGER_VISIBLE) { + return (sc->vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT); + } + + return Control::get_cursor_shape(p_pos); +} + +void SplitContainerDragger::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_MOUSE_ENTER: { + mouse_inside = true; + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + if (sc->get_theme_constant(SNAME("autohide"))) { + queue_redraw(); + } + } break; + + case NOTIFICATION_MOUSE_EXIT: { + mouse_inside = false; + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + if (sc->get_theme_constant(SNAME("autohide"))) { + queue_redraw(); + } + } break; + + case NOTIFICATION_DRAW: { + SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent()); + if (!dragging && !mouse_inside && sc->get_theme_constant(SNAME("autohide"))) { + return; + } + + Ref<Texture2D> tex = sc->get_theme_icon(SNAME("grabber")); + draw_texture(tex, (get_size() - tex->get_size()) / 2); + } break; + } +} + Control *SplitContainer::_getch(int p_idx) const { int idx = 0; - for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to<Control>(get_child(i)); + for (int i = 0; i < get_child_count(false); i++) { + Control *c = Object::cast_to<Control>(get_child(i, false)); if (!c || !c->is_visible()) { continue; } @@ -55,58 +143,84 @@ Control *SplitContainer::_getch(int p_idx) const { return nullptr; } -void SplitContainer::_resort() { - int axis = vertical ? 1 : 0; +Ref<Texture2D> SplitContainer::_get_grabber_icon() const { + if (is_fixed) { + return theme_cache.grabber_icon; + } else { + if (vertical) { + return theme_cache.grabber_icon_v; + } else { + return theme_cache.grabber_icon_h; + } + } +} +void SplitContainer::_compute_middle_sep(bool p_clamp) { Control *first = _getch(0); Control *second = _getch(1); - // If we have only one element - if (!first || !second) { - if (first) { - fit_child_in_rect(first, Rect2(Point2(), get_size())); - } else if (second) { - fit_child_in_rect(second, Rect2(Point2(), get_size())); - } - return; - } - - // Determine expanded children + // Determine expanded children. bool first_expanded = (vertical ? first->get_v_size_flags() : first->get_h_size_flags()) & SIZE_EXPAND; bool second_expanded = (vertical ? second->get_v_size_flags() : second->get_h_size_flags()) & SIZE_EXPAND; - // Determine the separation between items - Ref<Texture2D> g = get_theme_icon(SNAME("grabber")); - int sep = get_theme_constant(SNAME("separation")); - sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0; + // Compute the minimum size. + int axis = vertical ? 1 : 0; + int size = get_size()[axis]; + int ms_first = first->get_combined_minimum_size()[axis]; + int ms_second = second->get_combined_minimum_size()[axis]; - // Compute the minimum size - Size2 ms_first = first->get_combined_minimum_size(); - Size2 ms_second = second->get_combined_minimum_size(); + // Determine the separation between items. + Ref<Texture2D> g = _get_grabber_icon(); + int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0; - // Compute the separator position without the split offset - float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio()); - int no_offset_middle_sep = 0; + // Compute the wished separation_point. + int wished_middle_sep = 0; + int split_offset_with_collapse = 0; + if (!collapsed) { + split_offset_with_collapse = split_offset; + } if (first_expanded && second_expanded) { - no_offset_middle_sep = get_size()[axis] * ratio - sep / 2; + float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio()); + wished_middle_sep = size * ratio - sep / 2 + split_offset_with_collapse; } else if (first_expanded) { - no_offset_middle_sep = get_size()[axis] - ms_second[axis] - sep; + wished_middle_sep = size - sep + split_offset_with_collapse; } else { - no_offset_middle_sep = ms_first[axis]; + wished_middle_sep = split_offset_with_collapse; } - // Compute the final middle separation. - middle_sep = no_offset_middle_sep; - if (!collapsed) { - int clamped_split_offset = CLAMP(split_offset, ms_first[axis] - no_offset_middle_sep, (get_size()[axis] - ms_second[axis] - sep) - no_offset_middle_sep); - middle_sep += clamped_split_offset; - if (should_clamp_split_offset) { - split_offset = clamped_split_offset; + // Clamp the middle sep to acceptatble values. + middle_sep = CLAMP(wished_middle_sep, ms_first, size - sep - ms_second); - should_clamp_split_offset = false; + // Clamp the split_offset if requested. + if (p_clamp) { + split_offset -= wished_middle_sep - middle_sep; + p_clamp = false; + } +} + +void SplitContainer::_resort() { + Control *first = _getch(0); + Control *second = _getch(1); + + // If we have only one element. + if (!first || !second) { + if (first) { + fit_child_in_rect(first, Rect2(Point2(), get_size())); + } else if (second) { + fit_child_in_rect(second, Rect2(Point2(), get_size())); } + dragging_area_control->hide(); + return; } + // If we have more that one. + _compute_middle_sep(false); + + // Determine the separation between items. + Ref<Texture2D> g = _get_grabber_icon(); + int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0; + + // Move the children, including the dragger. if (vertical) { fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep))); int sofs = middle_sep + sep; @@ -124,16 +238,27 @@ void SplitContainer::_resort() { } } - update(); + // Handle the dragger visibility and position. + if (dragger_visibility == DRAGGER_VISIBLE && !collapsed) { + dragging_area_control->show(); + + int dragger_ctrl_size = MAX(sep, theme_cache.minimum_grab_thickness); + if (vertical) { + dragging_area_control->set_rect(Rect2(Point2(0, middle_sep - (dragger_ctrl_size - sep) / 2), Size2(get_size().width, dragger_ctrl_size))); + } else { + dragging_area_control->set_rect(Rect2(Point2(middle_sep - (dragger_ctrl_size - sep) / 2, 0), Size2(dragger_ctrl_size, get_size().height))); + } + + dragging_area_control->queue_redraw(); + } else { + dragging_area_control->hide(); + } } Size2 SplitContainer::get_minimum_size() const { - /* Calculate MINIMUM SIZE */ - Size2i minimum; - Ref<Texture2D> g = get_theme_icon(SNAME("grabber")); - int sep = get_theme_constant(SNAME("separation")); - sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(sep, vertical ? g->get_height() : g->get_width()) : 0; + Ref<Texture2D> g = _get_grabber_icon(); + int sep = (dragger_visibility != DRAGGER_HIDDEN_COLLAPSED) ? MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width()) : 0; for (int i = 0; i < 2; i++) { if (!_getch(i)) { @@ -162,6 +287,23 @@ Size2 SplitContainer::get_minimum_size() const { return minimum; } +void SplitContainer::_validate_property(PropertyInfo &p_property) const { + if (is_fixed && p_property.name == "vertical") { + p_property.usage = PROPERTY_USAGE_NONE; + } +} + +void SplitContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.separation = get_theme_constant(SNAME("separation")); + theme_cache.minimum_grab_thickness = get_theme_constant(SNAME("minimum_grab_thickness")); + theme_cache.autohide = get_theme_constant(SNAME("autohide")); + theme_cache.grabber_icon = get_theme_icon(SNAME("grabber")); + theme_cache.grabber_icon_h = get_theme_icon(SNAME("h_grabber")); + theme_cache.grabber_icon_v = get_theme_icon(SNAME("v_grabber")); +} + void SplitContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSLATION_CHANGED: @@ -173,130 +315,12 @@ void SplitContainer::_notification(int p_what) { _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; - } - - if (collapsed || (!dragging && !mouse_inside && get_theme_constant(SNAME("autohide")))) { - return; - } - - if (dragger_visibility != DRAGGER_VISIBLE) { - return; - } - - int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_theme_constant(SNAME("separation")) : 0; - Ref<Texture2D> tex = get_theme_icon(SNAME("grabber")); - Size2 size = get_size(); - - if (vertical) { - draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2)); - } else { - 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; } } -void SplitContainer::gui_input(const Ref<InputEvent> &p_event) { - ERR_FAIL_COND(p_event.is_null()); - - if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) { - return; - } - - Ref<InputEventMouseButton> mb = p_event; - - if (mb.is_valid()) { - if (mb->get_button_index() == MouseButton::LEFT) { - if (mb->is_pressed()) { - int sep = get_theme_constant(SNAME("separation")); - - if (vertical) { - if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + sep) { - dragging = true; - drag_from = mb->get_position().y; - drag_ofs = split_offset; - } - } else { - if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + sep) { - dragging = true; - drag_from = mb->get_position().x; - drag_ofs = split_offset; - } - } - } else { - dragging = false; - } - } - } - - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid()) { - bool mouse_inside_state = false; - if (vertical) { - mouse_inside_state = mm->get_position().y > middle_sep && mm->get_position().y < middle_sep + get_theme_constant(SNAME("separation")); - } else { - mouse_inside_state = mm->get_position().x > middle_sep && mm->get_position().x < middle_sep + get_theme_constant(SNAME("separation")); - } - - if (mouse_inside != mouse_inside_state) { - mouse_inside = mouse_inside_state; - if (get_theme_constant(SNAME("autohide"))) { - update(); - } - } - - if (!dragging) { - return; - } - - if (!vertical && is_layout_rtl()) { - split_offset = drag_ofs + (drag_from - (vertical ? mm->get_position().y : mm->get_position().x)); - } else { - split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); - } - should_clamp_split_offset = true; - queue_sort(); - emit_signal(SNAME("dragged"), get_split_offset()); - } -} - -Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const { - if (dragging) { - return (vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT); - } - - if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) { - int sep = get_theme_constant(SNAME("separation")); - - if (vertical) { - if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) { - return CURSOR_VSPLIT; - } - } else { - if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) { - return CURSOR_HSPLIT; - } - } - } - - return Control::get_cursor_shape(p_pos); -} - void SplitContainer::set_split_offset(int p_offset) { if (split_offset == p_offset) { return; @@ -312,8 +336,11 @@ int SplitContainer::get_split_offset() const { } void SplitContainer::clamp_split_offset() { - should_clamp_split_offset = true; + if (!_getch(0) || !_getch(1)) { + return; + } + _compute_middle_sep(true); queue_sort(); } @@ -333,7 +360,6 @@ void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) { dragger_visibility = p_visibility; queue_sort(); - update(); } SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const { @@ -344,6 +370,17 @@ bool SplitContainer::is_collapsed() const { return collapsed; } +void SplitContainer::set_vertical(bool p_vertical) { + ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + "."); + vertical = p_vertical; + update_minimum_size(); + _resort(); +} + +bool SplitContainer::is_vertical() const { + return vertical; +} + Vector<int> SplitContainer::get_allowed_size_flags_horizontal() const { Vector<int> flags; flags.append(SIZE_FILL); @@ -379,11 +416,15 @@ void SplitContainer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_dragger_visibility", "mode"), &SplitContainer::set_dragger_visibility); ClassDB::bind_method(D_METHOD("get_dragger_visibility"), &SplitContainer::get_dragger_visibility); + ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &SplitContainer::set_vertical); + ClassDB::bind_method(D_METHOD("is_vertical"), &SplitContainer::is_vertical); + ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::INT, "offset"))); ADD_PROPERTY(PropertyInfo(Variant::INT, "split_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_split_offset", "get_split_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed"); ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden and Collapsed"), "set_dragger_visibility", "get_dragger_visibility"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); BIND_ENUM_CONSTANT(DRAGGER_VISIBLE); BIND_ENUM_CONSTANT(DRAGGER_HIDDEN); @@ -392,4 +433,7 @@ void SplitContainer::_bind_methods() { SplitContainer::SplitContainer(bool p_vertical) { vertical = p_vertical; + + dragging_area_control = memnew(SplitContainerDragger); + add_child(dragging_area_control, false, Node::INTERNAL_MODE_BACK); } diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index a69ffe4de9..d297e3a3ea 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -33,8 +33,26 @@ #include "scene/gui/container.h" +class SplitContainerDragger : public Control { + GDCLASS(SplitContainerDragger, Control); + +protected: + void _notification(int p_what); + virtual void gui_input(const Ref<InputEvent> &p_event) override; + +private: + bool dragging = false; + int drag_from = 0; + int drag_ofs = 0; + bool mouse_inside = false; + +public: + virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; +}; + class SplitContainer : public Container { GDCLASS(SplitContainer, Container); + friend class SplitContainerDragger; public: enum DraggerVisibility { @@ -44,24 +62,38 @@ public: }; private: - bool should_clamp_split_offset = false; int split_offset = 0; int middle_sep = 0; bool vertical = false; - bool dragging = false; - int drag_from = 0; - int drag_ofs = 0; bool collapsed = false; DraggerVisibility dragger_visibility = DRAGGER_VISIBLE; - bool mouse_inside = false; + + SplitContainerDragger *dragging_area_control = nullptr; + + struct ThemeCache { + int separation = 0; + int minimum_grab_thickness = 0; + int autohide = 0; + Ref<Texture2D> grabber_icon; + Ref<Texture2D> grabber_icon_h; + Ref<Texture2D> grabber_icon_v; + } theme_cache; Control *_getch(int p_idx) const; + Ref<Texture2D> _get_grabber_icon() const; + void _compute_middle_sep(bool p_clamp); void _resort(); + void _dragging_area_gui_input(const Ref<InputEvent> &p_event); + protected: - virtual void gui_input(const Ref<InputEvent> &p_event) override; + bool is_fixed = false; + + virtual void _update_theme_item_cache() override; + void _notification(int p_what); + void _validate_property(PropertyInfo &p_property) const; static void _bind_methods(); public: @@ -75,7 +107,8 @@ public: void set_dragger_visibility(DraggerVisibility p_visibility); DraggerVisibility get_dragger_visibility() const; - virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; + void set_vertical(bool p_vertical); + bool is_vertical() const; virtual Size2 get_minimum_size() const override; @@ -92,7 +125,7 @@ class HSplitContainer : public SplitContainer { public: HSplitContainer() : - SplitContainer(false) {} + SplitContainer(false) { is_fixed = true; } }; class VSplitContainer : public SplitContainer { @@ -100,7 +133,7 @@ class VSplitContainer : public SplitContainer { public: VSplitContainer() : - SplitContainer(true) {} + SplitContainer(true) { is_fixed = true; } }; #endif // SPLIT_CONTAINER_H diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index 869683e427..88e68ec763 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -60,7 +60,7 @@ void SubViewportContainer::set_stretch(bool p_enable) { stretch = p_enable; update_minimum_size(); queue_sort(); - update(); + queue_redraw(); } bool SubViewportContainer::is_stretch_enabled() const { @@ -88,7 +88,7 @@ void SubViewportContainer::set_stretch_shrink(int p_shrink) { c->set_size(get_size() / shrink); } - update(); + queue_redraw(); } int SubViewportContainer::get_stretch_shrink() const { diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index e0739f909f..cf6681f809 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -44,14 +44,7 @@ Size2 TabBar::get_minimum_size() const { return ms; } - 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<StyleBox> button_highlight = get_theme_stylebox(SNAME("button_highlight")); - Ref<Texture2D> close = get_theme_icon(SNAME("close")); - int hseparation = get_theme_constant(SNAME("h_separation")); - - int y_margin = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height); + int y_margin = MAX(MAX(theme_cache.tab_unselected_style->get_minimum_size().height, theme_cache.tab_selected_style->get_minimum_size().height), theme_cache.tab_disabled_style->get_minimum_size().height); for (int i = 0; i < tabs.size(); i++) { if (tabs[i].hidden) { @@ -62,22 +55,22 @@ Size2 TabBar::get_minimum_size() const { Ref<StyleBox> style; if (tabs[i].disabled) { - style = tab_disabled; + style = theme_cache.tab_disabled_style; } else if (current == i) { - style = tab_selected; + style = theme_cache.tab_selected_style; } else { - style = tab_unselected; + style = theme_cache.tab_unselected_style; } ms.width += style->get_minimum_size().width; Ref<Texture2D> tex = tabs[i].icon; if (tex.is_valid()) { ms.height = MAX(ms.height, tex->get_size().height + y_margin); - ms.width += tex->get_size().width + hseparation; + ms.width += tex->get_size().width + theme_cache.h_separation; } if (!tabs[i].text.is_empty()) { - ms.width += tabs[i].size_text + hseparation; + ms.width += tabs[i].size_text + theme_cache.h_separation; } ms.height = MAX(ms.height, tabs[i].text_buf->get_size().y + y_margin); @@ -87,22 +80,22 @@ Size2 TabBar::get_minimum_size() const { Ref<Texture2D> rb = tabs[i].right_button; if (close_visible) { - ms.width += button_highlight->get_minimum_size().width + rb->get_width(); + ms.width += theme_cache.button_hl_style->get_minimum_size().width + rb->get_width(); } else { - ms.width += button_highlight->get_margin(SIDE_LEFT) + rb->get_width() + hseparation; + ms.width += theme_cache.button_hl_style->get_margin(SIDE_LEFT) + rb->get_width() + theme_cache.h_separation; } 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.width += theme_cache.button_hl_style->get_margin(SIDE_LEFT) + theme_cache.close_icon->get_width() + theme_cache.h_separation; - ms.height = MAX(ms.height, close->get_height() + y_margin); + ms.height = MAX(ms.height, theme_cache.close_icon->get_height() + y_margin); } if (ms.width - ofs > style->get_minimum_size().width) { - ms.width -= hseparation; + ms.width -= theme_cache.h_separation; } } @@ -122,46 +115,43 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { Point2 pos = mm->get_position(); if (buttons_visible) { - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - if (is_layout_rtl()) { - if (pos.x < decr->get_width()) { + if (pos.x < theme_cache.decrement_icon->get_width()) { if (highlight_arrow != 1) { highlight_arrow = 1; - update(); + queue_redraw(); } - } else if (pos.x < incr->get_width() + decr->get_width()) { + } else if (pos.x < theme_cache.increment_icon->get_width() + theme_cache.decrement_icon->get_width()) { if (highlight_arrow != 0) { highlight_arrow = 0; - update(); + queue_redraw(); } } else if (highlight_arrow != -1) { highlight_arrow = -1; - update(); + queue_redraw(); } } else { - int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); - if (pos.x > limit_minus_buttons + decr->get_width()) { + int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); + if (pos.x > limit_minus_buttons + theme_cache.decrement_icon->get_width()) { if (highlight_arrow != 1) { highlight_arrow = 1; - update(); + queue_redraw(); } } else if (pos.x > limit_minus_buttons) { if (highlight_arrow != 0) { highlight_arrow = 0; - update(); + queue_redraw(); } } else if (highlight_arrow != -1) { highlight_arrow = -1; - update(); + queue_redraw(); } } } if (get_viewport()->gui_is_dragging() && can_drop_data(pos, get_viewport()->gui_get_drag_data())) { dragging_valid_tab = true; - update(); + queue_redraw(); } _update_hover(); @@ -172,22 +162,22 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_pressed()) { + if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_or_control_pressed()) { if (scrolling_enabled && buttons_visible) { if (offset > 0) { offset--; _update_cache(); - update(); + queue_redraw(); } } } - if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_pressed()) { + if (mb->is_pressed() && mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_or_control_pressed()) { if (scrolling_enabled && buttons_visible) { if (missing_right && offset < tabs.size()) { offset++; _update_cache(); - update(); + queue_redraw(); } } } @@ -198,7 +188,7 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { } rb_pressing = false; - update(); + queue_redraw(); } if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { @@ -207,46 +197,43 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { } cb_pressing = false; - update(); + queue_redraw(); } if (mb->is_pressed() && (mb->get_button_index() == MouseButton::LEFT || (select_with_rmb && mb->get_button_index() == MouseButton::RIGHT))) { Point2 pos = mb->get_position(); if (buttons_visible) { - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - if (is_layout_rtl()) { - if (pos.x < decr->get_width()) { + if (pos.x < theme_cache.decrement_icon->get_width()) { if (missing_right) { offset++; _update_cache(); - update(); + queue_redraw(); } return; - } else if (pos.x < incr->get_width() + decr->get_width()) { + } else if (pos.x < theme_cache.increment_icon->get_width() + theme_cache.decrement_icon->get_width()) { if (offset > 0) { offset--; _update_cache(); - update(); + queue_redraw(); } return; } } else { - int limit = get_size().width - incr->get_width() - decr->get_width(); - if (pos.x > limit + decr->get_width()) { + int limit = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); + if (pos.x > limit + theme_cache.decrement_icon->get_width()) { if (missing_right) { offset++; _update_cache(); - update(); + queue_redraw(); } return; } else if (pos.x > limit) { if (offset > 0) { offset--; _update_cache(); - update(); + queue_redraw(); } return; } @@ -266,13 +253,13 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { if (tabs[i].rb_rect.has_point(pos)) { rb_pressing = true; - update(); + queue_redraw(); return; } if (tabs[i].cb_rect.has_point(pos) && (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current))) { cb_pressing = true; - update(); + queue_redraw(); return; } @@ -299,9 +286,6 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) { } void TabBar::_shape(int p_tab) { - Ref<Font> font = get_theme_font(SNAME("font")); - int font_size = get_theme_font_size(SNAME("font_size")); - tabs.write[p_tab].xl_text = atr(tabs[p_tab].text); tabs.write[p_tab].text_buf->clear(); tabs.write[p_tab].text_buf->set_width(-1); @@ -311,13 +295,43 @@ void TabBar::_shape(int p_tab) { tabs.write[p_tab].text_buf->set_direction((TextServer::Direction)tabs[p_tab].text_direction); } - tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, font, font_size, tabs[p_tab].language); + tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, theme_cache.font, theme_cache.font_size, tabs[p_tab].language); +} + +void TabBar::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.h_separation = get_theme_constant(SNAME("h_separation")); + + theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected")); + theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected")); + theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled")); + + theme_cache.increment_icon = get_theme_icon(SNAME("increment")); + theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight")); + theme_cache.decrement_icon = get_theme_icon(SNAME("decrement")); + theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight")); + theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark")); + theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.outline_size = get_theme_constant(SNAME("outline_size")); + + theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color")); + theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color")); + theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + + theme_cache.close_icon = get_theme_icon(SNAME("close")); + theme_cache.button_pressed_style = get_theme_stylebox(SNAME("button_pressed")); + theme_cache.button_hl_style = get_theme_stylebox(SNAME("button_highlight")); } void TabBar::_notification(int p_what) { switch (p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { - update(); + queue_redraw(); } break; case NOTIFICATION_THEME_CHANGED: @@ -343,7 +357,7 @@ void TabBar::_notification(int p_what) { case NOTIFICATION_DRAG_END: { if (dragging_valid_tab) { dragging_valid_tab = false; - update(); + queue_redraw(); } } break; @@ -352,18 +366,9 @@ void TabBar::_notification(int p_what) { return; } - 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")); - 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")); - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - bool rtl = is_layout_rtl(); Vector2 size = get_size(); - int limit_minus_buttons = size.width - incr->get_width() - decr->get_width(); + int limit_minus_buttons = size.width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); int ofs = tabs[offset].ofs_cache; @@ -378,14 +383,14 @@ void TabBar::_notification(int p_what) { Color col; if (tabs[i].disabled) { - sb = tab_disabled; - col = font_disabled_color; + sb = theme_cache.tab_disabled_style; + col = theme_cache.font_disabled_color; } else if (i == current) { - sb = tab_selected; - col = font_selected_color; + sb = theme_cache.tab_selected_style; + col = theme_cache.font_selected_color; } else { - sb = tab_unselected; - col = font_unselected_color; + sb = theme_cache.tab_unselected_style; + col = theme_cache.font_unselected_color; } _draw_tab(sb, col, i, rtl ? size.width - ofs - tabs[i].size_cache : ofs); @@ -396,41 +401,38 @@ void TabBar::_notification(int p_what) { // Draw selected tab in the front, but only if it's visible. if (current >= offset && current <= max_drawn_tab && !tabs[current].hidden) { - Ref<StyleBox> sb = tabs[current].disabled ? tab_disabled : tab_selected; + Ref<StyleBox> sb = tabs[current].disabled ? theme_cache.tab_disabled_style : theme_cache.tab_selected_style; float x = rtl ? size.width - tabs[current].ofs_cache - tabs[current].size_cache : tabs[current].ofs_cache; - _draw_tab(sb, font_selected_color, current, x); + _draw_tab(sb, theme_cache.font_selected_color, current, x); } if (buttons_visible) { - Ref<Texture2D> incr_hl = get_theme_icon(SNAME("increment_highlight")); - Ref<Texture2D> decr_hl = get_theme_icon(SNAME("decrement_highlight")); - - int vofs = (size.height - incr->get_size().height) / 2; + int vofs = (size.height - theme_cache.increment_icon->get_size().height) / 2; if (rtl) { if (missing_right) { - draw_texture(highlight_arrow == 1 ? decr_hl : decr, Point2(0, vofs)); + draw_texture(highlight_arrow == 1 ? theme_cache.decrement_hl_icon : theme_cache.decrement_icon, Point2(0, vofs)); } else { - draw_texture(decr, Point2(0, vofs), Color(1, 1, 1, 0.5)); + draw_texture(theme_cache.decrement_icon, Point2(0, vofs), Color(1, 1, 1, 0.5)); } if (offset > 0) { - draw_texture(highlight_arrow == 0 ? incr_hl : incr, Point2(incr->get_size().width, vofs)); + draw_texture(highlight_arrow == 0 ? theme_cache.increment_hl_icon : theme_cache.increment_icon, Point2(theme_cache.increment_icon->get_size().width, vofs)); } else { - draw_texture(incr, Point2(incr->get_size().width, vofs), Color(1, 1, 1, 0.5)); + draw_texture(theme_cache.increment_icon, Point2(theme_cache.increment_icon->get_size().width, vofs), Color(1, 1, 1, 0.5)); } } else { if (offset > 0) { - draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit_minus_buttons, vofs)); + draw_texture(highlight_arrow == 0 ? theme_cache.decrement_hl_icon : theme_cache.decrement_icon, Point2(limit_minus_buttons, vofs)); } else { - draw_texture(decr, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5)); + draw_texture(theme_cache.decrement_icon, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5)); } if (missing_right) { - draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit_minus_buttons + decr->get_size().width, vofs)); + draw_texture(highlight_arrow == 1 ? theme_cache.increment_hl_icon : theme_cache.increment_icon, Point2(limit_minus_buttons + theme_cache.decrement_icon->get_size().width, vofs)); } else { - draw_texture(incr, Point2(limit_minus_buttons + decr->get_size().width, vofs), Color(1, 1, 1, 0.5)); + draw_texture(theme_cache.increment_icon, Point2(limit_minus_buttons + theme_cache.decrement_icon->get_size().width, vofs), Color(1, 1, 1, 0.5)); } } } @@ -462,10 +464,7 @@ void TabBar::_notification(int p_what) { } } - Ref<Texture2D> drop_mark = get_theme_icon(SNAME("drop_mark")); - Color drop_mark_color = get_theme_color(SNAME("drop_mark_color")); - - drop_mark->draw(get_canvas_item(), Point2(x - drop_mark->get_width() / 2, (size.height - drop_mark->get_height()) / 2), drop_mark_color); + theme_cache.drop_mark_icon->draw(get_canvas_item(), Point2(x - theme_cache.drop_mark_icon->get_width() / 2, (size.height - theme_cache.drop_mark_icon->get_height()) / 2), theme_cache.drop_mark_color); } } break; } @@ -475,10 +474,6 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in RID ci = get_canvas_item(); bool rtl = is_layout_rtl(); - 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("h_separation")); - Rect2 sb_rect = Rect2(p_x, 0, tabs[p_index].size_cache, get_size().height); p_tab_style->draw(ci, sb_rect); @@ -491,7 +486,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in if (icon.is_valid()) { icon->draw(ci, Point2i(rtl ? p_x - icon->get_width() : p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); - p_x = rtl ? p_x - icon->get_width() - hseparation : p_x + icon->get_width() + hseparation; + p_x = rtl ? p_x - icon->get_width() - theme_cache.h_separation : p_x + icon->get_width() + theme_cache.h_separation; } // Draw the text. @@ -499,17 +494,17 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in Point2i text_pos = Point2i(rtl ? p_x - tabs[p_index].size_text : p_x, p_tab_style->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[p_index].text_buf->get_size().y) / 2); - if (outline_size > 0 && font_outline_color.a > 0) { - tabs[p_index].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + if (theme_cache.outline_size > 0 && theme_cache.font_outline_color.a > 0) { + tabs[p_index].text_buf->draw_outline(ci, text_pos, theme_cache.outline_size, theme_cache.font_outline_color); } tabs[p_index].text_buf->draw(ci, text_pos, p_font_color); - p_x = rtl ? p_x - tabs[p_index].size_text - hseparation : p_x + tabs[p_index].size_text + hseparation; + p_x = rtl ? p_x - tabs[p_index].size_text - theme_cache.h_separation : p_x + tabs[p_index].size_text + theme_cache.h_separation; } // Draw and calculate rect of the right button. if (tabs[p_index].right_button.is_valid()) { - Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight")); + Ref<StyleBox> style = theme_cache.button_hl_style; Ref<Texture2D> rb = tabs[p_index].right_button; Rect2 rb_rect; @@ -521,7 +516,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in if (rb_hover == p_index) { if (rb_pressing) { - get_theme_stylebox(SNAME("button_pressed"))->draw(ci, rb_rect); + theme_cache.button_pressed_style->draw(ci, rb_rect); } else { style->draw(ci, rb_rect); } @@ -534,8 +529,8 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in // Draw and calculate rect of the close button. if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_index == current)) { - Ref<StyleBox> style = get_theme_stylebox(SNAME("button_highlight")); - Ref<Texture2D> cb = get_theme_icon(SNAME("close")); + Ref<StyleBox> style = theme_cache.button_hl_style; + Ref<Texture2D> cb = theme_cache.close_icon; Rect2 cb_rect; cb_rect.size = style->get_minimum_size() + cb->get_size(); @@ -546,7 +541,7 @@ void TabBar::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_in if (!tabs[p_index].disabled && cb_hover == p_index) { if (cb_pressing) { - get_theme_stylebox(SNAME("button_pressed"))->draw(ci, cb_rect); + theme_cache.button_pressed_style->draw(ci, cb_rect); } else { style->draw(ci, cb_rect); } @@ -581,7 +576,7 @@ void TabBar::set_tab_count(int p_count) { } } - update(); + queue_redraw(); update_minimum_size(); notify_property_list_changed(); } @@ -607,7 +602,7 @@ void TabBar::set_current_tab(int p_current) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); emit_signal(SNAME("tab_changed"), p_current); } @@ -647,7 +642,7 @@ void TabBar::set_tab_title(int p_tab, const String &p_title) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } @@ -663,7 +658,7 @@ void TabBar::set_tab_text_direction(int p_tab, Control::TextDirection p_text_dir if (tabs[p_tab].text_direction != p_text_direction) { tabs.write[p_tab].text_direction = p_text_direction; _shape(p_tab); - update(); + queue_redraw(); } } @@ -683,7 +678,7 @@ void TabBar::set_tab_language(int p_tab, const String &p_language) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } } @@ -707,7 +702,7 @@ void TabBar::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } @@ -730,7 +725,7 @@ void TabBar::set_tab_disabled(int p_tab, bool p_disabled) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } @@ -753,7 +748,7 @@ void TabBar::set_tab_hidden(int p_tab, bool p_hidden) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } @@ -776,7 +771,7 @@ void TabBar::set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } @@ -817,7 +812,7 @@ void TabBar::_update_hover() { } if (hover_buttons != -1) { - update(); + queue_redraw(); break; } } @@ -838,7 +833,7 @@ void TabBar::_update_hover() { cb_hover = hover_buttons; if (rb_hover != rb_hover_old || cb_hover != cb_hover_old) { - update(); + queue_redraw(); } } } @@ -849,14 +844,8 @@ void TabBar::_update_cache() { return; } - Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled")); - Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected")); - Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected")); - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - int limit = get_size().width; - int limit_minus_buttons = limit - incr->get_width() - decr->get_width(); + int limit_minus_buttons = limit - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); int w = 0; @@ -940,7 +929,7 @@ void TabBar::_on_mouse_exited() { highlight_arrow = -1; dragging_valid_tab = false; - update(); + queue_redraw(); } void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { @@ -955,7 +944,7 @@ void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); if (tabs.size() == 1 && is_inside_tree()) { @@ -974,7 +963,7 @@ void TabBar::clear_tabs() { current = 0; previous = 0; - update(); + queue_redraw(); update_minimum_size(); notify_property_list_changed(); } @@ -1004,7 +993,7 @@ void TabBar::remove_tab(int p_idx) { } } - update(); + queue_redraw(); update_minimum_size(); notify_property_list_changed(); @@ -1152,7 +1141,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) { set_current_tab(hover_now); } else { _update_cache(); - update(); + queue_redraw(); } update_minimum_size(); @@ -1188,7 +1177,7 @@ void TabBar::set_tab_alignment(AlignmentMode p_alignment) { tab_alignment = p_alignment; _update_cache(); - update(); + queue_redraw(); } TabBar::AlignmentMode TabBar::get_tab_alignment() const { @@ -1210,7 +1199,7 @@ void TabBar::set_clip_tabs(bool p_clip_tabs) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } @@ -1251,59 +1240,54 @@ void TabBar::move_tab(int p_from, int p_to) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); notify_property_list_changed(); } int TabBar::get_tab_width(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, tabs.size(), 0); - 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 hseparation = get_theme_constant(SNAME("h_separation")); - Ref<StyleBox> style; if (tabs[p_idx].disabled) { - style = tab_disabled; + style = theme_cache.tab_disabled_style; } else if (current == p_idx) { - style = tab_selected; + style = theme_cache.tab_selected_style; } else { - style = tab_unselected; + style = theme_cache.tab_unselected_style; } int x = style->get_minimum_size().width; Ref<Texture2D> tex = tabs[p_idx].icon; if (tex.is_valid()) { - x += tex->get_width() + hseparation; + x += tex->get_width() + theme_cache.h_separation; } if (!tabs[p_idx].text.is_empty()) { - x += tabs[p_idx].size_text + hseparation; + x += tabs[p_idx].size_text + theme_cache.h_separation; } bool close_visible = cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx == current); if (tabs[p_idx].right_button.is_valid()) { - Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight")); + Ref<StyleBox> btn_style = theme_cache.button_hl_style; Ref<Texture2D> rb = tabs[p_idx].right_button; if (close_visible) { x += btn_style->get_minimum_size().width + rb->get_width(); } else { - x += btn_style->get_margin(SIDE_LEFT) + rb->get_width() + hseparation; + x += btn_style->get_margin(SIDE_LEFT) + rb->get_width() + theme_cache.h_separation; } } if (close_visible) { - Ref<StyleBox> btn_style = get_theme_stylebox(SNAME("button_highlight")); - Ref<Texture2D> cb = get_theme_icon(SNAME("close")); - x += btn_style->get_margin(SIDE_LEFT) + cb->get_width() + hseparation; + Ref<StyleBox> btn_style = theme_cache.button_hl_style; + Ref<Texture2D> cb = theme_cache.close_icon; + x += btn_style->get_margin(SIDE_LEFT) + cb->get_width() + theme_cache.h_separation; } if (x > style->get_minimum_size().width) { - x -= hseparation; + x -= theme_cache.h_separation; } return x; @@ -1314,9 +1298,7 @@ void TabBar::_ensure_no_over_offset() { return; } - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); + int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); int prev_offset = offset; @@ -1337,7 +1319,7 @@ void TabBar::_ensure_no_over_offset() { if (prev_offset != offset) { _update_cache(); - update(); + queue_redraw(); } } @@ -1354,14 +1336,12 @@ void TabBar::ensure_tab_visible(int p_idx) { if (p_idx < offset) { offset = p_idx; _update_cache(); - update(); + queue_redraw(); return; } - Ref<Texture2D> incr = get_theme_icon(SNAME("increment")); - Ref<Texture2D> decr = get_theme_icon(SNAME("decrement")); - int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); + int limit_minus_buttons = get_size().width - theme_cache.increment_icon->get_width() - theme_cache.decrement_icon->get_width(); int total_w = tabs[max_drawn_tab].ofs_cache - tabs[offset].ofs_cache; for (int i = max_drawn_tab; i <= p_idx; i++) { @@ -1389,7 +1369,7 @@ void TabBar::ensure_tab_visible(int p_idx) { if (prev_offset != offset) { _update_cache(); - update(); + queue_redraw(); } } @@ -1416,7 +1396,7 @@ void TabBar::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } @@ -1438,7 +1418,7 @@ void TabBar::set_max_tab_width(int p_width) { if (scroll_to_selected) { ensure_tab_visible(current); } - update(); + queue_redraw(); update_minimum_size(); } diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h index d123385e47..ac4a6a195e 100644 --- a/scene/gui/tab_bar.h +++ b/scene/gui/tab_bar.h @@ -104,6 +104,34 @@ private: bool scroll_to_selected = true; int tabs_rearrange_group = -1; + struct ThemeCache { + int h_separation = 0; + + Ref<StyleBox> tab_unselected_style; + Ref<StyleBox> tab_selected_style; + Ref<StyleBox> tab_disabled_style; + + Ref<Texture2D> increment_icon; + Ref<Texture2D> increment_hl_icon; + Ref<Texture2D> decrement_icon; + Ref<Texture2D> decrement_hl_icon; + Ref<Texture2D> drop_mark_icon; + Color drop_mark_color; + + Ref<Font> font; + int font_size; + int outline_size = 0; + + Color font_selected_color; + Color font_unselected_color; + Color font_disabled_color; + Color font_outline_color; + + Ref<Texture2D> close_icon; + Ref<StyleBox> button_pressed_style; + Ref<StyleBox> button_hl_style; + } theme_cache; + int get_tab_width(int p_idx) const; void _ensure_no_over_offset(); @@ -117,6 +145,7 @@ private: protected: virtual void gui_input(const Ref<InputEvent> &p_event) override; + virtual void _update_theme_item_cache() override; bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 10a6d18330..f45d132a66 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -60,26 +60,24 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { } // Handle menu button. - Ref<Texture2D> menu = get_theme_icon(SNAME("menu")); - if (is_layout_rtl()) { - if (popup && pos.x < menu->get_width()) { + if (popup && pos.x < theme_cache.menu_icon->get_width()) { emit_signal(SNAME("pre_popup_pressed")); Vector2 popup_pos = get_screen_position(); - popup_pos.y += menu->get_height(); + popup_pos.y += theme_cache.menu_icon->get_height(); popup->set_position(popup_pos); popup->popup(); return; } } else { - if (popup && pos.x > size.width - menu->get_width()) { + if (popup && pos.x > size.width - theme_cache.menu_icon->get_width()) { emit_signal(SNAME("pre_popup_pressed")); Vector2 popup_pos = get_screen_position(); popup_pos.x += size.width - popup->get_size().width; - popup_pos.y += menu->get_height(); + popup_pos.y += theme_cache.menu_icon->get_height(); popup->set_position(popup_pos); popup->popup(); @@ -98,34 +96,33 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { if (pos.y > _get_top_margin()) { if (menu_hovered) { menu_hovered = false; - update(); + queue_redraw(); } return; } - Ref<Texture2D> menu = get_theme_icon(SNAME("menu")); if (popup) { if (is_layout_rtl()) { - if (pos.x <= menu->get_width()) { + if (pos.x <= theme_cache.menu_icon->get_width()) { if (!menu_hovered) { menu_hovered = true; - update(); + queue_redraw(); return; } } else if (menu_hovered) { menu_hovered = false; - update(); + queue_redraw(); } } else { - if (pos.x >= size.width - menu->get_width()) { + if (pos.x >= size.width - theme_cache.menu_icon->get_width()) { if (!menu_hovered) { menu_hovered = true; - update(); + queue_redraw(); return; } } else if (menu_hovered) { menu_hovered = false; - update(); + queue_redraw(); } } @@ -136,6 +133,41 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) { } } +void TabContainer::_update_theme_item_cache() { + Container::_update_theme_item_cache(); + + theme_cache.side_margin = get_theme_constant(SNAME("side_margin")); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); + theme_cache.tabbar_style = get_theme_stylebox(SNAME("tabbar_background")); + + theme_cache.menu_icon = get_theme_icon(SNAME("menu")); + theme_cache.menu_hl_icon = get_theme_icon(SNAME("menu_highlight")); + + // TabBar overrides. + theme_cache.icon_separation = get_theme_constant(SNAME("icon_separation")); + theme_cache.outline_size = get_theme_constant(SNAME("outline_size")); + + theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected")); + theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected")); + theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled")); + + theme_cache.increment_icon = get_theme_icon(SNAME("increment")); + theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight")); + theme_cache.decrement_icon = get_theme_icon(SNAME("decrement")); + theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight")); + theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark")); + theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color")); + + theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color")); + theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color")); + theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color")); + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + + theme_cache.tab_font = get_theme_font(SNAME("font")); + theme_cache.tab_font_size = get_theme_font_size(SNAME("font_size")); +} + void TabContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -155,27 +187,26 @@ void TabContainer::_notification(int p_what) { Size2 size = get_size(); // Draw only the tab area if the header is hidden. - Ref<StyleBox> panel = get_theme_stylebox(SNAME("panel")); if (!tabs_visible) { - panel->draw(canvas, Rect2(0, 0, size.width, size.height)); + theme_cache.panel_style->draw(canvas, Rect2(0, 0, size.width, size.height)); return; } int header_height = _get_top_margin(); - panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); + // Draw background for the tabbar. + theme_cache.tabbar_style->draw(canvas, Rect2(0, 0, size.width, header_height)); + // Draw the background for the tab's content. + theme_cache.panel_style->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height)); // 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")); - - int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width(); + int x = is_layout_rtl() ? 0 : get_size().width - theme_cache.menu_icon->get_width(); if (menu_hovered) { - menu_hl->draw(get_canvas_item(), Point2(x, (header_height - menu_hl->get_height()) / 2)); + theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_hl_icon->get_height()) / 2)); } else { - menu->draw(get_canvas_item(), Point2(x, (header_height - menu->get_height()) / 2)); + theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, (header_height - theme_cache.menu_icon->get_height()) / 2)); } } } break; @@ -194,23 +225,27 @@ void TabContainer::_on_theme_changed() { return; } - 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_icon_override(SNAME("drop_mark"), get_theme_icon(SNAME("drop_mark"))); - tab_bar->add_theme_color_override(SNAME("drop_mark_color"), get_theme_color(SNAME("drop_mark_color"))); - 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_font_size_override(SNAME("font_size"), get_theme_font_size(SNAME("font_size"))); - tab_bar->add_theme_constant_override(SNAME("h_separation"), get_theme_constant(SNAME("icon_separation"))); - tab_bar->add_theme_constant_override(SNAME("outline_size"), get_theme_constant(SNAME("outline_size"))); + tab_bar->add_theme_style_override(SNAME("tab_unselected"), theme_cache.tab_unselected_style); + tab_bar->add_theme_style_override(SNAME("tab_selected"), theme_cache.tab_selected_style); + tab_bar->add_theme_style_override(SNAME("tab_disabled"), theme_cache.tab_disabled_style); + + tab_bar->add_theme_icon_override(SNAME("increment"), theme_cache.increment_icon); + tab_bar->add_theme_icon_override(SNAME("increment_highlight"), theme_cache.increment_hl_icon); + tab_bar->add_theme_icon_override(SNAME("decrement"), theme_cache.decrement_icon); + tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), theme_cache.decrement_hl_icon); + tab_bar->add_theme_icon_override(SNAME("drop_mark"), theme_cache.drop_mark_icon); + tab_bar->add_theme_color_override(SNAME("drop_mark_color"), theme_cache.drop_mark_color); + + tab_bar->add_theme_color_override(SNAME("font_selected_color"), theme_cache.font_selected_color); + tab_bar->add_theme_color_override(SNAME("font_unselected_color"), theme_cache.font_unselected_color); + tab_bar->add_theme_color_override(SNAME("font_disabled_color"), theme_cache.font_disabled_color); + tab_bar->add_theme_color_override(SNAME("font_outline_color"), theme_cache.font_outline_color); + + tab_bar->add_theme_font_override(SNAME("font"), theme_cache.tab_font); + tab_bar->add_theme_font_size_override(SNAME("font_size"), theme_cache.tab_font_size); + + tab_bar->add_theme_constant_override(SNAME("h_separation"), theme_cache.icon_separation); + tab_bar->add_theme_constant_override(SNAME("outline_size"), theme_cache.outline_size); _update_margins(); if (get_tab_count() > 0) { @@ -218,13 +253,12 @@ void TabContainer::_on_theme_changed() { } else { update_minimum_size(); } - update(); + queue_redraw(); theme_changing = false; } void TabContainer::_repaint() { - Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel")); Vector<Control *> controls = _get_tab_controls(); int current = get_current_tab(); @@ -239,10 +273,10 @@ void TabContainer::_repaint() { 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)); + c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + theme_cache.panel_style->get_margin(SIDE_TOP)); + c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_LEFT)); + c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - theme_cache.panel_style->get_margin(SIDE_RIGHT)); + c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - theme_cache.panel_style->get_margin(SIDE_BOTTOM)); } else { c->hide(); } @@ -252,8 +286,7 @@ void TabContainer::_repaint() { } void TabContainer::_update_margins() { - int menu_width = get_theme_icon(SNAME("menu"))->get_width(); - int side_margin = get_theme_constant(SNAME("side_margin")); + int menu_width = theme_cache.menu_icon->get_width(); // Directly check for validity, to avoid errors when quitting. bool has_popup = popup_obj_id.is_valid(); @@ -267,7 +300,7 @@ void TabContainer::_update_margins() { switch (get_tab_alignment()) { case TabBar::ALIGNMENT_LEFT: { - tab_bar->set_offset(SIDE_LEFT, side_margin); + tab_bar->set_offset(SIDE_LEFT, theme_cache.side_margin); tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0); } break; @@ -289,10 +322,10 @@ void TabContainer::_update_margins() { int total_tabs_width = last_tab_rect.position.x - first_tab_pos + last_tab_rect.size.width; // 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))) { + if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + theme_cache.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); + tab_bar->set_offset(SIDE_RIGHT, -theme_cache.side_margin); } } break; @@ -304,7 +337,7 @@ void TabContainer::_update_margins() { void TabContainer::_on_mouse_exited() { if (menu_hovered) { menu_hovered = false; - update(); + queue_redraw(); } } @@ -502,7 +535,7 @@ void TabContainer::add_child_notify(Node *p_child) { _update_margins(); if (get_tab_count() == 1) { - update(); + queue_redraw(); } p_child->connect("renamed", callable_mp(this, &TabContainer::_refresh_tab_names)); @@ -558,7 +591,7 @@ void TabContainer::remove_child_notify(Node *p_child) { _update_margins(); if (get_tab_count() == 0) { - update(); + queue_redraw(); } p_child->remove_meta("_tab_name"); @@ -656,7 +689,7 @@ void TabContainer::set_tabs_visible(bool p_visible) { } } - update(); + queue_redraw(); update_minimum_size(); } @@ -794,13 +827,12 @@ Size2 TabContainer::get_minimum_size() const { if (!get_clip_tabs()) { if (get_popup()) { - ms.x += get_theme_icon(SNAME("menu"))->get_width(); + ms.x += theme_cache.menu_icon->get_width(); } - int side_margin = get_theme_constant(SNAME("side_margin")); - if (side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER && + if (theme_cache.side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER && (get_tab_alignment() != TabBar::ALIGNMENT_RIGHT || !get_popup())) { - ms.x += side_margin; + ms.x += theme_cache.side_margin; } } } @@ -820,7 +852,7 @@ Size2 TabContainer::get_minimum_size() const { } ms.y += max_control_height; - Size2 panel_ms = get_theme_stylebox(SNAME("panel"))->get_minimum_size(); + Size2 panel_ms = theme_cache.panel_style->get_minimum_size(); ms.x = MAX(ms.x, panel_ms.x); ms.y += panel_ms.y; @@ -838,7 +870,7 @@ void TabContainer::set_popup(Node *p_popup) { popup_obj_id = popup_id; if (had_popup != bool(popup)) { - update(); + queue_redraw(); _update_margins(); if (!get_clip_tabs()) { update_minimum_size(); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 60c8130939..b552aa459b 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -48,6 +48,39 @@ class TabContainer : public Container { bool theme_changing = false; Node *child_removing = nullptr; + struct ThemeCache { + int side_margin = 0; + + Ref<StyleBox> panel_style; + Ref<StyleBox> tabbar_style; + + Ref<Texture2D> menu_icon; + Ref<Texture2D> menu_hl_icon; + + // TabBar overrides. + int icon_separation = 0; + int outline_size = 0; + + Ref<StyleBox> tab_unselected_style; + Ref<StyleBox> tab_selected_style; + Ref<StyleBox> tab_disabled_style; + + Ref<Texture2D> increment_icon; + Ref<Texture2D> increment_hl_icon; + Ref<Texture2D> decrement_icon; + Ref<Texture2D> decrement_hl_icon; + Ref<Texture2D> drop_mark_icon; + Color drop_mark_color; + + Color font_selected_color; + Color font_unselected_color; + Color font_disabled_color; + Color font_outline_color; + + Ref<Font> tab_font; + int tab_font_size; + } theme_cache; + int _get_top_margin() const; Vector<Control *> _get_tab_controls() const; void _on_theme_changed(); @@ -65,6 +98,8 @@ class TabContainer : public Container { protected: virtual void gui_input(const Ref<InputEvent> &p_event) override; + virtual void _update_theme_item_cache() override; + void _notification(int p_what); virtual void add_child_notify(Node *p_child) override; virtual void move_child_notify(Node *p_child) override; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 097eb1fd95..318447ecd8 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -452,13 +452,13 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_WM_WINDOW_FOCUS_IN: { window_has_focus = true; draw_caret = true; - update(); + queue_redraw(); } break; case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { window_has_focus = false; draw_caret = false; - update(); + queue_redraw(); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -1507,7 +1507,7 @@ void TextEdit::_notification(int p_what) { } text.invalidate_cache(caret.line, caret.column, true, t, structured_text_parser(st_parser, st_args, t)); - update(); + queue_redraw(); } } break; @@ -1614,7 +1614,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } if (mb->is_pressed()) { - if (mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_pressed()) { + if (mb->get_button_index() == MouseButton::WHEEL_UP && !mb->is_command_or_control_pressed()) { if (mb->is_shift_pressed()) { h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor())); } else if (mb->is_alt_pressed()) { @@ -1625,7 +1625,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { _scroll_up(3 * mb->get_factor()); } } - if (mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_pressed()) { + if (mb->get_button_index() == MouseButton::WHEEL_DOWN && !mb->is_command_or_control_pressed()) { if (mb->is_shift_pressed()) { h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor())); } else if (mb->is_alt_pressed()) { @@ -1696,7 +1696,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } selection.selecting_line = prev_line; selection.selecting_column = prev_col; - update(); + queue_redraw(); } else { if (caret.line < selection.selecting_line || (caret.line == selection.selecting_line && caret.column < selection.selecting_column)) { if (selection.shiftclick_left) { @@ -1718,7 +1718,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { selection.active = false; } - update(); + queue_redraw(); } } else if (drag_and_drop_selection_enabled && is_mouse_over_selection()) { selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; @@ -1746,7 +1746,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { last_dblclk = OS::get_singleton()->get_ticks_msec(); last_dblclk_pos = mb->get_position(); } - update(); + queue_redraw(); } if (is_middle_mouse_paste_enabled() && mb->get_button_index() == MouseButton::MIDDLE && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { @@ -1880,7 +1880,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { if (current_hovered_gutter != hovered_gutter) { hovered_gutter = current_hovered_gutter; - update(); + queue_redraw(); } if (drag_action && can_drop_data(mpos, get_viewport()->gui_get_drag_data())) { @@ -1920,7 +1920,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { // Allow unicode handling if: // * No Modifiers are pressed (except shift) - bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed()); + bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed()); selection.selecting_text = false; @@ -2146,7 +2146,7 @@ void TextEdit::_swap_current_input_direction() { input_direction = TEXT_DIRECTION_LTR; } set_caret_column(caret.column); - update(); + queue_redraw(); } void TextEdit::_new_line(bool p_split_current_line, bool p_above) { @@ -2527,7 +2527,7 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) { } _remove_text(caret.line, caret.column, next_line, next_column); - update(); + queue_redraw(); } void TextEdit::_move_caret_document_start(bool p_select) { @@ -2816,7 +2816,7 @@ void TextEdit::set_editable(const bool p_editable) { editable = p_editable; - update(); + queue_redraw(); } bool TextEdit::is_editable() const { @@ -2846,7 +2846,7 @@ void TextEdit::set_text_direction(Control::TextDirection p_text_direction) { menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); } - update(); + queue_redraw(); } } @@ -2866,7 +2866,7 @@ void TextEdit::set_language(const String &p_language) { text.set_direction_and_language(dir, (!language.is_empty()) ? language : TranslationServer::get_singleton()->get_tool_locale()); text.invalidate_all(); _update_placeholder(); - update(); + queue_redraw(); } } @@ -2880,7 +2880,7 @@ void TextEdit::set_structured_text_bidi_override(TextServer::StructuredTextParse for (int i = 0; i < text.size(); i++) { text.set(i, text[i], structured_text_parser(st_parser, st_args, text[i])); } - update(); + queue_redraw(); } } @@ -2897,7 +2897,7 @@ void TextEdit::set_structured_text_bidi_override_options(Array p_args) { for (int i = 0; i < text.size(); i++) { text.set(i, text[i], structured_text_parser(st_parser, st_args, text[i])); } - update(); + queue_redraw(); } Array TextEdit::get_structured_text_bidi_override_options() const { @@ -2912,7 +2912,7 @@ void TextEdit::set_tab_size(const int p_size) { text.set_tab_size(p_size); text.invalidate_all_lines(); _update_placeholder(); - update(); + queue_redraw(); } int TextEdit::get_tab_size() const { @@ -2926,7 +2926,7 @@ void TextEdit::set_overtype_mode_enabled(const bool p_enabled) { } overtype_mode = p_enabled; - update(); + queue_redraw(); } bool TextEdit::is_overtype_mode_enabled() const { @@ -3022,7 +3022,7 @@ void TextEdit::set_text(const String &p_text) { set_caret_line(0); set_caret_column(0); - update(); + queue_redraw(); setting_text = false; emit_signal(SNAME("text_set")); } @@ -3050,7 +3050,7 @@ void TextEdit::set_placeholder(const String &p_text) { placeholder_text = p_text; _update_placeholder(); - update(); + queue_redraw(); } String TextEdit::get_placeholder() const { @@ -3149,7 +3149,7 @@ void TextEdit::insert_line_at(int p_at, const String &p_text) { ++selection.to_line; } } - update(); + queue_redraw(); } void TextEdit::insert_text_at_caret(const String &p_text) { @@ -3166,7 +3166,7 @@ void TextEdit::insert_text_at_caret(const String &p_text) { set_caret_line(new_line, false); set_caret_column(new_column); - update(); + queue_redraw(); if (had_selection) { end_complex_operation(); @@ -3557,7 +3557,7 @@ void TextEdit::undo() { set_caret_line(undo_stack_pos->get().from_line, false); set_caret_column(undo_stack_pos->get().from_column); } - update(); + queue_redraw(); } void TextEdit::redo() { @@ -3592,7 +3592,7 @@ void TextEdit::redo() { set_caret_line(undo_stack_pos->get().to_line, false); set_caret_column(undo_stack_pos->get().to_column); undo_stack_pos = undo_stack_pos->next(); - update(); + queue_redraw(); } void TextEdit::clear_undo_history() { @@ -3962,7 +3962,7 @@ void TextEdit::set_caret_type(CaretType p_type) { } caret_type = p_type; - update(); + queue_redraw(); } TextEdit::CaretType TextEdit::get_caret_type() const { @@ -3990,13 +3990,13 @@ bool TextEdit::is_caret_blink_enabled() const { return caret_blink_enabled; } -float TextEdit::get_caret_blink_speed() const { +float TextEdit::get_caret_blink_interval() const { return caret_blink_timer->get_wait_time(); } -void TextEdit::set_caret_blink_speed(const float p_speed) { - ERR_FAIL_COND(p_speed <= 0); - caret_blink_timer->set_wait_time(p_speed); +void TextEdit::set_caret_blink_interval(const float p_interval) { + ERR_FAIL_COND(p_interval <= 0); + caret_blink_timer->set_wait_time(p_interval); } void TextEdit::set_move_caret_on_right_click_enabled(const bool p_enabled) { @@ -4217,7 +4217,7 @@ void TextEdit::select_all() { selection.shiftclick_left = true; set_caret_line(selection.to_line, false); set_caret_column(selection.to_column, false); - update(); + queue_redraw(); } void TextEdit::select_word_under_caret() { @@ -4312,7 +4312,7 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t selection.shiftclick_left = true; } - update(); + queue_redraw(); } bool TextEdit::has_selection() const { @@ -4359,7 +4359,7 @@ int TextEdit::get_selection_to_column() const { void TextEdit::deselect() { selection.active = false; - update(); + queue_redraw(); } void TextEdit::delete_selection() { @@ -4372,7 +4372,7 @@ void TextEdit::delete_selection() { _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); set_caret_line(selection.from_line, false, false); set_caret_column(selection.from_column); - update(); + queue_redraw(); } /* Line wrapping. */ @@ -4464,7 +4464,7 @@ void TextEdit::set_scroll_past_end_of_file_enabled(const bool p_enabled) { } scroll_past_end_of_file_enabled = p_enabled; - update(); + queue_redraw(); } bool TextEdit::is_scroll_past_end_of_file_enabled() const { @@ -4688,7 +4688,7 @@ void TextEdit::adjust_viewport_to_caret() { } h_scroll->set_value(caret.x_ofs); - update(); + queue_redraw(); } void TextEdit::center_viewport_to_caret() { @@ -4741,7 +4741,7 @@ void TextEdit::center_viewport_to_caret() { } h_scroll->set_value(caret.x_ofs); - update(); + queue_redraw(); } /* Minimap */ @@ -4752,7 +4752,7 @@ void TextEdit::set_draw_minimap(bool p_enabled) { draw_minimap = p_enabled; _update_wrap_at_column(); - update(); + queue_redraw(); } bool TextEdit::is_drawing_minimap() const { @@ -4766,7 +4766,7 @@ void TextEdit::set_minimap_width(int p_minimap_width) { minimap_width = p_minimap_width; _update_wrap_at_column(); - update(); + queue_redraw(); } int TextEdit::get_minimap_width() const { @@ -4786,8 +4786,11 @@ void TextEdit::add_gutter(int p_at) { } text.add_gutter(p_at); + + _update_gutter_width(); + emit_signal(SNAME("gutter_added")); - update(); + queue_redraw(); } void TextEdit::remove_gutter(int p_gutter) { @@ -4796,8 +4799,11 @@ void TextEdit::remove_gutter(int p_gutter) { gutters.remove_at(p_gutter); text.remove_gutter(p_gutter); + + _update_gutter_width(); + emit_signal(SNAME("gutter_removed")); - update(); + queue_redraw(); } int TextEdit::get_gutter_count() const { @@ -4822,7 +4828,7 @@ void TextEdit::set_gutter_type(int p_gutter, GutterType p_type) { } gutters.write[p_gutter].type = p_type; - update(); + queue_redraw(); } TextEdit::GutterType TextEdit::get_gutter_type(int p_gutter) const { @@ -4870,7 +4876,7 @@ void TextEdit::set_gutter_clickable(int p_gutter, bool p_clickable) { } gutters.write[p_gutter].clickable = p_clickable; - update(); + queue_redraw(); } bool TextEdit::is_gutter_clickable(int p_gutter) const { @@ -4918,7 +4924,7 @@ void TextEdit::merge_gutters(int p_from_line, int p_to_line) { text.set_line_gutter_clickable(p_to_line, i, true); } } - update(); + queue_redraw(); } void TextEdit::set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callback) { @@ -4929,7 +4935,7 @@ void TextEdit::set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callb } gutters.write[p_gutter].custom_draw_callback = p_draw_callback; - update(); + queue_redraw(); } // Line gutters. @@ -4954,7 +4960,7 @@ void TextEdit::set_line_gutter_text(int p_line, int p_gutter, const String &p_te } text.set_line_gutter_text(p_line, p_gutter, p_text); - update(); + queue_redraw(); } String TextEdit::get_line_gutter_text(int p_line, int p_gutter) const { @@ -4972,7 +4978,7 @@ void TextEdit::set_line_gutter_icon(int p_line, int p_gutter, const Ref<Texture2 } text.set_line_gutter_icon(p_line, p_gutter, p_icon); - update(); + queue_redraw(); } Ref<Texture2D> TextEdit::get_line_gutter_icon(int p_line, int p_gutter) const { @@ -4990,7 +4996,7 @@ void TextEdit::set_line_gutter_item_color(int p_line, int p_gutter, const Color } text.set_line_gutter_item_color(p_line, p_gutter, p_color); - update(); + queue_redraw(); } Color TextEdit::get_line_gutter_item_color(int p_line, int p_gutter) const { @@ -5020,7 +5026,7 @@ void TextEdit::set_line_background_color(int p_line, const Color &p_color) { } text.set_line_background_color(p_line, p_color); - update(); + queue_redraw(); } Color TextEdit::get_line_background_color(int p_line) const { @@ -5038,7 +5044,7 @@ void TextEdit::set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighte if (syntax_highlighter.is_valid()) { syntax_highlighter->set_text_edit(this); } - update(); + queue_redraw(); } Ref<SyntaxHighlighter> TextEdit::get_syntax_highlighter() const { @@ -5052,7 +5058,7 @@ void TextEdit::set_highlight_current_line(bool p_enabled) { } highlight_current_line = p_enabled; - update(); + queue_redraw(); } bool TextEdit::is_highlight_current_line_enabled() const { @@ -5065,7 +5071,7 @@ void TextEdit::set_highlight_all_occurrences(const bool p_enabled) { } highlight_all_occurrences = p_enabled; - update(); + queue_redraw(); } bool TextEdit::is_highlight_all_occurrences_enabled() const { @@ -5081,7 +5087,7 @@ void TextEdit::set_draw_control_chars(bool p_enabled) { text.set_draw_control_chars(draw_control_chars); text.invalidate_font(); _update_placeholder(); - update(); + queue_redraw(); } } @@ -5095,7 +5101,7 @@ void TextEdit::set_draw_tabs(bool p_enabled) { } draw_tabs = p_enabled; - update(); + queue_redraw(); } bool TextEdit::is_drawing_tabs() const { @@ -5108,7 +5114,7 @@ void TextEdit::set_draw_spaces(bool p_enabled) { } draw_spaces = p_enabled; - update(); + queue_redraw(); } bool TextEdit::is_drawing_spaces() const { @@ -5288,8 +5294,8 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_caret_blink_enabled", "enable"), &TextEdit::set_caret_blink_enabled); ClassDB::bind_method(D_METHOD("is_caret_blink_enabled"), &TextEdit::is_caret_blink_enabled); - ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &TextEdit::set_caret_blink_speed); - ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &TextEdit::get_caret_blink_speed); + ClassDB::bind_method(D_METHOD("set_caret_blink_interval", "interval"), &TextEdit::set_caret_blink_interval); + ClassDB::bind_method(D_METHOD("get_caret_blink_interval"), &TextEdit::get_caret_blink_interval); ClassDB::bind_method(D_METHOD("set_move_caret_on_right_click_enabled", "enable"), &TextEdit::set_move_caret_on_right_click_enabled); ClassDB::bind_method(D_METHOD("is_move_caret_on_right_click_enabled"), &TextEdit::is_move_caret_on_right_click_enabled); @@ -5518,7 +5524,7 @@ void TextEdit::_bind_methods() { ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_type", PROPERTY_HINT_ENUM, "Line,Block"), "set_caret_type", "get_caret_type"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_caret_blink_speed", "get_caret_blink_speed"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval", PROPERTY_HINT_RANGE, "0.1,10,0.01,suffix:s"), "set_caret_blink_interval", "get_caret_blink_interval"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_move_on_right_click"), "set_move_caret_on_right_click_enabled", "is_move_caret_on_right_click_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled"); @@ -5560,7 +5566,7 @@ void TextEdit::_set_hiding_enabled(bool p_enabled) { _unhide_all_lines(); } hiding_enabled = p_enabled; - update(); + queue_redraw(); } bool TextEdit::_is_hiding_enabled() const { @@ -5577,7 +5583,7 @@ void TextEdit::_unhide_all_lines() { text.set_hidden(i, false); } _update_scrollbars(); - update(); + queue_redraw(); } void TextEdit::_set_line_as_hidden(int p_line, bool p_hidden) { @@ -5590,7 +5596,7 @@ void TextEdit::_set_line_as_hidden(int p_line, bool p_hidden) { if (_is_hiding_enabled() || !p_hidden) { text.set_hidden(p_line, p_hidden); } - update(); + queue_redraw(); } // Symbol lookup. @@ -5600,7 +5606,7 @@ void TextEdit::_set_symbol_lookup_word(const String &p_symbol) { } lookup_symbol_word = p_symbol; - update(); + queue_redraw(); } /* Text manipulation */ @@ -5985,14 +5991,14 @@ void TextEdit::_reset_caret_blink_timer() { if (has_focus()) { caret_blink_timer->stop(); caret_blink_timer->start(); - update(); + queue_redraw(); } } void TextEdit::_toggle_draw_caret() { draw_caret = !draw_caret; if (is_visible_in_tree() && has_focus() && window_has_focus) { - update(); + queue_redraw(); } } @@ -6054,7 +6060,7 @@ void TextEdit::_update_selection_mode_pointer() { set_caret_line(line, false); set_caret_column(col); - update(); + queue_redraw(); click_select_held->start(); } @@ -6106,7 +6112,7 @@ void TextEdit::_update_selection_mode_word() { DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text()); } - update(); + queue_redraw(); click_select_held->start(); } @@ -6137,7 +6143,7 @@ void TextEdit::_update_selection_mode_line() { DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text()); } - update(); + queue_redraw(); click_select_held->start(); } @@ -6163,7 +6169,7 @@ void TextEdit::_post_shift_selection() { if (selection.active && selection.selecting_mode == SelectionMode::SELECTION_MODE_SHIFT) { select(selection.selecting_line, selection.selecting_column, caret.line, caret.column); - update(); + queue_redraw(); } selection.selecting_text = true; @@ -6325,7 +6331,7 @@ void TextEdit::_scroll_moved(double p_to_val) { caret.line_ofs = n_line; caret.wrap_ofs = wi; } - update(); + queue_redraw(); } double TextEdit::_get_visible_lines_offset() const { @@ -6447,7 +6453,7 @@ void TextEdit::_update_minimap_hover() { if (hovering_minimap) { // Only redraw if the hovering status changed. hovering_minimap = false; - update(); + queue_redraw(); } // Return early to avoid running the operations below when not needed. @@ -6460,7 +6466,7 @@ void TextEdit::_update_minimap_hover() { if (new_hovering_minimap != hovering_minimap) { // Only redraw if the hovering status changed. hovering_minimap = new_hovering_minimap; - update(); + queue_redraw(); } } @@ -6522,7 +6528,7 @@ void TextEdit::_update_gutter_width() { if (gutters_width > 0) { gutter_padding = 2; } - update(); + queue_redraw(); } /* Syntax highlighting. */ diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index f97f99075c..a8da878ede 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -762,8 +762,8 @@ public: void set_caret_blink_enabled(const bool p_enabled); bool is_caret_blink_enabled() const; - void set_caret_blink_speed(const float p_speed); - float get_caret_blink_speed() const; + void set_caret_blink_interval(const float p_interval); + float get_caret_blink_interval() const; void set_move_caret_on_right_click_enabled(const bool p_enabled); bool is_move_caret_on_right_click_enabled() const; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 916bb2981e..d9ab1c2c55 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -67,7 +67,7 @@ bool TextureButton::has_point(const Point2 &p_point) const { Rect2 rect = Rect2(); Size2 mask_size = click_mask->get_size(); - if (_position_rect.has_no_area()) { + if (!_position_rect.has_area()) { rect.size = mask_size; } else if (_tile) { // if the stretch mode is tile we offset the point to keep it inside the mask size @@ -112,7 +112,7 @@ bool TextureButton::has_point(const Point2 &p_point) const { } Point2i p = point; - return click_mask->get_bit(p); + return click_mask->get_bitv(p); } return Control::has_point(p_point); @@ -299,7 +299,7 @@ void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) { } normal = p_normal; - update(); + queue_redraw(); update_minimum_size(); } @@ -309,7 +309,7 @@ void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) { } pressed = p_pressed; - update(); + queue_redraw(); update_minimum_size(); } @@ -319,7 +319,7 @@ void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) { } hover = p_hover; - update(); + queue_redraw(); update_minimum_size(); } @@ -329,7 +329,7 @@ void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) { } disabled = p_disabled; - update(); + queue_redraw(); } void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) { @@ -337,7 +337,7 @@ void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) { return; } click_mask = p_click_mask; - update(); + queue_redraw(); update_minimum_size(); } @@ -380,7 +380,7 @@ void TextureButton::set_ignore_texture_size(bool p_ignore) { ignore_texture_size = p_ignore; update_minimum_size(); - update(); + queue_redraw(); } void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) { @@ -389,7 +389,7 @@ void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) { } stretch_mode = p_stretch_mode; - update(); + queue_redraw(); } TextureButton::StretchMode TextureButton::get_stretch_mode() const { @@ -402,7 +402,7 @@ void TextureButton::set_flip_h(bool p_flip) { } hflip = p_flip; - update(); + queue_redraw(); } bool TextureButton::is_flipped_h() const { @@ -415,7 +415,7 @@ void TextureButton::set_flip_v(bool p_flip) { } vflip = p_flip; - update(); + queue_redraw(); } bool TextureButton::is_flipped_v() const { diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index 2a9e1a8990..a9982b3ece 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -38,7 +38,7 @@ void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) { } under = p_texture; - update(); + queue_redraw(); update_minimum_size(); } @@ -52,7 +52,7 @@ void TextureProgressBar::set_over_texture(const Ref<Texture2D> &p_texture) { } over = p_texture; - update(); + queue_redraw(); if (under.is_null()) { update_minimum_size(); } @@ -70,7 +70,7 @@ void TextureProgressBar::set_stretch_margin(Side p_side, int p_size) { } stretch_margin[p_side] = p_size; - update(); + queue_redraw(); update_minimum_size(); } @@ -85,7 +85,7 @@ void TextureProgressBar::set_nine_patch_stretch(bool p_stretch) { } nine_patch_stretch = p_stretch; - update(); + queue_redraw(); update_minimum_size(); } @@ -113,7 +113,7 @@ void TextureProgressBar::set_progress_texture(const Ref<Texture2D> &p_texture) { } progress = p_texture; - update(); + queue_redraw(); update_minimum_size(); } @@ -127,7 +127,7 @@ void TextureProgressBar::set_progress_offset(Point2 p_offset) { } progress_offset = p_offset; - update(); + queue_redraw(); } Point2 TextureProgressBar::get_progress_offset() const { @@ -140,7 +140,7 @@ void TextureProgressBar::set_tint_under(const Color &p_tint) { } tint_under = p_tint; - update(); + queue_redraw(); } Color TextureProgressBar::get_tint_under() const { @@ -153,7 +153,7 @@ void TextureProgressBar::set_tint_progress(const Color &p_tint) { } tint_progress = p_tint; - update(); + queue_redraw(); } Color TextureProgressBar::get_tint_progress() const { @@ -166,7 +166,7 @@ void TextureProgressBar::set_tint_over(const Color &p_tint) { } tint_over = p_tint; - update(); + queue_redraw(); } Color TextureProgressBar::get_tint_over() const { @@ -591,7 +591,7 @@ void TextureProgressBar::set_fill_mode(int p_fill) { } mode = (FillMode)p_fill; - update(); + queue_redraw(); } int TextureProgressBar::get_fill_mode() { @@ -611,7 +611,7 @@ void TextureProgressBar::set_radial_initial_angle(float p_angle) { } rad_init_angle = p_angle; - update(); + queue_redraw(); } float TextureProgressBar::get_radial_initial_angle() { @@ -626,7 +626,7 @@ void TextureProgressBar::set_fill_degrees(float p_angle) { } rad_max_degrees = angle_clamped; - update(); + queue_redraw(); } float TextureProgressBar::get_fill_degrees() { @@ -639,7 +639,7 @@ void TextureProgressBar::set_radial_center_offset(const Point2 &p_off) { } rad_center_off = p_off; - update(); + queue_redraw(); } Point2 TextureProgressBar::get_radial_center_offset() { diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index 4dd1c74c12..459e67091d 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -94,7 +94,7 @@ void TextureRect::_notification(int p_what) { Ref<AtlasTexture> p_atlas = texture; - if (p_atlas.is_valid() && region.has_no_area()) { + if (p_atlas.is_valid() && !region.has_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; @@ -104,10 +104,10 @@ void TextureRect::_notification(int p_what) { 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 { + if (region.has_area()) { draw_texture_rect_region(texture, Rect2(offset, size), region); + } else { + draw_texture_rect(texture, Rect2(offset, size), tile); } } break; } @@ -150,7 +150,7 @@ void TextureRect::_bind_methods() { void TextureRect::_texture_changed() { if (texture.is_valid()) { - update(); + queue_redraw(); update_minimum_size(); } } @@ -170,7 +170,7 @@ void TextureRect::set_texture(const Ref<Texture2D> &p_tex) { texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureRect::_texture_changed)); } - update(); + queue_redraw(); update_minimum_size(); } @@ -184,7 +184,7 @@ void TextureRect::set_ignore_texture_size(bool p_ignore) { } ignore_texture_size = p_ignore; - update(); + queue_redraw(); update_minimum_size(); } @@ -198,7 +198,7 @@ void TextureRect::set_stretch_mode(StretchMode p_mode) { } stretch_mode = p_mode; - update(); + queue_redraw(); } TextureRect::StretchMode TextureRect::get_stretch_mode() const { @@ -211,7 +211,7 @@ void TextureRect::set_flip_h(bool p_flip) { } hflip = p_flip; - update(); + queue_redraw(); } bool TextureRect::is_flipped_h() const { @@ -224,7 +224,7 @@ void TextureRect::set_flip_v(bool p_flip) { } vflip = p_flip; - update(); + queue_redraw(); } bool TextureRect::is_flipped_v() const { diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 2b19ee4d0b..237c78407b 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -126,13 +126,13 @@ void TreeItem::_change_tree(Tree *p_tree) { tree->pressing_for_editor = false; } - tree->update(); + tree->queue_redraw(); } tree = p_tree; if (tree) { - tree->update(); + tree->queue_redraw(); cells.resize(tree->columns.size()); } } @@ -551,7 +551,7 @@ void TreeItem::set_collapsed(bool p_collapsed) { select(tree->selected_col); } - tree->update(); + tree->queue_redraw(); } } @@ -569,7 +569,7 @@ void TreeItem::set_visible(bool p_visible) { } visible = p_visible; if (tree) { - tree->update(); + tree->queue_redraw(); _changed_notify(); } } @@ -610,7 +610,7 @@ TreeItem *TreeItem::create_child(int p_idx) { TreeItem *ti = memnew(TreeItem(tree)); if (tree) { ti->cells.resize(tree->columns.size()); - tree->update(); + tree->queue_redraw(); } TreeItem *l_prev = nullptr; @@ -880,7 +880,7 @@ void TreeItem::move_before(TreeItem *p_item) { p_item->prev = this; if (tree && old_tree == tree) { - tree->update(); + tree->queue_redraw(); } validate_cache(); @@ -924,7 +924,7 @@ void TreeItem::move_after(TreeItem *p_item) { } if (tree && old_tree == tree) { - tree->update(); + tree->queue_redraw(); } validate_cache(); } @@ -939,7 +939,7 @@ void TreeItem::remove_child(TreeItem *p_item) { p_item->parent = nullptr; if (tree) { - tree->update(); + tree->queue_redraw(); } validate_cache(); } @@ -972,7 +972,7 @@ void TreeItem::set_as_cursor(int p_column) { } tree->selected_item = this; tree->selected_col = p_column; - tree->update(); + tree->queue_redraw(); } void TreeItem::select(int p_column) { @@ -1013,7 +1013,7 @@ Ref<Texture2D> TreeItem::get_button(int p_column, int p_idx) const { return cells[p_column].buttons[p_idx].texture; } -String TreeItem::get_button_tooltip(int p_column, int p_idx) const { +String TreeItem::get_button_tooltip_text(int p_column, int p_idx) const { ERR_FAIL_INDEX_V(p_column, cells.size(), String()); ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String()); return cells[p_column].buttons[p_idx].tooltip; @@ -1160,12 +1160,12 @@ int TreeItem::get_custom_font_size(int p_column) const { return cells[p_column].custom_font_size; } -void TreeItem::set_tooltip(int p_column, const String &p_tooltip) { +void TreeItem::set_tooltip_text(int p_column, const String &p_tooltip) { ERR_FAIL_INDEX(p_column, cells.size()); cells.write[p_column].tooltip = p_tooltip; } -String TreeItem::get_tooltip(int p_column) const { +String TreeItem::get_tooltip_text(int p_column) const { ERR_FAIL_INDEX_V(p_column, cells.size(), ""); return cells[p_column].tooltip; } @@ -1286,14 +1286,14 @@ Size2 TreeItem::get_minimum_size(int p_column) { // Icon. if (cell.mode == CELL_MODE_CHECK) { - size.width += tree->cache.checked->get_width() + tree->cache.hseparation; + size.width += tree->theme_cache.checked->get_width() + tree->theme_cache.hseparation; } if (cell.icon.is_valid()) { Size2i icon_size = cell.get_icon_size(); if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) { icon_size.width = cell.icon_max_w; } - size.width += icon_size.width + tree->cache.hseparation; + size.width += icon_size.width + tree->theme_cache.hseparation; size.height = MAX(size.height, icon_size.height); } @@ -1301,13 +1301,13 @@ Size2 TreeItem::get_minimum_size(int p_column) { for (int i = 0; i < cell.buttons.size(); i++) { Ref<Texture2D> texture = cell.buttons[i].texture; if (texture.is_valid()) { - Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size(); + Size2 button_size = texture->get_size() + tree->theme_cache.button_pressed->get_minimum_size(); size.width += button_size.width; size.height = MAX(size.height, button_size.height); } } if (cell.buttons.size() >= 2) { - size.width += (cell.buttons.size() - 1) * tree->cache.button_margin; + size.width += (cell.buttons.size() - 1) * tree->theme_cache.button_margin; } cells.write[p_column].cached_minimum_size = size; @@ -1441,9 +1441,9 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_as_button", "column", "enable"), &TreeItem::set_custom_as_button); ClassDB::bind_method(D_METHOD("is_custom_set_as_button", "column"), &TreeItem::is_custom_set_as_button); - ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL("")); + ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip_text"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL("")); ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count); - ClassDB::bind_method(D_METHOD("get_button_tooltip", "column", "button_idx"), &TreeItem::get_button_tooltip); + ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_idx"), &TreeItem::get_button_tooltip_text); ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_idx"), &TreeItem::get_button_id); ClassDB::bind_method(D_METHOD("get_button_by_id", "column", "id"), &TreeItem::get_button_by_id); ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button); @@ -1452,8 +1452,8 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled); ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled); - ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip); - ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip); + ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text); + ClassDB::bind_method(D_METHOD("get_tooltip_text", "column"), &TreeItem::get_tooltip_text); ClassDB::bind_method(D_METHOD("set_text_alignment", "column", "text_alignment"), &TreeItem::set_text_alignment); ClassDB::bind_method(D_METHOD("get_text_alignment", "column"), &TreeItem::get_text_alignment); @@ -1535,68 +1535,68 @@ TreeItem::~TreeItem() { /**********************************************/ /**********************************************/ -void Tree::update_cache() { - cache.font = get_theme_font(SNAME("font")); - cache.font_size = get_theme_font_size(SNAME("font_size")); - cache.tb_font = get_theme_font(SNAME("title_button_font")); - cache.tb_font_size = get_theme_font_size(SNAME("title_button_font_size")); - cache.bg = get_theme_stylebox(SNAME("bg")); - cache.selected = get_theme_stylebox(SNAME("selected")); - cache.selected_focus = get_theme_stylebox(SNAME("selected_focus")); - cache.cursor = get_theme_stylebox(SNAME("cursor")); - cache.cursor_unfocus = get_theme_stylebox(SNAME("cursor_unfocused")); - cache.button_pressed = get_theme_stylebox(SNAME("button_pressed")); - - cache.checked = get_theme_icon(SNAME("checked")); - cache.unchecked = get_theme_icon(SNAME("unchecked")); - cache.indeterminate = get_theme_icon(SNAME("indeterminate")); - if (is_layout_rtl()) { - cache.arrow_collapsed = get_theme_icon(SNAME("arrow_collapsed_mirrored")); - } else { - cache.arrow_collapsed = get_theme_icon(SNAME("arrow_collapsed")); - } - cache.arrow = get_theme_icon(SNAME("arrow")); - cache.select_arrow = get_theme_icon(SNAME("select_arrow")); - cache.updown = get_theme_icon(SNAME("updown")); - - cache.custom_button = get_theme_stylebox(SNAME("custom_button")); - cache.custom_button_hover = get_theme_stylebox(SNAME("custom_button_hover")); - cache.custom_button_pressed = get_theme_stylebox(SNAME("custom_button_pressed")); - cache.custom_button_font_highlight = get_theme_color(SNAME("custom_button_font_highlight")); - - cache.font_color = get_theme_color(SNAME("font_color")); - cache.font_selected_color = get_theme_color(SNAME("font_selected_color")); - cache.drop_position_color = get_theme_color(SNAME("drop_position_color")); - cache.hseparation = get_theme_constant(SNAME("h_separation")); - cache.vseparation = get_theme_constant(SNAME("v_separation")); - cache.item_margin = get_theme_constant(SNAME("item_margin")); - cache.button_margin = get_theme_constant(SNAME("button_margin")); - - cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); - cache.font_outline_size = get_theme_constant(SNAME("outline_size")); - - cache.draw_guides = get_theme_constant(SNAME("draw_guides")); - cache.guide_color = get_theme_color(SNAME("guide_color")); - cache.draw_relationship_lines = get_theme_constant(SNAME("draw_relationship_lines")); - cache.relationship_line_width = get_theme_constant(SNAME("relationship_line_width")); - cache.parent_hl_line_width = get_theme_constant(SNAME("parent_hl_line_width")); - cache.children_hl_line_width = get_theme_constant(SNAME("children_hl_line_width")); - cache.parent_hl_line_margin = get_theme_constant(SNAME("parent_hl_line_margin")); - cache.relationship_line_color = get_theme_color(SNAME("relationship_line_color")); - cache.parent_hl_line_color = get_theme_color(SNAME("parent_hl_line_color")); - cache.children_hl_line_color = get_theme_color(SNAME("children_hl_line_color")); - - cache.scroll_border = get_theme_constant(SNAME("scroll_border")); - cache.scroll_speed = get_theme_constant(SNAME("scroll_speed")); - - cache.title_button = get_theme_stylebox(SNAME("title_button_normal")); - cache.title_button_pressed = get_theme_stylebox(SNAME("title_button_pressed")); - cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover")); - cache.title_button_color = get_theme_color(SNAME("title_button_color")); - - cache.base_scale = get_theme_default_base_scale(); - - v_scroll->set_custom_step(cache.font->get_height(cache.font_size)); +void Tree::_update_theme_item_cache() { + Control::_update_theme_item_cache(); + + theme_cache.panel_style = get_theme_stylebox(SNAME("panel")); + theme_cache.focus_style = get_theme_stylebox(SNAME("focus")); + + theme_cache.font = get_theme_font(SNAME("font")); + theme_cache.font_size = get_theme_font_size(SNAME("font_size")); + theme_cache.tb_font = get_theme_font(SNAME("title_button_font")); + theme_cache.tb_font_size = get_theme_font_size(SNAME("title_button_font_size")); + + theme_cache.selected = get_theme_stylebox(SNAME("selected")); + theme_cache.selected_focus = get_theme_stylebox(SNAME("selected_focus")); + theme_cache.cursor = get_theme_stylebox(SNAME("cursor")); + theme_cache.cursor_unfocus = get_theme_stylebox(SNAME("cursor_unfocused")); + theme_cache.button_pressed = get_theme_stylebox(SNAME("button_pressed")); + + theme_cache.checked = get_theme_icon(SNAME("checked")); + theme_cache.unchecked = get_theme_icon(SNAME("unchecked")); + theme_cache.indeterminate = get_theme_icon(SNAME("indeterminate")); + theme_cache.arrow = get_theme_icon(SNAME("arrow")); + theme_cache.arrow_collapsed = get_theme_icon(SNAME("arrow_collapsed")); + theme_cache.arrow_collapsed_mirrored = get_theme_icon(SNAME("arrow_collapsed_mirrored")); + theme_cache.select_arrow = get_theme_icon(SNAME("select_arrow")); + theme_cache.updown = get_theme_icon(SNAME("updown")); + + theme_cache.custom_button = get_theme_stylebox(SNAME("custom_button")); + theme_cache.custom_button_hover = get_theme_stylebox(SNAME("custom_button_hover")); + theme_cache.custom_button_pressed = get_theme_stylebox(SNAME("custom_button_pressed")); + theme_cache.custom_button_font_highlight = get_theme_color(SNAME("custom_button_font_highlight")); + + theme_cache.font_color = get_theme_color(SNAME("font_color")); + theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color")); + theme_cache.drop_position_color = get_theme_color(SNAME("drop_position_color")); + theme_cache.hseparation = get_theme_constant(SNAME("h_separation")); + theme_cache.vseparation = get_theme_constant(SNAME("v_separation")); + theme_cache.item_margin = get_theme_constant(SNAME("item_margin")); + theme_cache.button_margin = get_theme_constant(SNAME("button_margin")); + + theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color")); + theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size")); + + theme_cache.draw_guides = get_theme_constant(SNAME("draw_guides")); + theme_cache.guide_color = get_theme_color(SNAME("guide_color")); + theme_cache.draw_relationship_lines = get_theme_constant(SNAME("draw_relationship_lines")); + theme_cache.relationship_line_width = get_theme_constant(SNAME("relationship_line_width")); + theme_cache.parent_hl_line_width = get_theme_constant(SNAME("parent_hl_line_width")); + theme_cache.children_hl_line_width = get_theme_constant(SNAME("children_hl_line_width")); + theme_cache.parent_hl_line_margin = get_theme_constant(SNAME("parent_hl_line_margin")); + theme_cache.relationship_line_color = get_theme_color(SNAME("relationship_line_color")); + theme_cache.parent_hl_line_color = get_theme_color(SNAME("parent_hl_line_color")); + theme_cache.children_hl_line_color = get_theme_color(SNAME("children_hl_line_color")); + + theme_cache.scroll_border = get_theme_constant(SNAME("scroll_border")); + theme_cache.scroll_speed = get_theme_constant(SNAME("scroll_speed")); + + theme_cache.title_button = get_theme_stylebox(SNAME("title_button_normal")); + theme_cache.title_button_pressed = get_theme_stylebox(SNAME("title_button_pressed")); + theme_cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover")); + theme_cache.title_button_color = get_theme_color(SNAME("title_button_color")); + + theme_cache.base_scale = get_theme_default_base_scale(); } int Tree::compute_item_height(TreeItem *p_item) const { @@ -1604,7 +1604,7 @@ int Tree::compute_item_height(TreeItem *p_item) const { return 0; } - ERR_FAIL_COND_V(cache.font.is_null(), 0); + ERR_FAIL_COND_V(theme_cache.font.is_null(), 0); int height = 0; for (int i = 0; i < columns.size(); i++) { @@ -1622,7 +1622,7 @@ int Tree::compute_item_height(TreeItem *p_item) const { switch (p_item->cells[i].mode) { case TreeItem::CELL_MODE_CHECK: { - int check_icon_h = cache.checked->get_height(); + int check_icon_h = theme_cache.checked->get_height(); if (height < check_icon_h) { height = check_icon_h; } @@ -1642,7 +1642,7 @@ int Tree::compute_item_height(TreeItem *p_item) const { } } if (p_item->cells[i].mode == TreeItem::CELL_MODE_CUSTOM && p_item->cells[i].custom_button) { - height += cache.custom_button->get_minimum_size().height; + height += theme_cache.custom_button->get_minimum_size().height; } } break; @@ -1655,7 +1655,7 @@ int Tree::compute_item_height(TreeItem *p_item) const { height = item_min_height; } - height += cache.vseparation; + height += theme_cache.vseparation; return height; } @@ -1665,7 +1665,7 @@ int Tree::get_item_height(TreeItem *p_item) const { return 0; } int height = compute_item_height(p_item); - height += cache.vseparation; + height += theme_cache.vseparation; if (!p_item->collapsed) { /* if not collapsed, check the children */ @@ -1682,7 +1682,7 @@ int Tree::get_item_height(TreeItem *p_item) const { } void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color) { - ERR_FAIL_COND(cache.font.is_null()); + ERR_FAIL_COND(theme_cache.font.is_null()); Rect2i rect = p_rect; Size2 ts = p_cell.text_buf->get_size(); @@ -1694,7 +1694,7 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co if (p_cell.icon_max_w > 0 && bmsize.width > p_cell.icon_max_w) { bmsize.width = p_cell.icon_max_w; } - w += bmsize.width + cache.hseparation; + w += bmsize.width + theme_cache.hseparation; if (rect.size.width > 0 && (w + ts.width) > rect.size.width) { ts.width = rect.size.width - w; } @@ -1728,8 +1728,8 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color); } p_cell.text_buf->draw(ci, draw_pos, p_color); - rect.position.x += ts.width + cache.hseparation; - rect.size.x -= ts.width + cache.hseparation; + rect.position.x += ts.width + theme_cache.hseparation; + rect.size.x -= ts.width + theme_cache.hseparation; } if (!p_cell.icon.is_null()) { @@ -1741,8 +1741,8 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co } p_cell.draw_icon(ci, rect.position + Size2i(0, Math::floor((real_t)(rect.size.y - bmsize.y) / 2)), bmsize, p_icon_color); - rect.position.x += bmsize.x + cache.hseparation; - rect.size.x -= bmsize.x + cache.hseparation; + rect.position.x += bmsize.x + theme_cache.hseparation; + rect.size.x -= bmsize.x + theme_cache.hseparation; } if (!rtl) { @@ -1764,7 +1764,7 @@ void Tree::update_column(int p_col) { columns.write[p_col].text_buf->set_direction((TextServer::Direction)columns[p_col].text_direction); } - columns.write[p_col].text_buf->add_string(columns[p_col].title, cache.font, cache.font_size, columns[p_col].language); + columns.write[p_col].text_buf->add_string(columns[p_col].title, theme_cache.font, theme_cache.font_size, columns[p_col].language); } void Tree::update_item_cell(TreeItem *p_item, int p_col) { @@ -1813,14 +1813,14 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) { if (p_item->cells[p_col].custom_font.is_valid()) { font = p_item->cells[p_col].custom_font; } else { - font = cache.font; + font = theme_cache.font; } int font_size; if (p_item->cells[p_col].custom_font_size > 0) { font_size = p_item->cells[p_col].custom_font_size; } else { - font_size = cache.font_size; + font_size = theme_cache.font_size; } p_item->cells.write[p_col].text_buf->add_string(valtext, font, font_size, p_item->cells[p_col].language); TS->shaped_text_set_bidi_override(p_item->cells[p_col].text_buf->get_rid(), structured_text_parser(p_item->cells[p_col].st_parser, p_item->cells[p_col].st_args, valtext)); @@ -1840,7 +1840,7 @@ void Tree::update_item_cache(TreeItem *p_item) { } int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item) { - if (p_pos.y - cache.offset.y > (p_draw_size.height)) { + if (p_pos.y - theme_cache.offset.y > (p_draw_size.height)) { return -1; //draw no more! } @@ -1856,18 +1856,18 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 bool rtl = cache.rtl; /* Calculate height of the label part */ - label_h += cache.vseparation; + label_h += theme_cache.vseparation; /* Draw label, if height fits */ bool skip = (p_item == root && hide_root); - if (!skip && (p_pos.y + label_h - cache.offset.y) > 0) { + if (!skip && (p_pos.y + label_h - theme_cache.offset.y) > 0) { // Draw separation. - ERR_FAIL_COND_V(cache.font.is_null(), -1); + ERR_FAIL_COND_V(theme_cache.font.is_null(), -1); - int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); + int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.hseparation : theme_cache.item_margin); int skip2 = 0; for (int i = 0; i < columns.size(); i++) { if (skip2) { @@ -1885,8 +1885,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 continue; } } else { - ofs += cache.hseparation; - w -= cache.hseparation; + ofs += theme_cache.hseparation; + w -= theme_cache.hseparation; } if (p_item->cells[i].expand_right) { @@ -1902,10 +1902,10 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int button_w = 0; for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = p_item->cells[i].buttons[j].texture; - button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin; + button_w += b->get_size().width + theme_cache.button_pressed->get_minimum_size().width + theme_cache.button_margin; } - int total_ofs = ofs - cache.offset.x; + int total_ofs = ofs - theme_cache.offset.x; if (total_ofs + w > p_draw_size.width) { w = MAX(button_w, p_draw_size.width - total_ofs); @@ -1915,9 +1915,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int bw = 0; for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = p_item->cells[i].buttons[j].texture; - Size2 s = b->get_size() + cache.button_pressed->get_minimum_size(); + Size2 s = b->get_size() + theme_cache.button_pressed->get_minimum_size(); - Point2i o = Point2i(ofs + w - s.width, p_pos.y) - cache.offset + p_draw_ofs; + Point2i o = Point2i(ofs + w - s.width, p_pos.y) - theme_cache.offset + p_draw_ofs; if (cache.click_type == Cache::CLICK_BUTTON && cache.click_item == p_item && cache.click_column == i && cache.click_index == j && !p_item->cells[i].buttons[j].disabled) { // Being pressed. @@ -1925,48 +1925,48 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (rtl) { od.x = get_size().width - od.x - s.x; } - cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, s.width, MAX(s.height, label_h))); + theme_cache.button_pressed->draw(get_canvas_item(), Rect2(od.x, od.y, s.width, MAX(s.height, label_h))); } o.y += (label_h - s.height) / 2; - o += cache.button_pressed->get_offset(); + o += theme_cache.button_pressed->get_offset(); if (rtl) { o.x = get_size().width - o.x - b->get_width(); } b->draw(ci, o, p_item->cells[i].buttons[j].disabled ? Color(1, 1, 1, 0.5) : p_item->cells[i].buttons[j].color); - w -= s.width + cache.button_margin; - bw += s.width + cache.button_margin; + w -= s.width + theme_cache.button_margin; + bw += s.width + theme_cache.button_margin; } - Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - cache.offset + p_draw_ofs, Size2i(w, label_h)); + Rect2i item_rect = Rect2i(Point2i(ofs, p_pos.y) - theme_cache.offset + p_draw_ofs, Size2i(w, label_h)); Rect2i cell_rect = item_rect; if (i != 0) { - cell_rect.position.x -= cache.hseparation; - cell_rect.size.x += cache.hseparation; + cell_rect.position.x -= theme_cache.hseparation; + cell_rect.size.x += theme_cache.hseparation; } - if (cache.draw_guides) { + if (theme_cache.draw_guides) { Rect2 r = cell_rect; if (rtl) { r.position.x = get_size().width - r.position.x - r.size.x; } - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(r.position.x, r.position.y + r.size.height), r.position + r.size, cache.guide_color, 1); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(r.position.x, r.position.y + r.size.height), r.position + r.size, theme_cache.guide_color, 1); } if (i == 0) { if (p_item->cells[0].selected && select_mode == SELECT_ROW) { - Rect2i row_rect = Rect2i(Point2i(cache.bg->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - cache.bg->get_minimum_size().width, item_rect.size.y)); + Rect2i row_rect = Rect2i(Point2i(theme_cache.panel_style->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - theme_cache.panel_style->get_minimum_size().width, item_rect.size.y)); //Rect2 r = Rect2i(row_rect.pos,row_rect.size); //r.grow(cache.selected->get_margin(SIDE_LEFT)); if (rtl) { row_rect.position.x = get_size().width - row_rect.position.x - row_rect.size.x; } if (has_focus()) { - cache.selected_focus->draw(ci, row_rect); + theme_cache.selected_focus->draw(ci, row_rect); } else { - cache.selected->draw(ci, row_rect); + theme_cache.selected->draw(ci, row_rect); } } } @@ -1982,9 +1982,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } if (p_item->cells[i].selected) { if (has_focus()) { - cache.selected_focus->draw(ci, r); + theme_cache.selected_focus->draw(ci, r); } else { - cache.selected->draw(ci, r); + theme_cache.selected->draw(ci, r); } } } @@ -1996,8 +1996,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 r.position.x = p_draw_ofs.x; r.size.x = w + ofs; } else { - r.position.x -= cache.hseparation; - r.size.x += cache.hseparation; + r.position.x -= theme_cache.hseparation; + r.size.x += theme_cache.hseparation; } if (rtl) { r.position.x = get_size().width - r.position.x - r.size.x; @@ -2020,28 +2020,34 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (drop_mode_over == p_item) { if (drop_mode_section == 0 || drop_mode_section == -1) { // Line above. - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), theme_cache.drop_position_color); } if (drop_mode_section == 0) { // Side lines. - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), cache.drop_position_color); - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), cache.drop_position_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, 1, r.size.y), theme_cache.drop_position_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x + r.size.x - 1, r.position.y, 1, r.size.y), theme_cache.drop_position_color); } if (drop_mode_section == 0 || (drop_mode_section == 1 && (!p_item->get_first_child() || p_item->is_collapsed()))) { // Line below. - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), cache.drop_position_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y, r.size.x, 1), theme_cache.drop_position_color); } } else if (drop_mode_over == p_item->get_parent()) { if (drop_mode_section == 1 && !p_item->get_prev() /* && !drop_mode_over->is_collapsed() */) { // The drop_mode_over shouldn't ever be collapsed in here, otherwise we would be drawing a child of a collapsed item. // Line above. - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), cache.drop_position_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), theme_cache.drop_position_color); } } } - Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_selected_color" : "font_color"); - Color font_outline_color = cache.font_outline_color; - int outline_size = cache.font_outline_size; + Color col; + if (p_item->cells[i].custom_color) { + col = p_item->cells[i].color; + } else { + col = p_item->cells[i].selected ? theme_cache.font_selected_color : theme_cache.font_color; + } + + Color font_outline_color = theme_cache.font_outline_color; + int outline_size = theme_cache.font_outline_size; Color icon_col = p_item->cells[i].icon_color; if (p_item->cells[i].dirty) { @@ -2061,9 +2067,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color); } break; case TreeItem::CELL_MODE_CHECK: { - Ref<Texture2D> checked = cache.checked; - Ref<Texture2D> unchecked = cache.unchecked; - Ref<Texture2D> indeterminate = cache.indeterminate; + Ref<Texture2D> checked = theme_cache.checked; + Ref<Texture2D> unchecked = theme_cache.unchecked; + Ref<Texture2D> indeterminate = theme_cache.indeterminate; Point2i check_ofs = item_rect.position; check_ofs.y += Math::floor((real_t)(item_rect.size.y - checked->get_height()) / 2); @@ -2075,7 +2081,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 unchecked->draw(ci, check_ofs); } - int check_w = checked->get_width() + cache.hseparation; + int check_w = checked->get_width() + theme_cache.hseparation; text_pos.x += check_w; @@ -2091,7 +2097,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 break; } - Ref<Texture2D> downarrow = cache.select_arrow; + Ref<Texture2D> downarrow = theme_cache.select_arrow; int cell_width = item_rect.size.x - downarrow->get_width(); p_item->cells.write[i].text_buf->set_width(cell_width); @@ -2113,7 +2119,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 downarrow->draw(ci, arrow_pos); } else { - Ref<Texture2D> updown = cache.updown; + Ref<Texture2D> updown = theme_cache.updown; int cell_width = item_rect.size.x - updown->get_width(); @@ -2170,7 +2176,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 break; } - Ref<Texture2D> downarrow = cache.select_arrow; + Ref<Texture2D> downarrow = theme_cache.select_arrow; Rect2i ir = item_rect; @@ -2182,16 +2188,16 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (p_item->cells[i].custom_button) { if (cache.hover_item == p_item && cache.hover_cell == i) { if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { - draw_style_box(cache.custom_button_pressed, ir); + draw_style_box(theme_cache.custom_button_pressed, ir); } else { - draw_style_box(cache.custom_button_hover, ir); - col = cache.custom_button_font_highlight; + draw_style_box(theme_cache.custom_button_hover, ir); + col = theme_cache.custom_button_font_highlight; } } else { - draw_style_box(cache.custom_button, ir); + draw_style_box(theme_cache.custom_button, ir); } - ir.size -= cache.custom_button->get_minimum_size(); - ir.position += cache.custom_button->get_offset(); + ir.size -= theme_cache.custom_button->get_minimum_size(); + ir.position += theme_cache.custom_button->get_offset(); } draw_item_rect(p_item->cells.write[i], ir, col, icon_col, outline_size, font_outline_color); @@ -2212,9 +2218,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 cell_rect.position.x = get_size().width - cell_rect.position.x - cell_rect.size.x; } if (has_focus()) { - cache.cursor->draw(ci, cell_rect); + theme_cache.cursor->draw(ci, cell_rect); } else { - cache.cursor_unfocus->draw(ci, cell_rect); + theme_cache.cursor_unfocus->draw(ci, cell_rect); } } } @@ -2224,13 +2230,17 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 Ref<Texture2D> arrow; if (p_item->collapsed) { - arrow = cache.arrow_collapsed; + if (is_layout_rtl()) { + arrow = theme_cache.arrow_collapsed_mirrored; + } else { + arrow = theme_cache.arrow_collapsed; + } } else { - arrow = cache.arrow; + arrow = theme_cache.arrow; } - Point2 apos = p_pos + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset + p_draw_ofs; - apos.x += cache.item_margin - arrow->get_width(); + Point2 apos = p_pos + Point2i(0, (label_h - arrow->get_height()) / 2) - theme_cache.offset + p_draw_ofs; + apos.x += theme_cache.item_margin - arrow->get_width(); if (rtl) { apos.x = get_size().width - apos.x - arrow->get_width(); @@ -2243,7 +2253,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 Point2 children_pos = p_pos; if (!skip) { - children_pos.x += cache.item_margin; + children_pos.x += theme_cache.item_margin; htotal += label_h; children_pos.y += htotal; } @@ -2251,7 +2261,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (!p_item->collapsed) { /* if not collapsed, check the children */ TreeItem *c = p_item->first_child; - int base_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y; + int base_ofs = children_pos.y - theme_cache.offset.y + p_draw_ofs.y; int prev_ofs = base_ofs; int prev_hl_ofs = base_ofs; @@ -2262,20 +2272,20 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } // Draw relationship lines. - if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) { - int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); - int parent_ofs = p_pos.x + cache.item_margin; - Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; + if (theme_cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root) && c->is_visible()) { + int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? theme_cache.hseparation : theme_cache.item_margin); + int parent_ofs = p_pos.x + theme_cache.item_margin; + Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - theme_cache.offset + p_draw_ofs; if (c->get_visible_child_count() > 0) { - root_pos -= Point2i(cache.arrow->get_width(), 0); + root_pos -= Point2i(theme_cache.arrow->get_width(), 0); } - float line_width = cache.relationship_line_width * Math::round(cache.base_scale); - float parent_line_width = cache.parent_hl_line_width * Math::round(cache.base_scale); - float children_line_width = cache.children_hl_line_width * Math::round(cache.base_scale); + float line_width = theme_cache.relationship_line_width * Math::round(theme_cache.base_scale); + float parent_line_width = theme_cache.parent_hl_line_width * Math::round(theme_cache.base_scale); + float children_line_width = theme_cache.children_hl_line_width * Math::round(theme_cache.base_scale); - Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; + Point2i parent_pos = Point2i(parent_ofs - theme_cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + theme_cache.arrow->get_height() / 2) - theme_cache.offset + p_draw_ofs; int more_prev_ofs = 0; @@ -2289,43 +2299,43 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (_is_branch_selected(c)) { // If this item or one of its children is selected, we draw the line using parent highlight style. if (htotal >= 0) { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), theme_cache.parent_hl_line_color, parent_line_width); } - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), theme_cache.parent_hl_line_color, parent_line_width); - more_prev_ofs = cache.parent_hl_line_margin; + more_prev_ofs = theme_cache.parent_hl_line_margin; prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); } else if (p_item->is_selected(0)) { // If parent item is selected (but this item is not), we draw the line using children highlight style. // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. if (_is_sibling_branch_selected(c)) { if (htotal >= 0) { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), theme_cache.children_hl_line_color, children_line_width); } - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), theme_cache.parent_hl_line_color, parent_line_width); prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); } else { if (htotal >= 0) { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), theme_cache.children_hl_line_color, children_line_width); } - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), theme_cache.children_hl_line_color, children_line_width); } } else { // If nothing of the above is true, we draw the line using normal style. // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. if (_is_sibling_branch_selected(c)) { if (htotal >= 0) { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + theme_cache.parent_hl_line_margin, root_pos.y), theme_cache.relationship_line_color, line_width); } - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), theme_cache.parent_hl_line_color, parent_line_width); prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); } else { if (htotal >= 0) { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), theme_cache.relationship_line_color, line_width); } - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), theme_cache.relationship_line_color, line_width); } } } @@ -2338,12 +2348,12 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 break; // Last loop done, stop. } - if (cache.draw_relationship_lines == 0) { + if (theme_cache.draw_relationship_lines == 0) { return -1; // No need to draw anymore, full stop. } htotal = -1; - children_pos.y = cache.offset.y + p_draw_size.height; + children_pos.y = theme_cache.offset.y + p_draw_size.height; } else { htotal += child_h; children_pos.y += child_h; @@ -2494,7 +2504,7 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) { void Tree::_range_click_timeout() { if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { - Point2 pos = get_local_mouse_position() - cache.bg->get_offset(); + Point2 pos = get_local_mouse_position() - theme_cache.panel_style->get_offset(); if (show_column_titles) { pos.y -= _get_title_button_height(); @@ -2512,7 +2522,7 @@ void Tree::_range_click_timeout() { Ref<InputEventMouseButton> mb; mb.instantiate(); - int x_limit = get_size().width - cache.bg->get_minimum_size().width; + int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width; if (h_scroll->is_visible()) { x_limit -= h_scroll->get_minimum_size().width; } @@ -2521,7 +2531,7 @@ void Tree::_range_click_timeout() { propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case) blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, false, root, MouseButton::LEFT, mb); + propagate_mouse_event(pos + theme_cache.offset, 0, 0, x_limit + theme_cache.offset.width, false, root, MouseButton::LEFT, mb); blocked--; if (range_click_timer->is_one_shot()) { @@ -2550,7 +2560,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int return 0; } - int item_h = compute_item_height(p_item) + cache.vseparation; + int item_h = compute_item_height(p_item) + theme_cache.vseparation; bool skip = (p_item == root && hide_root); @@ -2561,7 +2571,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int return -1; } - if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) { + if (!p_item->disable_folding && !hide_folding && p_item->first_child && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + theme_cache.item_margin))) { p_item->set_collapsed(!p_item->is_collapsed()); return -1; } @@ -2580,7 +2590,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int if (p_item->cells[i].expand_right) { int plus = 1; while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text.is_empty() && p_item->cells[i + plus].icon.is_null()) { - col_width += cache.hseparation; + col_width += theme_cache.hseparation; col_width += get_column_width(i + plus); plus++; } @@ -2600,16 +2610,16 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int if (col == -1) { return -1; } else if (col == 0) { - int margin = x_ofs + cache.item_margin; //-cache.hseparation; - //int lm = cache.bg->get_margin(SIDE_LEFT); + int margin = x_ofs + theme_cache.item_margin; //-theme_cache.hseparation; + //int lm = theme_cache.panel_style->get_margin(SIDE_LEFT); col_width -= margin; limit_w -= margin; col_ofs += margin; x -= margin; } else { - col_width -= cache.hseparation; - limit_w -= cache.hseparation; - x -= cache.hseparation; + col_width -= theme_cache.hseparation; + limit_w -= theme_cache.hseparation; + x -= theme_cache.hseparation; } if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_first_child()) { @@ -2626,7 +2636,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int int button_w = 0; for (int j = p_item->cells[col].buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = p_item->cells[col].buttons[j].texture; - button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin; + button_w += b->get_size().width + theme_cache.button_pressed->get_minimum_size().width + theme_cache.button_margin; } col_width = MAX(button_w, MIN(limit_w, col_width)); @@ -2634,7 +2644,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = c.buttons[j].texture; - int w = b->get_size().width + cache.button_pressed->get_minimum_size().width; + int w = b->get_size().width + theme_cache.button_pressed->get_minimum_size().width; if (x > col_width - w) { if (c.buttons[j].disabled) { @@ -2658,11 +2668,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int cache.click_item = p_item; cache.click_column = col; cache.click_pos = click_pos; - update(); + queue_redraw(); return -1; } - col_width -= w + cache.button_margin; + col_width -= w + theme_cache.button_margin; } if (p_button == MouseButton::LEFT || (p_button == MouseButton::RIGHT && allow_rmb_select)) { @@ -2676,7 +2686,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int return -1; } - if (select_mode == SELECT_MULTI && p_mod->is_command_pressed() && c.selectable) { + if (select_mode == SELECT_MULTI && p_mod->is_command_or_control_pressed() && c.selectable) { if (!c.selected || p_button == MouseButton::RIGHT) { p_item->select(col); emit_signal(SNAME("multi_selected"), p_item, col, true); @@ -2716,7 +2726,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int emit_signal(SNAME("multi_selected"),p_item,col,true); } */ - update(); + queue_redraw(); } } } @@ -2742,7 +2752,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int case TreeItem::CELL_MODE_CHECK: { bring_up_editor = false; //checkboxes are not edited with editor if (force_edit_checkbox_only_on_checkbox) { - if (x < cache.checked->get_width()) { + if (x < theme_cache.checked->get_width()) { p_item->set_checked(col, !c.checked); item_edited(col, p_item, p_button); } @@ -2764,7 +2774,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int } popup_menu->set_size(Size2(col_width, 0)); - popup_menu->set_position(get_screen_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h) - cache.offset); + popup_menu->set_position(get_screen_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h) - theme_cache.offset); popup_menu->popup(); popup_edited_item = p_item; popup_edited_item_col = col; @@ -2822,9 +2832,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int case TreeItem::CELL_MODE_CUSTOM: { edited_item = p_item; edited_col = col; - bool on_arrow = x > col_width - cache.select_arrow->get_width(); + bool on_arrow = x > col_width - theme_cache.select_arrow->get_width(); - custom_popup_rect = Rect2i(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h - cache.offset.y), Size2(get_column_width(col), item_h)); + custom_popup_rect = Rect2i(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs + item_h - theme_cache.offset.y), Size2(get_column_width(col), item_h)); if (on_arrow || !p_item->cells[col].custom_button) { emit_signal(SNAME("custom_popup_edited"), ((bool)(x >= (col_width - item_h / 2)))); @@ -2846,7 +2856,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int popup_pressing_edited_item = p_item; popup_pressing_edited_item_column = col; - pressing_item_rect = Rect2(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs) - cache.offset, Size2(col_width, item_h)); + pressing_item_rect = Rect2(get_global_position() + Point2i(col_ofs, _get_title_button_height() + y_ofs) - theme_cache.offset, Size2(col_width, item_h)); pressing_for_editor_text = editor_text; pressing_for_editor = true; @@ -2855,8 +2865,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int Point2i new_pos = p_pos; if (!skip) { - x_ofs += cache.item_margin; - //new_pos.x-=cache.item_margin; + x_ofs += theme_cache.item_margin; + //new_pos.x-=theme_cache.item_margin; y_ofs += item_h; new_pos.y -= item_h; } @@ -2935,7 +2945,7 @@ void Tree::_text_editor_submit(String p_text) { } item_edited(popup_edited_item_col, popup_edited_item); - update(); + queue_redraw(); } void Tree::value_editor_changed(double p_value) { @@ -2952,7 +2962,7 @@ void Tree::value_editor_changed(double p_value) { text_editor->set_text(String::num(c.val, Math::range_step_decimals(c.step))); item_edited(popup_edited_item_col, popup_edited_item); - update(); + queue_redraw(); } void Tree::popup_select(int p_option) { @@ -2966,7 +2976,7 @@ void Tree::popup_select(int p_option) { popup_edited_item->cells.write[popup_edited_item_col].val = p_option; //popup_edited_item->edited_signal.call( popup_edited_item_col ); - update(); + queue_redraw(); item_edited(popup_edited_item_col, popup_edited_item); } @@ -2993,7 +3003,7 @@ void Tree::_go_left() { selected_item->select(selected_col - 1); } } - update(); + queue_redraw(); accept_event(); ensure_cursor_is_visible(); } @@ -3014,7 +3024,7 @@ void Tree::_go_right() { selected_item->select(selected_col + 1); } } - update(); + queue_redraw(); ensure_cursor_is_visible(); accept_event(); } @@ -3043,7 +3053,7 @@ void Tree::_go_up() { } selected_item = prev; emit_signal(SNAME("cell_selected")); - update(); + queue_redraw(); } else { int col = selected_col < 0 ? 0 : selected_col; while (prev && !prev->cells[col].selectable) { @@ -3086,7 +3096,7 @@ void Tree::_go_down() { selected_item = next; emit_signal(SNAME("cell_selected")); - update(); + queue_redraw(); } else { int col = selected_col < 0 ? 0 : selected_col; @@ -3117,7 +3127,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; - bool is_command = k.is_valid() && k->is_command_pressed(); + bool is_command = k.is_valid() && k->is_command_or_control_pressed(); if (p_event->is_action("ui_right") && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); @@ -3196,7 +3206,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (select_mode == SELECT_MULTI) { selected_item = next; emit_signal(SNAME("cell_selected")); - update(); + queue_redraw(); } else { while (next && !next->cells[selected_col].selectable) { next = next->get_next_visible(); @@ -3234,7 +3244,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (select_mode == SELECT_MULTI) { selected_item = prev; emit_signal(SNAME("cell_selected")); - update(); + queue_redraw(); } else { while (prev && !prev->cells[selected_col].selectable) { prev = prev->get_prev_visible(); @@ -3275,7 +3285,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (!k->is_pressed()) { return; } - if (k->is_command_pressed() || (k->is_shift_pressed() && k->get_unicode() == 0) || k->is_meta_pressed()) { + if (k->is_command_or_control_pressed() || (k->is_shift_pressed() && k->get_unicode() == 0) || k->is_meta_pressed()) { return; } if (!root) { @@ -3300,18 +3310,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff - update_cache(); - } - - Ref<StyleBox> bg = cache.bg; + Ref<StyleBox> bg = theme_cache.panel_style; bool rtl = is_layout_rtl(); Point2 pos = mm->get_position(); if (rtl) { pos.x = get_size().width - pos.x; } - pos -= cache.bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); Cache::ClickType old_hover = cache.hover_type; int old_index = cache.hover_index; @@ -3321,7 +3327,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (show_column_titles) { pos.y -= _get_title_button_height(); if (pos.y < 0) { - pos.x += cache.offset.x; + pos.x += theme_cache.offset.x; int len = 0; for (int i = 0; i < columns.size(); i++) { len += get_column_width(i); @@ -3339,7 +3345,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (rtl) { mpos.x = get_size().width - mpos.x; } - mpos -= cache.bg->get_offset(); + mpos -= theme_cache.panel_style->get_offset(); mpos.y -= _get_title_button_height(); if (mpos.y >= 0) { if (h_scroll->is_visible_in_tree()) { @@ -3358,11 +3364,11 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (drop_mode_flags) { if (it != drop_mode_over) { drop_mode_over = it; - update(); + queue_redraw(); } if (it && section != drop_mode_section) { drop_mode_section = section; - update(); + queue_redraw(); } } @@ -3371,14 +3377,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (it != old_it || col != old_col) { if (old_it && old_col >= old_it->cells.size()) { - // Columns may have changed since last update(). - update(); + // Columns may have changed since last redraw(). + queue_redraw(); } else { // Only need to update if mouse enters/exits a button bool was_over_button = old_it && old_it->cells[old_col].custom_button; bool is_over_button = it && it->cells[col].custom_button; if (was_over_button || is_over_button) { - update(); + queue_redraw(); } } } @@ -3387,7 +3393,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { // Update if mouse enters/exits columns if (cache.hover_type != old_hover || cache.hover_index != old_index) { - update(); + queue_redraw(); } if (pressing_for_editor && popup_pressing_edited_item && (popup_pressing_edited_item->get_cell_mode(popup_pressing_edited_item_column) == TreeItem::CELL_MODE_RANGE)) { @@ -3430,10 +3436,6 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff - update_cache(); - } - bool rtl = is_layout_rtl(); if (!mb->is_pressed()) { @@ -3443,12 +3445,12 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { if (rtl) { pos.x = get_size().width - pos.x; } - pos -= cache.bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); if (show_column_titles) { pos.y -= _get_title_button_height(); if (pos.y < 0) { - pos.x += cache.offset.x; + pos.x += theme_cache.offset.x; int len = 0; for (int i = 0; i < columns.size(); i++) { len += get_column_width(i); @@ -3526,7 +3528,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { cache.click_id = -1; cache.click_item = nullptr; cache.click_column = 0; - update(); + queue_redraw(); return; } @@ -3537,7 +3539,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { switch (mb->get_button_index()) { case MouseButton::RIGHT: case MouseButton::LEFT: { - Ref<StyleBox> bg = cache.bg; + Ref<StyleBox> bg = theme_cache.panel_style; Point2 pos = mb->get_position(); if (rtl) { @@ -3549,14 +3551,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { pos.y -= _get_title_button_height(); if (pos.y < 0) { - pos.x += cache.offset.x; + pos.x += theme_cache.offset.x; int len = 0; for (int i = 0; i < columns.size(); i++) { len += get_column_width(i); if (pos.x < static_cast<real_t>(len)) { cache.click_type = Cache::CLICK_TITLE; cache.click_index = i; - update(); + queue_redraw(); break; } } @@ -3572,14 +3574,14 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { pressing_for_editor = false; propagate_mouse_activated = false; - int x_limit = get_size().width - cache.bg->get_minimum_size().width; + int x_limit = get_size().width - theme_cache.panel_style->get_minimum_size().width; if (h_scroll->is_visible()) { x_limit -= h_scroll->get_minimum_size().width; } cache.rtl = is_layout_rtl(); blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, mb->is_double_click(), root, mb->get_button_index(), mb); + propagate_mouse_event(pos + theme_cache.offset, 0, 0, x_limit + theme_cache.offset.width, mb->is_double_click(), root, mb->get_button_index(), mb); blocked--; if (pressing_for_editor) { @@ -3613,7 +3615,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } if (mb->get_button_index() == MouseButton::LEFT) { - if (get_item_at_position(mb->get_position()) == nullptr && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && !mb->is_command_pressed()) { + if (get_item_at_position(mb->get_position()) == nullptr && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && !mb->is_command_or_control_pressed()) { emit_signal(SNAME("nothing_selected")); } } @@ -3766,7 +3768,7 @@ bool Tree::is_editing() { } Size2 Tree::get_internal_min_size() const { - Size2i size = cache.bg->get_offset(); + Size2i size = theme_cache.panel_style->get_offset(); if (root) { size.height += get_item_height(root); } @@ -3789,23 +3791,23 @@ void Tree::update_scrollbars() { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - v_scroll->set_begin(Point2(size.width - vmin.width, cache.bg->get_margin(SIDE_TOP))); - v_scroll->set_end(Point2(size.width, size.height - cache.bg->get_margin(SIDE_TOP) - cache.bg->get_margin(SIDE_BOTTOM))); + v_scroll->set_begin(Point2(size.width - vmin.width, theme_cache.panel_style->get_margin(SIDE_TOP))); + v_scroll->set_end(Point2(size.width, size.height - theme_cache.panel_style->get_margin(SIDE_TOP) - theme_cache.panel_style->get_margin(SIDE_BOTTOM))); h_scroll->set_begin(Point2(0, size.height - hmin.height)); h_scroll->set_end(Point2(size.width - vmin.width, size.height)); Size2 internal_min_size = get_internal_min_size(); - bool display_vscroll = internal_min_size.height + cache.bg->get_margin(SIDE_TOP) > size.height; - bool display_hscroll = internal_min_size.width + cache.bg->get_margin(SIDE_LEFT) > size.width; + bool display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) > size.height; + bool display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) > size.width; for (int i = 0; i < 2; i++) { // Check twice, as both values are dependent on each other. if (display_hscroll) { - display_vscroll = internal_min_size.height + cache.bg->get_margin(SIDE_TOP) + hmin.height > size.height; + display_vscroll = internal_min_size.height + theme_cache.panel_style->get_margin(SIDE_TOP) + hmin.height > size.height; } if (display_vscroll) { - display_hscroll = internal_min_size.width + cache.bg->get_margin(SIDE_LEFT) + vmin.width > size.width; + display_hscroll = internal_min_size.width + theme_cache.panel_style->get_margin(SIDE_LEFT) + vmin.width > size.width; } } @@ -3813,29 +3815,29 @@ void Tree::update_scrollbars() { v_scroll->show(); v_scroll->set_max(internal_min_size.height); v_scroll->set_page(size.height - hmin.height - tbh); - cache.offset.y = v_scroll->get_value(); + theme_cache.offset.y = v_scroll->get_value(); } else { v_scroll->hide(); - cache.offset.y = 0; + theme_cache.offset.y = 0; } if (display_hscroll) { h_scroll->show(); h_scroll->set_max(internal_min_size.width); h_scroll->set_page(size.width - vmin.width); - cache.offset.x = h_scroll->get_value(); + theme_cache.offset.x = h_scroll->get_value(); } else { h_scroll->hide(); - cache.offset.x = 0; + theme_cache.offset.x = 0; } } int Tree::_get_title_button_height() const { - ERR_FAIL_COND_V(cache.font.is_null() || cache.title_button.is_null(), 0); + ERR_FAIL_COND_V(theme_cache.font.is_null() || theme_cache.title_button.is_null(), 0); int h = 0; if (show_column_titles) { for (int i = 0; i < columns.size(); i++) { - h = MAX(h, columns[i].text_buf->get_size().y + cache.title_button->get_minimum_size().height); + h = MAX(h, columns[i].text_buf->get_size().y + theme_cache.title_button->get_minimum_size().height); } } return h; @@ -3852,7 +3854,7 @@ void Tree::_notification(int p_what) { case NOTIFICATION_MOUSE_EXIT: { if (cache.hover_type != Cache::CLICK_NONE) { cache.hover_type = Cache::CLICK_NONE; - update(); + queue_redraw(); } } break; @@ -3860,20 +3862,16 @@ void Tree::_notification(int p_what) { drag_touching = false; } break; - case NOTIFICATION_ENTER_TREE: { - update_cache(); - } break; - case NOTIFICATION_DRAG_END: { drop_mode_flags = 0; scrolling = false; set_physics_process_internal(false); - update(); + queue_redraw(); } break; case NOTIFICATION_DRAG_BEGIN: { single_select_defer = nullptr; - if (cache.scroll_speed > 0) { + if (theme_cache.scroll_speed > 0) { scrolling = true; set_physics_process_internal(true); } @@ -3917,22 +3915,22 @@ void Tree::_notification(int p_what) { } Point2 mouse_position = get_viewport()->get_mouse_position() - get_global_position(); - if (scrolling && get_rect().grow(cache.scroll_border).has_point(mouse_position)) { + if (scrolling && get_rect().grow(theme_cache.scroll_border).has_point(mouse_position)) { Point2 point; - 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); + if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < theme_cache.scroll_border)) { + point.x = mouse_position.x - theme_cache.scroll_border; + } else if (ABS(mouse_position.x - get_size().width) < theme_cache.scroll_border) { + point.x = mouse_position.x - (get_size().width - theme_cache.scroll_border); } - 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 ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < theme_cache.scroll_border)) { + point.y = mouse_position.y - theme_cache.scroll_border; + } else if (ABS(mouse_position.y - get_size().height) < theme_cache.scroll_border) { + point.y = mouse_position.y - (get_size().height - theme_cache.scroll_border); } - point *= cache.scroll_speed * get_physics_process_delta_time(); + point *= theme_cache.scroll_speed * get_physics_process_delta_time(); point += get_scroll(); h_scroll->set_value(point.x); v_scroll->set_value(point.y); @@ -3940,13 +3938,12 @@ void Tree::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - update_cache(); + v_scroll->set_custom_step(theme_cache.font->get_height(theme_cache.font_size)); + 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")); + Ref<StyleBox> bg = theme_cache.panel_style; Point2 draw_ofs; draw_ofs += bg->get_offset(); @@ -3970,11 +3967,11 @@ void Tree::_notification(int p_what) { if (show_column_titles) { //title buttons - int ofs2 = cache.bg->get_margin(SIDE_LEFT); + int ofs2 = theme_cache.panel_style->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); + Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? theme_cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? theme_cache.title_button_hover : theme_cache.title_button); + Ref<Font> f = theme_cache.tb_font; + Rect2 tbrect = Rect2(ofs2 - theme_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; } @@ -3985,19 +3982,18 @@ void Tree::_notification(int p_what) { 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); + if (theme_cache.font_outline_size > 0 && theme_cache.font_outline_color.a > 0) { + columns[i].text_buf->draw_outline(ci, text_pos, theme_cache.font_outline_size, theme_cache.font_outline_color); } - columns[i].text_buf->draw(ci, text_pos, cache.title_button_color); + columns[i].text_buf->draw(ci, text_pos, theme_cache.title_button_color); } } - // Draw the background focus outline last, so that it is drawn in front of the section headings. + // Draw the 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())); + theme_cache.focus_style->draw(ci, Rect2(Point2(), get_size())); RenderingServer::get_singleton()->canvas_item_add_clip_ignore(ci, false); } } break; @@ -4005,7 +4001,6 @@ void Tree::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { - update_cache(); _update_all(); } break; @@ -4040,7 +4035,7 @@ Size2 Tree::get_minimum_size() const { return Size2(); } else { Vector2 min_size = get_internal_min_size(); - Ref<StyleBox> bg = cache.bg; + Ref<StyleBox> bg = theme_cache.panel_style; if (bg.is_valid()) { min_size.x += bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT); min_size.y += bg->get_margin(SIDE_TOP) + bg->get_margin(SIDE_BOTTOM); @@ -4110,7 +4105,7 @@ void Tree::item_changed(int p_column, TreeItem *p_item) { if (p_item != nullptr && p_column >= 0 && p_column < p_item->cells.size()) { p_item->cells.write[p_column].dirty = true; } - update(); + queue_redraw(); } void Tree::item_selected(int p_column, TreeItem *p_item) { @@ -4129,7 +4124,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) { } else { select_single_item(p_item, root, p_column); } - update(); + queue_redraw(); } void Tree::item_deselected(int p_column, TreeItem *p_item) { @@ -4144,7 +4139,7 @@ void Tree::item_deselected(int p_column, TreeItem *p_item) { if (select_mode == SELECT_MULTI || select_mode == SELECT_SINGLE) { p_item->cells.write[p_column].selected = false; } - update(); + queue_redraw(); } void Tree::set_select_mode(SelectMode p_mode) { @@ -4167,7 +4162,7 @@ void Tree::deselect_all() { selected_item = nullptr; selected_col = -1; - update(); + queue_redraw(); } bool Tree::is_anything_selected() { @@ -4196,7 +4191,7 @@ void Tree::clear() { popup_edited_item = nullptr; popup_pressing_edited_item = nullptr; - update(); + queue_redraw(); }; void Tree::set_hide_root(bool p_enabled) { @@ -4205,7 +4200,7 @@ void Tree::set_hide_root(bool p_enabled) { } hide_root = p_enabled; - update(); + queue_redraw(); } bool Tree::is_root_hidden() const { @@ -4223,7 +4218,7 @@ void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) { return; } columns.write[p_column].custom_min_width = p_min_width; - update(); + queue_redraw(); } void Tree::set_column_expand(int p_column, bool p_expand) { @@ -4234,7 +4229,7 @@ void Tree::set_column_expand(int p_column, bool p_expand) { } columns.write[p_column].expand = p_expand; - update(); + queue_redraw(); } void Tree::set_column_expand_ratio(int p_column, int p_ratio) { @@ -4245,7 +4240,7 @@ void Tree::set_column_expand_ratio(int p_column, int p_ratio) { } columns.write[p_column].expand_ratio = p_ratio; - update(); + queue_redraw(); } void Tree::set_column_clip_content(int p_column, bool p_fit) { @@ -4256,7 +4251,7 @@ void Tree::set_column_clip_content(int p_column, bool p_fit) { } columns.write[p_column].clip_content = p_fit; - update(); + queue_redraw(); } bool Tree::is_column_expanding(int p_column) const { @@ -4336,7 +4331,7 @@ int Tree::get_column_minimum_width(int p_column) const { // Check if the visible title of the column is wider. if (show_column_titles) { - min_width = MAX(cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, cache.font_size).width + cache.bg->get_margin(SIDE_LEFT) + cache.bg->get_margin(SIDE_RIGHT), min_width); + min_width = MAX(theme_cache.font->get_string_size(columns[p_column].title, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + theme_cache.panel_style->get_margin(SIDE_LEFT) + theme_cache.panel_style->get_margin(SIDE_RIGHT), min_width); } if (!columns[p_column].clip_content) { @@ -4360,9 +4355,9 @@ int Tree::get_column_minimum_width(int p_column) const { // Get the item minimum size. Size2 item_size = item->get_minimum_size(p_column); if (p_column == 0) { - item_size.width += cache.item_margin * depth; + item_size.width += theme_cache.item_margin * depth; } else { - item_size.width += cache.hseparation; + item_size.width += theme_cache.hseparation; } // Check if the item is wider. @@ -4381,7 +4376,7 @@ int Tree::get_column_width(int p_column) const { if (columns[p_column].expand) { int expand_area = get_size().width; - Ref<StyleBox> bg = cache.bg; + Ref<StyleBox> bg = theme_cache.panel_style; if (bg.is_valid()) { expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT); @@ -4429,7 +4424,7 @@ void Tree::set_columns(int p_columns) { if (selected_col >= p_columns) { selected_col = p_columns - 1; } - update(); + queue_redraw(); } int Tree::get_columns() const { @@ -4437,7 +4432,7 @@ int Tree::get_columns() const { } void Tree::_scroll_moved(float) { - update(); + queue_redraw(); } Rect2 Tree::get_custom_popup_rect() const { @@ -4458,7 +4453,7 @@ int Tree::get_item_offset(TreeItem *p_item) const { ofs += compute_item_height(it); if (it != root || !hide_root) { - ofs += cache.vseparation; + ofs += theme_cache.vseparation; } if (it->first_child && !it->collapsed) { @@ -4489,14 +4484,14 @@ void Tree::ensure_cursor_is_visible() { return; // Nothing under cursor. } - const Size2 area_size = get_size() - cache.bg->get_minimum_size(); + const Size2 area_size = get_size() - theme_cache.panel_style->get_minimum_size(); int y_offset = get_item_offset(selected_item); if (y_offset != -1) { const int tbh = _get_title_button_height(); y_offset -= tbh; - const int cell_h = compute_item_height(selected_item) + cache.vseparation; + const int cell_h = compute_item_height(selected_item) + theme_cache.vseparation; const int screen_h = area_size.height - h_scroll->get_combined_minimum_size().height - tbh; if (cell_h > screen_h) { // Screen size is too small, maybe it was not resized yet. @@ -4563,7 +4558,7 @@ Rect2 Tree::get_item_rect(TreeItem *p_item, int p_column, int p_button) const { Vector2 ofst = Vector2(r.position.x + r.size.x, r.position.y); for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = c.buttons[j].texture; - Size2 size = b->get_size() + cache.button_pressed->get_minimum_size(); + Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size(); ofst.x -= size.x; if (j == p_button) { @@ -4582,7 +4577,7 @@ void Tree::set_column_titles_visible(bool p_show) { } show_column_titles = p_show; - update(); + queue_redraw(); } bool Tree::are_column_titles_visible() const { @@ -4596,12 +4591,9 @@ void Tree::set_column_title(int p_column, const String &p_title) { return; } - if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff - update_cache(); - } columns.write[p_column].title = p_title; update_column(p_column); - update(); + queue_redraw(); } String Tree::get_column_title(int p_column) const { @@ -4615,7 +4607,7 @@ void Tree::set_column_title_direction(int p_column, Control::TextDirection p_tex if (columns[p_column].text_direction != p_text_direction) { columns.write[p_column].text_direction = p_text_direction; update_column(p_column); - update(); + queue_redraw(); } } @@ -4629,7 +4621,7 @@ void Tree::set_column_title_language(int p_column, const String &p_language) { if (columns[p_column].language != p_language) { columns.write[p_column].language = p_language; update_column(p_column); - update(); + queue_redraw(); } } @@ -4660,7 +4652,7 @@ void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) { const real_t tree_height = get_size().y; const Rect2 item_rect = get_item_rect(p_item); const real_t item_y = item_rect.position.y; - const real_t item_height = item_rect.size.y + cache.vseparation; + const real_t item_height = item_rect.size.y + theme_cache.vseparation; if (p_center_on_item) { v_scroll->set_value(item_y - (tree_height - item_height) / 2.0f); @@ -4784,7 +4776,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_ Point2 pos = p_pos; if ((root != p_item || !hide_root) && p_item->is_visible()) { - h = compute_item_height(p_item) + cache.vseparation; + h = compute_item_height(p_item) + theme_cache.vseparation; if (pos.y < h) { if (drop_mode_flags == DROP_MODE_ON_ITEM) { section = 0; @@ -4841,7 +4833,7 @@ int Tree::get_column_at_position(const Point2 &p_pos) const { if (is_layout_rtl()) { pos.x = get_size().width - pos.x; } - pos -= cache.bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y -= _get_title_button_height(); if (pos.y < 0) { return -1; @@ -4871,7 +4863,7 @@ int Tree::get_drop_section_at_position(const Point2 &p_pos) const { if (is_layout_rtl()) { pos.x = get_size().width - pos.x; } - pos -= cache.bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y -= _get_title_button_height(); if (pos.y < 0) { return -100; @@ -4901,7 +4893,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const { if (is_layout_rtl()) { pos.x = get_size().width - pos.x; } - pos -= cache.bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y -= _get_title_button_height(); if (pos.y < 0) { return nullptr; @@ -4928,7 +4920,7 @@ TreeItem *Tree::get_item_at_position(const Point2 &p_pos) const { int Tree::get_button_id_at_position(const Point2 &p_pos) const { if (root) { Point2 pos = p_pos; - pos -= cache.bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y -= _get_title_button_height(); if (pos.y < 0) { return -1; @@ -4954,7 +4946,7 @@ int Tree::get_button_id_at_position(const Point2 &p_pos) const { for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = c.buttons[j].texture; - Size2 size = b->get_size() + cache.button_pressed->get_minimum_size(); + Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size(); if (pos.x > col_width - size.width) { return c.buttons[j].id; } @@ -4969,7 +4961,7 @@ int Tree::get_button_id_at_position(const Point2 &p_pos) const { String Tree::get_tooltip(const Point2 &p_pos) const { if (root) { Point2 pos = p_pos; - pos -= cache.bg->get_offset(); + pos -= theme_cache.panel_style->get_offset(); pos.y -= _get_title_button_height(); if (pos.y < 0) { return Control::get_tooltip(p_pos); @@ -4995,7 +4987,7 @@ String Tree::get_tooltip(const Point2 &p_pos) const { for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = c.buttons[j].texture; - Size2 size = b->get_size() + cache.button_pressed->get_minimum_size(); + Size2 size = b->get_size() + theme_cache.button_pressed->get_minimum_size(); if (pos.x > col_width - size.width) { String tooltip = c.buttons[j].tooltip; if (!tooltip.is_empty()) { @@ -5005,10 +4997,10 @@ String Tree::get_tooltip(const Point2 &p_pos) const { col_width -= size.width; } String ret; - if (it->get_tooltip(col) == "") { + if (it->get_tooltip_text(col) == "") { ret = it->get_text(col); } else { - ret = it->get_tooltip(col); + ret = it->get_tooltip_text(col); } return ret; } @@ -5027,7 +5019,7 @@ void Tree::set_hide_folding(bool p_hide) { } hide_folding = p_hide; - update(); + queue_redraw(); } bool Tree::is_folding_hidden() const { @@ -5043,7 +5035,7 @@ void Tree::set_drop_mode_flags(int p_flags) { drop_mode_over = nullptr; } - update(); + queue_redraw(); } int Tree::get_drop_mode_flags() const { @@ -5231,8 +5223,6 @@ Tree::Tree() { set_mouse_filter(MOUSE_FILTER_STOP); set_clip_contents(true); - - update_cache(); } Tree::~Tree() { diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 7f9c00b1b9..450943c048 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -245,7 +245,7 @@ public: void add_button(int p_column, const Ref<Texture2D> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = ""); int get_button_count(int p_column) const; - String get_button_tooltip(int p_column, int p_idx) const; + String get_button_tooltip_text(int p_column, int p_idx) const; Ref<Texture2D> get_button(int p_column, int p_idx) const; int get_button_id(int p_column, int p_idx) const; void erase_button(int p_column, int p_idx); @@ -308,8 +308,8 @@ public: void set_custom_as_button(int p_column, bool p_button); bool is_custom_set_as_button(int p_column) const; - void set_tooltip(int p_column, const String &p_tooltip); - String get_tooltip(int p_column) const; + void set_tooltip_text(int p_column, const String &p_tooltip); + String get_tooltip_text(int p_column) const; void set_text_alignment(int p_column, HorizontalAlignment p_alignment); HorizontalAlignment get_text_alignment(int p_column) const; @@ -482,12 +482,15 @@ private: void propagate_set_columns(TreeItem *p_item); - struct Cache { + struct ThemeCache { + Ref<StyleBox> panel_style; + Ref<StyleBox> focus_style; + Ref<Font> font; Ref<Font> tb_font; int font_size = 0; int tb_font_size = 0; - Ref<StyleBox> bg; + Ref<StyleBox> selected; Ref<StyleBox> selected_focus; Ref<StyleBox> cursor; @@ -505,8 +508,9 @@ private: Ref<Texture2D> checked; Ref<Texture2D> unchecked; Ref<Texture2D> indeterminate; - Ref<Texture2D> arrow_collapsed; Ref<Texture2D> arrow; + Ref<Texture2D> arrow_collapsed; + Ref<Texture2D> arrow_collapsed_mirrored; Ref<Texture2D> select_arrow; Ref<Texture2D> updown; @@ -536,7 +540,9 @@ private: int scroll_border = 0; int scroll_speed = 0; int font_outline_size = 0; + } theme_cache; + struct Cache { enum ClickType { CLICK_NONE, CLICK_TITLE, @@ -559,7 +565,6 @@ private: Point2i text_editor_position; bool rtl = false; - } cache; int _get_title_button_height() const; @@ -572,7 +577,6 @@ private: bool v_scroll_enabled = true; Size2 get_internal_min_size() const; - void update_cache(); void update_scrollbars(); Rect2 search_item_rect(TreeItem *p_from, TreeItem *p_item); @@ -620,6 +624,8 @@ private: bool _scroll(bool p_horizontal, float p_pages); protected: + virtual void _update_theme_item_cache() override; + static void _bind_methods(); public: diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp index 4024d4c80e..1e03ed6e76 100644 --- a/scene/gui/video_stream_player.cpp +++ b/scene/gui/video_stream_player.cpp @@ -213,7 +213,7 @@ void VideoStreamPlayer::set_expand(bool p_expand) { } expand = p_expand; - update(); + queue_redraw(); update_minimum_size(); } @@ -261,7 +261,7 @@ void VideoStreamPlayer::set_stream(const Ref<VideoStream> &p_stream) { AudioServer::get_singleton()->unlock(); } - update(); + queue_redraw(); if (!expand) { update_minimum_size(); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 515f4d88a6..05d86f77f2 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -88,7 +88,7 @@ void CanvasItem::_handle_visibility_change(bool p_visible) { notification(NOTIFICATION_VISIBILITY_CHANGED); if (p_visible) { - update(); + queue_redraw(); } else { emit_signal(SceneStringNames::get_singleton()->hidden); } @@ -121,7 +121,7 @@ CanvasItem *CanvasItem::get_current_item_drawn() { return current_item_drawn; } -void CanvasItem::_update_callback() { +void CanvasItem::_redraw_callback() { if (!is_inside_tree()) { pending_update = false; return; @@ -242,7 +242,7 @@ void CanvasItem::_enter_canvas() { } pending_update = false; - update(); + queue_redraw(); notification(NOTIFICATION_ENTER_CANVAS); } @@ -338,6 +338,7 @@ void CanvasItem::_notification(int p_what) { } if (window) { window->disconnect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &CanvasItem::_window_visibility_changed)); + window = nullptr; } global_invalid = true; parent_visible_in_tree = false; @@ -355,7 +356,7 @@ void CanvasItem::_window_visibility_changed() { } } -void CanvasItem::update() { +void CanvasItem::queue_redraw() { if (!is_inside_tree()) { return; } @@ -365,7 +366,14 @@ void CanvasItem::update() { pending_update = true; - MessageQueue::get_singleton()->push_call(this, SNAME("_update_callback")); + MessageQueue::get_singleton()->push_callable(callable_mp(this, &CanvasItem::_redraw_callback)); +} + +void CanvasItem::move_to_front() { + if (!get_parent()) { + return; + } + get_parent()->move_child(this, -1); } void CanvasItem::set_modulate(const Color &p_modulate) { @@ -438,7 +446,7 @@ int CanvasItem::get_light_mask() const { void CanvasItem::item_rect_changed(bool p_size_changed) { if (p_size_changed) { - update(); + queue_redraw(); } emit_signal(SceneStringNames::get_singleton()->item_rect_changed); } @@ -867,7 +875,6 @@ void CanvasItem::force_update_transform() { void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("_top_level_raise_self"), &CanvasItem::_top_level_raise_self); - ClassDB::bind_method(D_METHOD("_update_callback"), &CanvasItem::_update_callback); #ifdef TOOLS_ENABLED ClassDB::bind_method(D_METHOD("_edit_set_state", "state"), &CanvasItem::_edit_set_state); @@ -896,7 +903,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("show"), &CanvasItem::show); ClassDB::bind_method(D_METHOD("hide"), &CanvasItem::hide); - ClassDB::bind_method(D_METHOD("update"), &CanvasItem::update); + ClassDB::bind_method(D_METHOD("queue_redraw"), &CanvasItem::queue_redraw); + ClassDB::bind_method(D_METHOD("move_to_front"), &CanvasItem::move_to_front); ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &CanvasItem::set_as_top_level); ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &CanvasItem::is_set_as_top_level); @@ -1100,7 +1108,7 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) { texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter); } RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache); - update(); + queue_redraw(); if (p_propagate) { for (CanvasItem *E : children_items) { @@ -1141,7 +1149,7 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat); } RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache); - update(); + queue_redraw(); if (p_propagate) { for (CanvasItem *E : children_items) { if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) { diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 1e0d4552ce..b80289fdb4 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -110,7 +110,7 @@ private: void _propagate_visibility_changed(bool p_parent_visible_in_tree); void _handle_visibility_change(bool p_visible); - void _update_callback(); + void _redraw_callback(); void _enter_canvas(); void _exit_canvas(); @@ -197,7 +197,8 @@ public: void show(); void hide(); - void update(); + void queue_redraw(); + void move_to_front(); void set_clip_children(bool p_enabled); bool is_clipping_children() const; diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 4890db995a..214efe432b 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -329,14 +329,14 @@ void CanvasLayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_less,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "suffix:px"), "set_transform", "get_transform"); ADD_GROUP("", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport"); ADD_GROUP("Follow Viewport", "follow_viewport"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enabled"), "set_follow_viewport", "is_following_viewport"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_less"), "set_follow_viewport_scale", "get_follow_viewport_scale"); ADD_SIGNAL(MethodInfo("visibility_changed")); } diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 9a23bc65bf..bec378dd91 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -36,11 +36,11 @@ void HTTPRequest::_redirect_request(const String &p_new_url) { } Error HTTPRequest::_request() { - return client->connect_to_host(url, port, use_ssl, validate_ssl); + return client->connect_to_host(url, port, use_tls, validate_tls); } Error HTTPRequest::_parse_url(const String &p_url) { - use_ssl = false; + use_tls = false; request_string = ""; port = 80; request_sent = false; @@ -54,12 +54,12 @@ Error HTTPRequest::_parse_url(const String &p_url) { Error err = p_url.parse_url(scheme, url, port, request_string); ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing URL: " + p_url + "."); if (scheme == "https://") { - use_ssl = true; + use_tls = true; } else if (scheme != "http://") { ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid URL scheme: " + scheme + "."); } if (port == 0) { - port = use_ssl ? 443 : 80; + port = use_tls ? 443 : 80; } if (request_string.is_empty()) { request_string = "/"; @@ -98,7 +98,7 @@ String HTTPRequest::get_header_value(const PackedStringArray &p_headers, const S return value; } -Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const String &p_request_data) { +Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const String &p_request_data) { // Copy the string into a raw buffer. Vector<uint8_t> raw_data; @@ -110,10 +110,10 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h memcpy(w, charstr.ptr(), len); } - return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data); + return request_raw(p_url, p_custom_headers, p_tls_validate_domain, p_method, raw_data); } -Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_ssl_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) { +Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_custom_headers, bool p_tls_validate_domain, HTTPClient::Method p_method, const Vector<uint8_t> &p_request_data_raw) { ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED); ERR_FAIL_COND_V_MSG(requesting, ERR_BUSY, "HTTPRequest is processing a request. Wait for completion or cancel it before attempting a new one."); @@ -129,7 +129,7 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust return err; } - validate_ssl = p_ssl_validate_domain; + validate_tls = p_tls_validate_domain; headers = p_custom_headers; @@ -413,8 +413,8 @@ bool HTTPRequest::_update_connection() { call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } break; - case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: { - call_deferred(SNAME("_request_done"), RESULT_SSL_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray()); + case HTTPClient::STATUS_TLS_HANDSHAKE_ERROR: { + call_deferred(SNAME("_request_done"), RESULT_TLS_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; } break; } @@ -570,8 +570,8 @@ void HTTPRequest::_timeout() { } void HTTPRequest::_bind_methods() { - ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "ssl_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String())); - ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "ssl_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray())); + ClassDB::bind_method(D_METHOD("request", "url", "custom_headers", "tls_validate_domain", "method", "request_data"), &HTTPRequest::request, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(String())); + ClassDB::bind_method(D_METHOD("request_raw", "url", "custom_headers", "tls_validate_domain", "method", "request_data_raw"), &HTTPRequest::request_raw, DEFVAL(PackedStringArray()), DEFVAL(true), DEFVAL(HTTPClient::METHOD_GET), DEFVAL(PackedByteArray())); ClassDB::bind_method(D_METHOD("cancel_request"), &HTTPRequest::cancel_request); ClassDB::bind_method(D_METHOD("get_http_client_status"), &HTTPRequest::get_http_client_status); @@ -621,7 +621,7 @@ void HTTPRequest::_bind_methods() { BIND_ENUM_CONSTANT(RESULT_CANT_CONNECT); BIND_ENUM_CONSTANT(RESULT_CANT_RESOLVE); BIND_ENUM_CONSTANT(RESULT_CONNECTION_ERROR); - BIND_ENUM_CONSTANT(RESULT_SSL_HANDSHAKE_ERROR); + BIND_ENUM_CONSTANT(RESULT_TLS_HANDSHAKE_ERROR); BIND_ENUM_CONSTANT(RESULT_NO_RESPONSE); BIND_ENUM_CONSTANT(RESULT_BODY_SIZE_LIMIT_EXCEEDED); BIND_ENUM_CONSTANT(RESULT_BODY_DECOMPRESS_FAILED); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 4b32188377..290bacd9d2 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -48,7 +48,7 @@ public: RESULT_CANT_CONNECT, RESULT_CANT_RESOLVE, RESULT_CONNECTION_ERROR, - RESULT_SSL_HANDSHAKE_ERROR, + RESULT_TLS_HANDSHAKE_ERROR, RESULT_NO_RESPONSE, RESULT_BODY_SIZE_LIMIT_EXCEEDED, RESULT_BODY_DECOMPRESS_FAILED, @@ -67,8 +67,8 @@ private: String url; int port = 80; Vector<String> headers; - bool validate_ssl = false; - bool use_ssl = false; + bool validate_tls = false; + bool use_tls = false; HTTPClient::Method method; Vector<uint8_t> request_data; @@ -121,8 +121,8 @@ protected: static void _bind_methods(); public: - Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request - Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_ssl_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request + Error request(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const String &p_request_data = ""); //connects to a full url and perform request + Error request_raw(const String &p_url, const Vector<String> &p_custom_headers = Vector<String>(), bool p_tls_validate_domain = true, HTTPClient::Method p_method = HTTPClient::METHOD_GET, const Vector<uint8_t> &p_request_data_raw = Vector<uint8_t>()); //connects to a full url and perform request void cancel_request(); HTTPClient::Status get_http_client_status() const; diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp index aad5baccab..9b63118f7c 100644 --- a/scene/main/multiplayer_peer.cpp +++ b/scene/main/multiplayer_peer.cpp @@ -120,19 +120,10 @@ void MultiplayerPeer::_bind_methods() { /*************/ -int MultiplayerPeerExtension::get_available_packet_count() const { - int count; - if (GDVIRTUAL_CALL(_get_available_packet_count, count)) { - return count; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_available_packet_count is unimplemented!"); - return -1; -} - Error MultiplayerPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - int err; + Error err; if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) { - return (Error)err; + return err; } if (GDVIRTUAL_IS_OVERRIDDEN(_get_packet_script)) { if (!GDVIRTUAL_CALL(_get_packet_script, script_buffer)) { @@ -153,9 +144,9 @@ Error MultiplayerPeerExtension::get_packet(const uint8_t **r_buffer, int &r_buff } Error MultiplayerPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - int err; + Error err; if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) { - return (Error)err; + return err; } if (GDVIRTUAL_IS_OVERRIDDEN(_put_packet_script)) { PackedByteArray a; @@ -171,87 +162,6 @@ Error MultiplayerPeerExtension::put_packet(const uint8_t *p_buffer, int p_buffer return FAILED; } -int MultiplayerPeerExtension::get_max_packet_size() const { - int size; - if (GDVIRTUAL_CALL(_get_max_packet_size, size)) { - return size; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_max_packet_size is unimplemented!"); - return 0; -} - -void MultiplayerPeerExtension::set_transfer_channel(int p_channel) { - if (GDVIRTUAL_CALL(_set_transfer_channel, p_channel)) { - return; - } - MultiplayerPeer::set_transfer_channel(p_channel); -} - -int MultiplayerPeerExtension::get_transfer_channel() const { - int channel; - if (GDVIRTUAL_CALL(_get_transfer_channel, channel)) { - return channel; - } - return MultiplayerPeer::get_transfer_channel(); -} - -void MultiplayerPeerExtension::set_transfer_mode(TransferMode p_mode) { - if (GDVIRTUAL_CALL(_set_transfer_mode, p_mode)) { - return; - } - MultiplayerPeer::set_transfer_mode(p_mode); -} - -MultiplayerPeer::TransferMode MultiplayerPeerExtension::get_transfer_mode() const { - int mode; - if (GDVIRTUAL_CALL(_get_transfer_mode, mode)) { - return (MultiplayerPeer::TransferMode)mode; - } - return MultiplayerPeer::get_transfer_mode(); -} - -void MultiplayerPeerExtension::set_target_peer(int p_peer_id) { - if (GDVIRTUAL_CALL(_set_target_peer, p_peer_id)) { - return; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_set_target_peer is unimplemented!"); -} - -int MultiplayerPeerExtension::get_packet_peer() const { - int peer; - if (GDVIRTUAL_CALL(_get_packet_peer, peer)) { - return peer; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_packet_peer is unimplemented!"); - return 0; -} - -bool MultiplayerPeerExtension::is_server() const { - bool server; - if (GDVIRTUAL_CALL(_is_server, server)) { - return server; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_is_server is unimplemented!"); - return false; -} - -void MultiplayerPeerExtension::poll() { - int err; - if (GDVIRTUAL_CALL(_poll, err)) { - return; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_poll is unimplemented!"); -} - -int MultiplayerPeerExtension::get_unique_id() const { - int id; - if (GDVIRTUAL_CALL(_get_unique_id, id)) { - return id; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_unique_id is unimplemented!"); - return 0; -} - void MultiplayerPeerExtension::set_refuse_new_connections(bool p_enable) { if (GDVIRTUAL_CALL(_set_refuse_new_connections, p_enable)) { return; @@ -267,15 +177,6 @@ bool MultiplayerPeerExtension::is_refusing_new_connections() const { return MultiplayerPeer::is_refusing_new_connections(); } -MultiplayerPeer::ConnectionStatus MultiplayerPeerExtension::get_connection_status() const { - int status; - if (GDVIRTUAL_CALL(_get_connection_status, status)) { - return (ConnectionStatus)status; - } - WARN_PRINT_ONCE("MultiplayerPeerExtension::_get_connection_status is unimplemented!"); - return CONNECTION_DISCONNECTED; -} - void MultiplayerPeerExtension::_bind_methods() { GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size"); GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size"); @@ -300,4 +201,7 @@ void MultiplayerPeerExtension::_bind_methods() { GDVIRTUAL_BIND(_set_refuse_new_connections, "p_enable"); GDVIRTUAL_BIND(_is_refusing_new_connections); GDVIRTUAL_BIND(_get_connection_status); + + ADD_PROPERTY_DEFAULT("transfer_mode", TRANSFER_MODE_RELIABLE); + ADD_PROPERTY_DEFAULT("transfer_channel", 0); } diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h index 8a012d7520..ab7483ece5 100644 --- a/scene/main/multiplayer_peer.h +++ b/scene/main/multiplayer_peer.h @@ -33,6 +33,7 @@ #include "core/io/packet_peer.h" +#include "core/extension/ext_wrappers.gen.inc" #include "core/object/gdvirtual.gen.inc" #include "core/object/script_language.h" #include "core/variant/native_ptr.h" @@ -103,55 +104,35 @@ protected: PackedByteArray script_buffer; public: - /* PacketPeer */ - virtual int get_available_packet_count() const override; + /* PacketPeer extension */ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - virtual int get_max_packet_size() const override; - - /* MultiplayerPeer */ - virtual void set_transfer_channel(int p_channel) override; - virtual int get_transfer_channel() const override; - virtual void set_transfer_mode(TransferMode p_mode) override; - virtual TransferMode get_transfer_mode() const override; - virtual void set_target_peer(int p_peer_id) override; - - virtual int get_packet_peer() const override; - - virtual bool is_server() const override; + GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>); + GDVIRTUAL0R(PackedByteArray, _get_packet_script); // For GDScript. - virtual void poll() override; + virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; + GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int); + GDVIRTUAL1R(Error, _put_packet_script, PackedByteArray); // For GDScript. - virtual int get_unique_id() const override; + EXBIND0RC(int, get_available_packet_count); + EXBIND0RC(int, get_max_packet_size); + /* MultiplayerPeer extension */ virtual void set_refuse_new_connections(bool p_enable) override; - virtual bool is_refusing_new_connections() const override; + GDVIRTUAL1(_set_refuse_new_connections, bool); // Optional. - virtual ConnectionStatus get_connection_status() const override; - - /* PacketPeer GDExtension */ - GDVIRTUAL0RC(int, _get_available_packet_count); - GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>); - GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int); - GDVIRTUAL0RC(int, _get_max_packet_size); - - /* PacketPeer GDScript */ - GDVIRTUAL0R(PackedByteArray, _get_packet_script); - GDVIRTUAL1R(int, _put_packet_script, PackedByteArray); - - /* MultiplayerPeer GDExtension */ - GDVIRTUAL1(_set_transfer_channel, int); - GDVIRTUAL0RC(int, _get_transfer_channel); - GDVIRTUAL1(_set_transfer_mode, int); - GDVIRTUAL0RC(int, _get_transfer_mode); - GDVIRTUAL1(_set_target_peer, int); - GDVIRTUAL0RC(int, _get_packet_peer); - GDVIRTUAL0RC(bool, _is_server); - GDVIRTUAL0R(int, _poll); - GDVIRTUAL0RC(int, _get_unique_id); - GDVIRTUAL1(_set_refuse_new_connections, bool); - GDVIRTUAL0RC(bool, _is_refusing_new_connections); - GDVIRTUAL0RC(int, _get_connection_status); + virtual bool is_refusing_new_connections() const override; + GDVIRTUAL0RC(bool, _is_refusing_new_connections); // Optional. + + EXBIND1(set_transfer_channel, int); + EXBIND0RC(int, get_transfer_channel); + EXBIND1(set_transfer_mode, TransferMode); + EXBIND0RC(TransferMode, get_transfer_mode); + EXBIND1(set_target_peer, int); + EXBIND0RC(int, get_packet_peer); + EXBIND0RC(bool, is_server); + EXBIND0(poll); + EXBIND0RC(int, get_unique_id); + EXBIND0RC(ConnectionStatus, get_connection_status); }; #endif // MULTIPLAYER_PEER_H diff --git a/scene/main/node.cpp b/scene/main/node.cpp index cc3d14e5be..29f4d4fb1c 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -328,12 +328,21 @@ void Node::move_child(Node *p_child, int p_pos) { // We need to check whether node is internal and move it only in the relevant node range. if (p_child->_is_internal_front()) { + if (p_pos < 0) { + p_pos += data.internal_children_front; + } ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos)); _move_child(p_child, p_pos); } else if (p_child->_is_internal_back()) { + if (p_pos < 0) { + p_pos += data.internal_children_back; + } ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos)); _move_child(p_child, data.children.size() - data.internal_children_back + p_pos); } else { + if (p_pos < 0) { + p_pos += get_child_count(false); + } ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos)); _move_child(p_child, p_pos + data.internal_children_front); } @@ -389,21 +398,6 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) { data.blocked--; } -void Node::raise() { - if (!data.parent) { - return; - } - - // Internal children move within a different index range. - if (_is_internal_front()) { - data.parent->move_child(this, data.parent->data.internal_children_front - 1); - } else if (_is_internal_back()) { - data.parent->move_child(this, data.parent->data.internal_children_back - 1); - } else { - data.parent->move_child(this, data.parent->get_child_count(false) - 1); - } -} - void Node::_propagate_groups_dirty() { for (const KeyValue<StringName, GroupData> &E : data.grouped) { if (E.value.group) { @@ -951,14 +945,11 @@ String Node::validate_child_name(Node *p_child) { String Node::adjust_name_casing(const String &p_name) { switch (GLOBAL_GET("editor/node_naming/name_casing").operator int()) { case NAME_CASING_PASCAL_CASE: - return p_name.capitalize().replace(" ", ""); - case NAME_CASING_CAMEL_CASE: { - String name = p_name.capitalize().replace(" ", ""); - name[0] = name.to_lower()[0]; - return name; - } + return p_name.to_pascal_case(); + case NAME_CASING_CAMEL_CASE: + return p_name.to_camel_case(); case NAME_CASING_SNAKE_CASE: - return p_name.capitalize().replace(" ", "_").to_lower(); + return p_name.to_snake_case(); } return p_name; } @@ -1134,7 +1125,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) { add_child_notify(p_child); } -void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_internal) { +void Node::add_child(Node *p_child, bool p_force_readable_name, InternalMode p_internal) { ERR_FAIL_NULL(p_child); ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself! ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent @@ -1143,7 +1134,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i #endif ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead."); - _validate_child_name(p_child, p_legible_unique_name); + _validate_child_name(p_child, p_force_readable_name); _add_child_nocheck(p_child, p_child->data.name); if (p_internal == INTERNAL_MODE_FRONT) { @@ -1157,7 +1148,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name, InternalMode p_i } } -void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) { +void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) { ERR_FAIL_NULL(p_sibling); ERR_FAIL_NULL(data.parent); ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself! @@ -1170,7 +1161,7 @@ void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) { internal = INTERNAL_MODE_BACK; } - data.parent->add_child(p_sibling, p_legible_unique_name, internal); + data.parent->add_child(p_sibling, p_force_readable_name, internal); data.parent->_move_child(p_sibling, get_index() + 1); } @@ -1925,43 +1916,6 @@ Ref<Tween> Node::create_tween() { return tween; } -void Node::remove_and_skip() { - ERR_FAIL_COND(!data.parent); - - Node *new_owner = get_owner(); - - List<Node *> children; - - while (true) { - bool clear = true; - for (int i = 0; i < data.children.size(); i++) { - Node *c_node = data.children[i]; - if (!c_node->get_owner()) { - continue; - } - - remove_child(c_node); - c_node->_propagate_replace_owner(this, nullptr); - children.push_back(c_node); - clear = false; - break; - } - - if (clear) { - break; - } - } - - while (!children.is_empty()) { - Node *c_node = children.front()->get(); - data.parent->add_child(c_node); - c_node->_propagate_replace_owner(nullptr, new_owner); - children.pop_front(); - } - - data.parent->remove_child(this); -} - void Node::set_scene_file_path(const String &p_scene_file_path) { data.scene_file_path = p_scene_file_path; } @@ -2790,11 +2744,11 @@ void Node::_bind_methods() { GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE); ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case")); - ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "legible_unique_name"), &Node::add_sibling, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "force_readable_name"), &Node::add_sibling, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_name", "name"), &Node::set_name); ClassDB::bind_method(D_METHOD("get_name"), &Node::get_name); - ClassDB::bind_method(D_METHOD("add_child", "node", "legible_unique_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_child", "node", "force_readable_name", "internal"), &Node::add_child, DEFVAL(false), DEFVAL(0)); ClassDB::bind_method(D_METHOD("remove_child", "node"), &Node::remove_child); ClassDB::bind_method(D_METHOD("get_child_count", "include_internal"), &Node::get_child_count, DEFVAL(false)); // Note that the default value bound for include_internal is false, while the method is declared with true. This is because internal nodes are irrelevant for GDSCript. ClassDB::bind_method(D_METHOD("get_children", "include_internal"), &Node::_get_children, DEFVAL(false)); @@ -2819,10 +2773,8 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group); ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_position"), &Node::move_child); ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups); - ClassDB::bind_method(D_METHOD("raise"), &Node::raise); ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner); ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner); - ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip); ClassDB::bind_method(D_METHOD("get_index", "include_internal"), &Node::get_index, DEFVAL(false)); ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree); ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty); @@ -2926,7 +2878,7 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_PROCESS); BIND_CONSTANT(NOTIFICATION_PARENTED); BIND_CONSTANT(NOTIFICATION_UNPARENTED); - BIND_CONSTANT(NOTIFICATION_INSTANCED); + BIND_CONSTANT(NOTIFICATION_SCENE_INSTANTIATED); BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN); BIND_CONSTANT(NOTIFICATION_DRAG_END); BIND_CONSTANT(NOTIFICATION_PATH_RENAMED); diff --git a/scene/main/node.h b/scene/main/node.h index 703c580d3f..13a938ef97 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -259,7 +259,7 @@ public: NOTIFICATION_PROCESS = 17, NOTIFICATION_PARENTED = 18, NOTIFICATION_UNPARENTED = 19, - NOTIFICATION_INSTANCED = 20, + NOTIFICATION_SCENE_INSTANTIATED = 20, NOTIFICATION_DRAG_BEGIN = 21, NOTIFICATION_DRAG_END = 22, NOTIFICATION_PATH_RENAMED = 23, @@ -303,8 +303,8 @@ public: StringName get_name() const; void set_name(const String &p_name); - void add_child(Node *p_child, bool p_legible_unique_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED); - void add_sibling(Node *p_sibling, bool p_legible_unique_name = false); + void add_child(Node *p_child, bool p_force_readable_name = false, InternalMode p_internal = INTERNAL_MODE_DISABLED); + void add_sibling(Node *p_sibling, bool p_force_readable_name = false); void remove_child(Node *p_child); int get_child_count(bool p_include_internal = true) const; @@ -348,7 +348,6 @@ public: void move_child(Node *p_child, int p_pos); void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false); - void raise(); void set_owner(Node *p_owner); Node *get_owner() const; @@ -357,7 +356,6 @@ public: void set_unique_name_in_owner(bool p_enabled); bool is_unique_name_in_owner() const; - void remove_and_skip(); int get_index(bool p_include_internal = true) const; Ref<Tween> create_tween(); @@ -531,4 +529,8 @@ Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args)); } +// Add these macro to your class's 'get_configuration_warnings' function to have warnings show up in the scene tree inspector. +#define DEPRECATED_NODE_WARNING warnings.push_back(RTR("This node is marked as deprecated and will be removed in future versions.\nPlease check the Godot documentation for information about migration.")); +#define EXPERIMENTAL_NODE_WARNING warnings.push_back(RTR("This node is marked as experimental and may be subject to removal or major changes in future versions.")); + #endif // NODE_H diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 109799e23a..c18aa5aaa2 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -46,6 +46,7 @@ #include "scene/debugger/scene_debugger.h" #include "scene/main/multiplayer_api.h" #include "scene/main/viewport.h" +#include "scene/resources/environment.h" #include "scene/resources/font.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" @@ -87,6 +88,14 @@ bool SceneTreeTimer::is_process_always() { return process_always; } +void SceneTreeTimer::set_process_in_physics(bool p_process_in_physics) { + process_in_physics = p_process_in_physics; +} + +bool SceneTreeTimer::is_process_in_physics() { + return process_in_physics; +} + void SceneTreeTimer::set_ignore_time_scale(bool p_ignore) { ignore_time_scale = p_ignore; } @@ -419,6 +428,8 @@ bool SceneTree::physics_process(double p_time) { _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack + process_timers(p_time, true); //go through timers + process_tweens(p_time, true); flush_transform_notifications(); @@ -461,37 +472,7 @@ bool SceneTree::process(double p_time) { _flush_delete_queue(); - //go through timers - - List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element - - for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) { - List<Ref<SceneTreeTimer>>::Element *N = E->next(); - if (paused && !E->get()->is_process_always()) { - if (E == L) { - break; //break on last, so if new timers were added during list traversal, ignore them. - } - E = N; - continue; - } - - double time_left = E->get()->get_time_left(); - if (E->get()->is_ignore_time_scale()) { - time_left -= Engine::get_singleton()->get_process_step(); - } else { - time_left -= p_time; - } - E->get()->set_time_left(time_left); - - if (time_left <= 0) { - E->get()->emit_signal(SNAME("timeout")); - timers.erase(E); - } - if (E == L) { - break; //break on last, so if new timers were added during list traversal, ignore them. - } - E = N; - } + process_timers(p_time, false); //go through timers process_tweens(p_time, false); @@ -529,6 +510,38 @@ bool SceneTree::process(double p_time) { return _quit; } +void SceneTree::process_timers(float p_delta, bool p_physics_frame) { + List<Ref<SceneTreeTimer>>::Element *L = timers.back(); //last element + + for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) { + List<Ref<SceneTreeTimer>>::Element *N = E->next(); + if ((paused && !E->get()->is_process_always()) || (E->get()->is_process_in_physics() != p_physics_frame)) { + if (E == L) { + break; //break on last, so if new timers were added during list traversal, ignore them. + } + E = N; + continue; + } + + double time_left = E->get()->get_time_left(); + if (E->get()->is_ignore_time_scale()) { + time_left -= Engine::get_singleton()->get_process_step(); + } else { + time_left -= p_delta; + } + E->get()->set_time_left(time_left); + + if (time_left <= 0) { + E->get()->emit_signal(SNAME("timeout")); + timers.erase(E); + } + if (E == L) { + break; //break on last, so if new timers were added during list traversal, ignore them. + } + E = N; + } +} + void SceneTree::process_tweens(float p_delta, bool p_physics) { // This methods works similarly to how SceneTreeTimers are handled. List<Ref<Tween>>::Element *L = tweens.back(); @@ -709,22 +722,6 @@ float SceneTree::get_debug_paths_width() const { return debug_paths_width; } -void SceneTree::set_debug_navigation_color(const Color &p_color) { - debug_navigation_color = p_color; -} - -Color SceneTree::get_debug_navigation_color() const { - return debug_navigation_color; -} - -void SceneTree::set_debug_navigation_disabled_color(const Color &p_color) { - debug_navigation_disabled_color = p_color; -} - -Color SceneTree::get_debug_navigation_disabled_color() const { - return debug_navigation_disabled_color; -} - Ref<Material> SceneTree::get_debug_paths_material() { if (debug_paths_material.is_valid()) { return debug_paths_material; @@ -742,40 +739,6 @@ Ref<Material> SceneTree::get_debug_paths_material() { return debug_paths_material; } -Ref<Material> SceneTree::get_debug_navigation_material() { - if (navigation_material.is_valid()) { - return navigation_material; - } - - Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); - line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - line_material->set_albedo(get_debug_navigation_color()); - - navigation_material = line_material; - - return navigation_material; -} - -Ref<Material> SceneTree::get_debug_navigation_disabled_material() { - if (navigation_disabled_material.is_valid()) { - return navigation_disabled_material; - } - - Ref<StandardMaterial3D> line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - line_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - line_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); - line_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - line_material->set_albedo(get_debug_navigation_disabled_color()); - - navigation_disabled_material = line_material; - - return navigation_disabled_material; -} - Ref<Material> SceneTree::get_debug_collision_material() { if (collision_material.is_valid()) { return collision_material; @@ -1125,16 +1088,16 @@ void SceneTree::_change_scene(Node *p_to) { } } -Error SceneTree::change_scene(const String &p_path) { +Error SceneTree::change_scene_to_file(const String &p_path) { Ref<PackedScene> new_scene = ResourceLoader::load(p_path); if (new_scene.is_null()) { return ERR_CANT_OPEN; } - return change_scene_to(new_scene); + return change_scene_to_packed(new_scene); } -Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) { +Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) { Node *new_scene = nullptr; if (p_scene.is_valid()) { new_scene = p_scene->instantiate(); @@ -1148,7 +1111,7 @@ Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) { Error SceneTree::reload_current_scene() { ERR_FAIL_COND_V(!current_scene, ERR_UNCONFIGURED); String fname = current_scene->get_scene_file_path(); - return change_scene(fname); + return change_scene_to_file(fname); } void SceneTree::add_current_scene(Node *p_current) { @@ -1156,11 +1119,13 @@ void SceneTree::add_current_scene(Node *p_current) { root->add_child(p_current); } -Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always) { +Ref<SceneTreeTimer> SceneTree::create_timer(double p_delay_sec, bool p_process_always, bool p_process_in_physics, bool p_ignore_time_scale) { Ref<SceneTreeTimer> stt; stt.instantiate(); stt->set_process_always(p_process_always); stt->set_time_left(p_delay_sec); + stt->set_process_in_physics(p_process_in_physics); + stt->set_ignore_time_scale(p_ignore_time_scale); timers.push_back(stt); return stt; } @@ -1258,7 +1223,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); - ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always", "process_in_physics", "ignore_time_scale"), &SceneTree::create_timer, DEFVAL(true), DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween); ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens); @@ -1295,8 +1260,8 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene); ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene); - ClassDB::bind_method(D_METHOD("change_scene", "path"), &SceneTree::change_scene); - ClassDB::bind_method(D_METHOD("change_scene_to", "packed_scene"), &SceneTree::change_scene_to); + ClassDB::bind_method(D_METHOD("change_scene_to_file", "path"), &SceneTree::change_scene_to_file); + ClassDB::bind_method(D_METHOD("change_scene_to_packed", "packed_scene"), &SceneTree::change_scene_to_packed); ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene); @@ -1351,7 +1316,7 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) { } void SceneTree::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { - if (p_function == "change_scene") { + if (p_function == "change_scene_to_file") { Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); List<String> directories; directories.push_back(dir_access->get_current_dir()); @@ -1370,9 +1335,9 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li } if (dir_access->dir_exists(filename)) { - directories.push_back(dir_access->get_current_dir().plus_file(filename)); + directories.push_back(dir_access->get_current_dir().path_join(filename)); } else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) { - r_options->push_back("\"" + dir_access->get_current_dir().plus_file(filename) + "\""); + r_options->push_back("\"" + dir_access->get_current_dir().path_join(filename) + "\""); } filename = dir_access->get_next(); @@ -1389,8 +1354,6 @@ SceneTree::SceneTree() { debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8)); debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4)); debug_paths_width = GLOBAL_DEF("debug/shapes/paths/geometry_width", 2.0); - debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4)); - debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4)); collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000); ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative @@ -1418,9 +1381,13 @@ SceneTree::SceneTree() { root->set_as_audio_listener_2d(true); current_scene = nullptr; - const int msaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/msaa", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)"))); - root->set_msaa(Viewport::MSAA(msaa_mode)); + const int msaa_mode_2d = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/msaa_2d", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_2d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_2d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)"))); + root->set_msaa_2d(Viewport::MSAA(msaa_mode_2d)); + + const int msaa_mode_3d = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/msaa_3d", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)"))); + root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d)); const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)")); @@ -1468,18 +1435,18 @@ SceneTree::SceneTree() { } } - int shadowmap_size = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size", 4096); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384")); - GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_size.mobile", 2048); - bool shadowmap_16_bits = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_16_bits", true); - int atlas_q0 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", 2); - int atlas_q1 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", 2); - int atlas_q2 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", 3); - int atlas_q3 = GLOBAL_DEF("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", 4); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/positional_shadow/atlas_quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + int shadowmap_size = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_size", 4096); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_size", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_size", PROPERTY_HINT_RANGE, "256,16384")); + GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_size.mobile", 2048); + bool shadowmap_16_bits = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_16_bits", true); + int atlas_q0 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", 2); + int atlas_q1 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", 2); + int atlas_q2 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", 3); + int atlas_q3 = GLOBAL_DEF("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", 4); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/lights_and_shadows/positional_shadow/atlas_quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); root->set_positional_shadow_atlas_size(shadowmap_size); root->set_positional_shadow_atlas_16_bits(shadowmap_16_bits); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index e66363ab33..031a331a99 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -53,6 +53,7 @@ class SceneTreeTimer : public RefCounted { double time_left = 0.0; bool process_always = true; + bool process_in_physics = false; bool ignore_time_scale = false; protected: @@ -65,6 +66,9 @@ public: void set_process_always(bool p_process_always); bool is_process_always(); + void set_process_in_physics(bool p_process_in_physics); + bool is_process_in_physics(); + void set_ignore_time_scale(bool p_ignore); bool is_ignore_time_scale(); @@ -176,6 +180,7 @@ private: void node_added(Node *p_node); void node_removed(Node *p_node); void node_renamed(Node *p_node); + void process_timers(float p_delta, bool p_physics_frame); void process_tweens(float p_delta, bool p_physics_frame); Group *add_to_group(const StringName &p_group, Node *p_node); @@ -329,15 +334,7 @@ public: void set_debug_paths_width(float p_width); float get_debug_paths_width() const; - void set_debug_navigation_color(const Color &p_color); - Color get_debug_navigation_color() const; - - void set_debug_navigation_disabled_color(const Color &p_color); - Color get_debug_navigation_disabled_color() const; - Ref<Material> get_debug_paths_material(); - Ref<Material> get_debug_navigation_material(); - Ref<Material> get_debug_navigation_disabled_material(); Ref<Material> get_debug_collision_material(); Ref<ArrayMesh> get_debug_contact_mesh(); @@ -361,11 +358,11 @@ public: void set_current_scene(Node *p_scene); Node *get_current_scene() const; - Error change_scene(const String &p_path); - Error change_scene_to(const Ref<PackedScene> &p_scene); + Error change_scene_to_file(const String &p_path); + Error change_scene_to_packed(const Ref<PackedScene> &p_scene); Error reload_current_scene(); - Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true); + Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false); Ref<Tween> create_tween(); TypedArray<Tween> get_processed_tweens(); diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index a621aea9c8..13034c5447 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -64,9 +64,9 @@ bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_valu if (active) { if (o->override.get_type() == Variant::OBJECT) { RID tex_rid = p_value; - RS::get_singleton()->global_shader_uniform_set_override(*r, tex_rid); + RS::get_singleton()->global_shader_parameter_set_override(*r, tex_rid); } else { - RS::get_singleton()->global_shader_uniform_set_override(*r, p_value); + RS::get_singleton()->global_shader_parameter_set_override(*r, p_value); } } o->in_use = p_value.get_type() != Variant::NIL; @@ -93,13 +93,13 @@ bool ShaderGlobalsOverride::_get(const StringName &p_name, Variant &r_ret) const void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const { Vector<StringName> variables; - variables = RS::get_singleton()->global_shader_uniform_get_list(); + variables = RS::get_singleton()->global_shader_parameter_get_list(); for (int i = 0; i < variables.size(); i++) { PropertyInfo pinfo; pinfo.name = "params/" + variables[i]; pinfo.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - switch (RS::get_singleton()->global_shader_uniform_get_type(variables[i])) { + switch (RS::get_singleton()->global_shader_parameter_get_type(variables[i])) { case RS::GLOBAL_VAR_TYPE_BOOL: { pinfo.type = Variant::BOOL; } break; @@ -234,9 +234,9 @@ void ShaderGlobalsOverride::_activate() { if (o->in_use && o->override.get_type() != Variant::NIL) { if (o->override.get_type() == Variant::OBJECT) { RID tex_rid = o->override; - RS::get_singleton()->global_shader_uniform_set_override(E.key, tex_rid); + RS::get_singleton()->global_shader_parameter_set_override(E.key, tex_rid); } else { - RS::get_singleton()->global_shader_uniform_set_override(E.key, o->override); + RS::get_singleton()->global_shader_parameter_set_override(E.key, o->override); } } @@ -258,7 +258,7 @@ void ShaderGlobalsOverride::_notification(int p_what) { for (const KeyValue<StringName, Override> &E : overrides) { const Override *o = &E.value; if (o->in_use) { - RS::get_singleton()->global_shader_uniform_set_override(E.key, Variant()); + RS::get_singleton()->global_shader_parameter_set_override(E.key, Variant()); } } } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index a5a4e29186..5295de5c09 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -190,14 +190,7 @@ void Viewport::_sub_window_register(Window *p_window) { } void Viewport::_sub_window_update(Window *p_window) { - int index = -1; - for (int i = 0; i < gui.sub_windows.size(); i++) { - if (gui.sub_windows[i].window == p_window) { - index = i; - break; - } - } - + int index = _sub_window_find(p_window); ERR_FAIL_COND(index == -1); const SubWindow &sw = gui.sub_windows[index]; @@ -257,14 +250,7 @@ void Viewport::_sub_window_grab_focus(Window *p_window) { return; } - int index = -1; - for (int i = 0; i < gui.sub_windows.size(); i++) { - if (gui.sub_windows[i].window == p_window) { - index = i; - break; - } - } - + int index = _sub_window_find(p_window); ERR_FAIL_COND(index == -1); if (p_window->get_flag(Window::FLAG_NO_FOCUS)) { @@ -312,13 +298,11 @@ void Viewport::_sub_window_grab_focus(Window *p_window) { } void Viewport::_sub_window_remove(Window *p_window) { - for (int i = 0; i < gui.sub_windows.size(); i++) { - if (gui.sub_windows[i].window == p_window) { - RS::get_singleton()->free(gui.sub_windows[i].canvas_item); - gui.sub_windows.remove_at(i); - break; - } - } + int index = _sub_window_find(p_window); + ERR_FAIL_COND(index == -1); + + RS::get_singleton()->free(gui.sub_windows[index].canvas_item); + gui.sub_windows.remove_at(index); if (gui.sub_windows.size() == 0) { RS::get_singleton()->free(subwindow_canvas); @@ -326,27 +310,46 @@ void Viewport::_sub_window_remove(Window *p_window) { } if (gui.subwindow_focused == p_window) { + Window *new_focused_window; Window *parent_visible = p_window->get_parent_visible_window(); gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_OUT); - if (parent_visible && parent_visible != this) { - gui.subwindow_focused = parent_visible; - gui.subwindow_focused->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + if (parent_visible) { + new_focused_window = parent_visible; } else { - gui.subwindow_focused = nullptr; - Window *this_window = Object::cast_to<Window>(this); - if (this_window) { - this_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + new_focused_window = Object::cast_to<Window>(this); + } + + if (new_focused_window) { + int new_focused_index = _sub_window_find(new_focused_window); + if (new_focused_index != -1) { + gui.subwindow_focused = new_focused_window; + } else { + gui.subwindow_focused = nullptr; } + + new_focused_window->_event_callback(DisplayServer::WINDOW_EVENT_FOCUS_IN); + } else { + gui.subwindow_focused = nullptr; } } RenderingServer::get_singleton()->viewport_set_parent_viewport(p_window->viewport, p_window->parent ? p_window->parent->viewport : RID()); } +int Viewport::_sub_window_find(Window *p_window) { + for (int i = 0; i < gui.sub_windows.size(); i++) { + if (gui.sub_windows[i].window == p_window) { + return i; + } + } + + return -1; +} + void Viewport::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -802,6 +805,10 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, update_canvas_items(); + for (ViewportTexture *E : viewport_textures) { + E->emit_changed(); + } + emit_signal(SNAME("size_changed")); } @@ -1023,7 +1030,7 @@ void Viewport::_update_canvas_items(Node *p_node) { CanvasItem *ci = Object::cast_to<CanvasItem>(p_node); if (ci) { - ci->update(); + ci->queue_redraw(); } } @@ -2096,7 +2103,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) { p_control->set_as_top_level(true); p_control->set_position(gui.last_mouse_pos); p_base->get_root_parent_control()->add_child(p_control); // Add as child of viewport. - p_control->raise(); + p_control->move_to_front(); gui.drag_preview_id = p_control->get_instance_id(); } @@ -2197,7 +2204,7 @@ void Viewport::_gui_control_grab_focus(Control *p_control) { gui.key_focus = p_control; emit_signal(SNAME("gui_focus_changed"), p_control); p_control->notification(Control::NOTIFICATION_FOCUS_ENTER); - p_control->update(); + p_control->queue_redraw(); } void Viewport::_gui_accept_event() { @@ -2865,7 +2872,7 @@ void Viewport::gui_release_focus() { Control *f = gui.key_focus; gui.key_focus = nullptr; f->notification(Control::NOTIFICATION_FOCUS_EXIT, true); - f->update(); + f->queue_redraw(); } } @@ -2873,17 +2880,30 @@ Control *Viewport::gui_get_focus_owner() { return gui.key_focus; } -void Viewport::set_msaa(MSAA p_msaa) { +void Viewport::set_msaa_2d(MSAA p_msaa) { ERR_FAIL_INDEX(p_msaa, MSAA_MAX); - if (msaa == p_msaa) { + if (msaa_2d == p_msaa) { return; } - msaa = p_msaa; - RS::get_singleton()->viewport_set_msaa(viewport, RS::ViewportMSAA(p_msaa)); + msaa_2d = p_msaa; + RS::get_singleton()->viewport_set_msaa_2d(viewport, RS::ViewportMSAA(p_msaa)); } -Viewport::MSAA Viewport::get_msaa() const { - return msaa; +Viewport::MSAA Viewport::get_msaa_2d() const { + return msaa_2d; +} + +void Viewport::set_msaa_3d(MSAA p_msaa) { + ERR_FAIL_INDEX(p_msaa, MSAA_MAX); + if (msaa_3d == p_msaa) { + return; + } + msaa_3d = p_msaa; + RS::get_singleton()->viewport_set_msaa_3d(viewport, RS::ViewportMSAA(p_msaa)); +} + +Viewport::MSAA Viewport::get_msaa_3d() const { + return msaa_3d; } void Viewport::set_screen_space_aa(ScreenSpaceAA p_screen_space_aa) { @@ -3675,8 +3695,11 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background); ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background); - ClassDB::bind_method(D_METHOD("set_msaa", "msaa"), &Viewport::set_msaa); - ClassDB::bind_method(D_METHOD("get_msaa"), &Viewport::get_msaa); + ClassDB::bind_method(D_METHOD("set_msaa_2d", "msaa"), &Viewport::set_msaa_2d); + ClassDB::bind_method(D_METHOD("get_msaa_2d"), &Viewport::get_msaa_2d); + + ClassDB::bind_method(D_METHOD("set_msaa_3d", "msaa"), &Viewport::set_msaa_3d); + ClassDB::bind_method(D_METHOD("get_msaa_3d"), &Viewport::get_msaa_3d); ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa); ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa); @@ -3816,7 +3839,8 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled"); ADD_GROUP("Rendering", ""); - ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa", "get_msaa"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa_2d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa_2d", "get_msaa_2d"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)")), "set_msaa_3d", "get_msaa_3d"); ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_taa"), "set_use_taa", "is_using_taa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding"); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 83083cd65a..afea3ea56c 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -297,7 +297,8 @@ private: bool positional_shadow_atlas_16_bits = true; PositionalShadowAtlasQuadrantSubdiv positional_shadow_atlas_quadrant_subdiv[4]; - MSAA msaa = MSAA_DISABLED; + MSAA msaa_2d = MSAA_DISABLED; + MSAA msaa_3d = MSAA_DISABLED; ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED; bool use_taa = false; @@ -460,6 +461,7 @@ private: void _sub_window_update(Window *p_window); void _sub_window_grab_focus(Window *p_window); void _sub_window_remove(Window *p_window); + int _sub_window_find(Window *p_window); bool _sub_windows_forward_input(const Ref<InputEvent> &p_event); SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point); @@ -522,8 +524,11 @@ public: void set_positional_shadow_atlas_quadrant_subdiv(int p_quadrant, PositionalShadowAtlasQuadrantSubdiv p_subdiv); PositionalShadowAtlasQuadrantSubdiv get_positional_shadow_atlas_quadrant_subdiv(int p_quadrant) const; - void set_msaa(MSAA p_msaa); - MSAA get_msaa() const; + void set_msaa_2d(MSAA p_msaa); + MSAA get_msaa_2d() const; + + void set_msaa_3d(MSAA p_msaa); + MSAA get_msaa_3d() const; void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa); ScreenSpaceAA get_screen_space_aa() const; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 5328ae7b8c..04f56bb874 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -32,10 +32,13 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" +#include "core/input/shortcut.h" #include "core/string/translation.h" +#include "core/variant/variant_parser.h" #include "scene/gui/control.h" #include "scene/scene_string_names.h" #include "scene/theme/theme_db.h" +#include "scene/theme/theme_owner.h" void Window::set_title(const String &p_title) { title = p_title; @@ -797,6 +800,19 @@ Viewport *Window::_get_embedder() const { void Window::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_POSTINITIALIZE: { + _invalidate_theme_cache(); + _update_theme_item_cache(); + } break; + + case NOTIFICATION_PARENTED: { + theme_owner->assign_theme_on_parented(this); + } break; + + case NOTIFICATION_UNPARENTED: { + theme_owner->clear_theme_on_unparented(this); + } break; + case NOTIFICATION_ENTER_TREE: { bool embedded = false; { @@ -849,13 +865,13 @@ void Window::_notification(int p_what) { RS::get_singleton()->viewport_set_active(get_viewport_rid(), true); } - // Need to defer here, because theme owner information might be set in - // add_child_notify, which doesn't get called until right after this. - call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED); + notification(NOTIFICATION_THEME_CHANGED); } break; case NOTIFICATION_THEME_CHANGED: { emit_signal(SceneStringNames::get_singleton()->theme_changed); + _invalidate_theme_cache(); + _update_theme_item_cache(); } break; case NOTIFICATION_READY: { @@ -865,6 +881,9 @@ void Window::_notification(int p_what) { } break; case NOTIFICATION_TRANSLATION_CHANGED: { + _invalidate_theme_cache(); + _update_theme_item_cache(); + if (embedder) { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { @@ -1034,9 +1053,31 @@ 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 the stop shortcut (F8 by default). + // The custom shortcut is provided via environment variable when running from the editor. + if (debugger_stop_shortcut.is_null()) { + String shortcut_str = OS::get_singleton()->get_environment("__GODOT_EDITOR_STOP_SHORTCUT__"); + if (!shortcut_str.is_empty()) { + Variant shortcut_var; + + VariantParser::StreamString ss; + ss.s = shortcut_str; + + String errs; + int line; + VariantParser::parse(&ss, shortcut_var, errs, line); + debugger_stop_shortcut = shortcut_var; + } + + if (debugger_stop_shortcut.is_null()) { + // Define a default shortcut if it wasn't provided or is invalid. + debugger_stop_shortcut.instantiate(); + debugger_stop_shortcut->set_events({ (Variant)InputEventKey::create_reference(Key::F8) }); + } + } + Ref<InputEventKey> k = p_ev; - if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_keycode() == Key::F8) { + if (k.is_valid() && k->is_pressed() && !k->is_echo() && debugger_stop_shortcut->matches_event(k)) { EngineDebugger::get_singleton()->send_message("request_quit", Array()); } } @@ -1255,28 +1296,29 @@ Rect2i Window::get_usable_parent_rect() const { } void Window::add_child_notify(Node *p_child) { - // We propagate when this node uses a custom theme, so it can pass it on to its children. - if (theme_owner || theme_owner_window) { - // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`. - Control::_propagate_theme_changed(this, theme_owner, theme_owner_window, false, true); - } - if (is_inside_tree() && wrap_controls) { child_controls_changed(); } } void Window::remove_child_notify(Node *p_child) { - // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate. - if (theme_owner || theme_owner_window) { - Control::_propagate_theme_changed(this, nullptr, nullptr, false, true); - } - if (is_inside_tree() && wrap_controls) { child_controls_changed(); } } +void Window::set_theme_owner_node(Node *p_node) { + theme_owner->set_owner_node(p_node); +} + +Node *Window::get_theme_owner_node() const { + return theme_owner->get_owner_node(); +} + +bool Window::has_theme_owner_node() const { + return theme_owner->has_owner_node(); +} + void Window::set_theme(const Ref<Theme> &p_theme) { if (theme == p_theme) { return; @@ -1288,24 +1330,24 @@ void Window::set_theme(const Ref<Theme> &p_theme) { theme = p_theme; if (theme.is_valid()) { - Control::_propagate_theme_changed(this, nullptr, this, is_inside_tree(), true); + theme_owner->propagate_theme_changed(this, this, is_inside_tree(), true); theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED); return; } Control *parent_c = Object::cast_to<Control>(get_parent()); - if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) { - Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true); + if (parent_c && parent_c->has_theme_owner_node()) { + theme_owner->propagate_theme_changed(this, parent_c->get_theme_owner_node(), is_inside_tree(), true); return; } Window *parent_w = cast_to<Window>(get_parent()); - if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) { - Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true); + if (parent_w && parent_w->has_theme_owner_node()) { + theme_owner->propagate_theme_changed(this, parent_w->get_theme_owner_node(), is_inside_tree(), true); return; } - Control::_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true); + theme_owner->propagate_theme_changed(this, nullptr, is_inside_tree(), true); } Ref<Theme> Window::get_theme() const { @@ -1314,10 +1356,22 @@ Ref<Theme> Window::get_theme() const { void Window::_theme_changed() { if (is_inside_tree()) { - Control::_propagate_theme_changed(this, nullptr, this, true, false); + theme_owner->propagate_theme_changed(this, this, true, false); } } +void Window::_invalidate_theme_cache() { + theme_icon_cache.clear(); + theme_style_cache.clear(); + theme_font_cache.clear(); + theme_font_size_cache.clear(); + theme_color_cache.clear(); + theme_constant_cache.clear(); +} + +void Window::_update_theme_item_cache() { +} + void Window::set_theme_type_variation(const StringName &p_theme_type) { theme_type_variation = p_theme_type; if (is_inside_tree()) { @@ -1329,100 +1383,124 @@ StringName Window::get_theme_type_variation() const { return theme_type_variation; } -void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const { - if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { - if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(theme_type_variation) != StringName()) { - ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); - } else { - ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list); - } - } else { - ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list); +Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_icon_cache.has(p_theme_type) && theme_icon_cache[p_theme_type].has(p_name)) { + return theme_icon_cache[p_theme_type][p_name]; } -} -Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Ref<Texture2D>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<Texture2D> icon = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); + theme_icon_cache[p_theme_type][p_name] = icon; + return icon; } Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_style_cache.has(p_theme_type) && theme_style_cache[p_theme_type].has(p_name)) { + return theme_style_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Ref<StyleBox>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<StyleBox> style = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + theme_style_cache[p_theme_type][p_name] = style; + return style; } Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_font_cache.has(p_theme_type) && theme_font_cache[p_theme_type].has(p_name)) { + return theme_font_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Ref<Font>>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Ref<Font> font = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); + theme_font_cache[p_theme_type][p_name] = font; + return font; } int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_font_size_cache.has(p_theme_type) && theme_font_size_cache[p_theme_type].has(p_name)) { + return theme_font_size_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + int font_size = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + theme_font_size_cache[p_theme_type][p_name] = font_size; + return font_size; } Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_color_cache.has(p_theme_type) && theme_color_cache[p_theme_type].has(p_name)) { + return theme_color_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<Color>(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + Color color = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); + theme_color_cache[p_theme_type][p_name] = color; + return color; } int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { + if (theme_constant_cache.has(p_theme_type) && theme_constant_cache[p_theme_type].has(p_name)) { + return theme_constant_cache[p_theme_type][p_name]; + } + List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::get_theme_item_in_types<int>(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + int constant = theme_owner->get_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + theme_constant_cache[p_theme_type][p_name] = constant; + return constant; } bool Window::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_ICON, p_name, theme_types); } bool Window::has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_STYLEBOX, p_name, theme_types); } bool Window::has_theme_font(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT, p_name, theme_types); } bool Window::has_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types); } bool Window::has_theme_color(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_COLOR, p_name, theme_types); } bool Window::has_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { List<StringName> theme_types; - _get_theme_type_dependencies(p_theme_type, &theme_types); - return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types); + theme_owner->get_theme_type_dependencies(this, p_theme_type, &theme_types); + return theme_owner->has_theme_item_in_types(Theme::DATA_TYPE_CONSTANT, p_name, theme_types); } float Window::get_theme_default_base_scale() const { - return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window); + return theme_owner->get_theme_default_base_scale(); } Ref<Font> Window::get_theme_default_font() const { - return Control::fetch_theme_default_font(theme_owner, theme_owner_window); + return theme_owner->get_theme_default_font(); } int Window::get_theme_default_font_size() const { - return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window); + return theme_owner->get_theme_default_font_size(); } Rect2i Window::get_parent_rect() const { @@ -1752,8 +1830,10 @@ void Window::_bind_methods() { } Window::Window() { + theme_owner = memnew(ThemeOwner); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); } Window::~Window() { + memdelete(theme_owner); } diff --git a/scene/main/window.h b/scene/main/window.h index a5b6b26104..8113117103 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -32,11 +32,13 @@ #define WINDOW_H #include "scene/main/viewport.h" +#include "scene/resources/theme.h" class Control; class Font; +class Shortcut; class StyleBox; -class Theme; +class ThemeOwner; class Window : public Viewport { GDCLASS(Window, Viewport) @@ -134,12 +136,20 @@ private: Window *exclusive_child = nullptr; HashSet<Window *> transient_children; - friend class Control; + ThemeOwner *theme_owner = nullptr; Ref<Theme> theme; - Control *theme_owner = nullptr; - Window *theme_owner_window = nullptr; StringName theme_type_variation; + mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache; + mutable HashMap<StringName, Theme::ThemeStyleMap> theme_style_cache; + mutable HashMap<StringName, Theme::ThemeFontMap> theme_font_cache; + mutable HashMap<StringName, Theme::ThemeFontSizeMap> theme_font_size_cache; + mutable HashMap<StringName, Theme::ThemeColorMap> theme_color_cache; + mutable HashMap<StringName, Theme::ThemeConstantMap> theme_constant_cache; + + void _theme_changed(); + void _invalidate_theme_cache(); + Viewport *embedder = nullptr; friend class Viewport; //friend back, can call the methods below @@ -151,10 +161,14 @@ private: void _event_callback(DisplayServer::WindowEvent p_event); virtual bool _can_consume_input_events() const override; + Ref<Shortcut> debugger_stop_shortcut; + protected: Viewport *_get_embedder() const; virtual Rect2i _popup_adjust_rect() const { return Rect2i(); } + virtual void _update_theme_item_cache(); + virtual void _post_popup() {} virtual Size2 _get_contents_minimum_size() const; static void _bind_methods(); @@ -254,13 +268,15 @@ public: void popup_centered(const Size2i &p_minsize = Size2i()); void popup_centered_clamped(const Size2i &p_size = Size2i(), float p_fallback_ratio = 0.75); + void set_theme_owner_node(Node *p_node); + Node *get_theme_owner_node() const; + bool has_theme_owner_node() const; + void set_theme(const Ref<Theme> &p_theme); Ref<Theme> get_theme() const; - void _theme_changed(); void set_theme_type_variation(const StringName &p_theme_type); StringName get_theme_type_variation() const; - _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const; Size2 get_contents_minimum_size() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 6c7bc552bf..72c57f1bfc 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -54,6 +54,7 @@ #include "scene/2d/mesh_instance_2d.h" #include "scene/2d/multimesh_instance_2d.h" #include "scene/2d/navigation_agent_2d.h" +#include "scene/2d/navigation_link_2d.h" #include "scene/2d/navigation_obstacle_2d.h" #include "scene/2d/parallax_background.h" #include "scene/2d/parallax_layer.h" @@ -142,7 +143,7 @@ #include "scene/resources/bit_map.h" #include "scene/resources/bone_map.h" #include "scene/resources/box_shape_3d.h" -#include "scene/resources/camera_effects.h" +#include "scene/resources/camera_attributes.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/capsule_shape_3d.h" #include "scene/resources/circle_shape_2d.h" @@ -152,6 +153,7 @@ #include "scene/resources/convex_polygon_shape_3d.h" #include "scene/resources/cylinder_shape_3d.h" #include "scene/resources/default_theme/default_theme.h" +#include "scene/resources/environment.h" #include "scene/resources/font.h" #include "scene/resources/gradient.h" #include "scene/resources/height_map_shape_3d.h" @@ -239,6 +241,7 @@ #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" #include "scene/3d/navigation_agent_3d.h" +#include "scene/3d/navigation_link_3d.h" #include "scene/3d/navigation_obstacle_3d.h" #include "scene/3d/navigation_region_3d.h" #include "scene/3d/node_3d.h" @@ -377,14 +380,14 @@ void register_scene_types() { GDREGISTER_CLASS(VSeparator); GDREGISTER_CLASS(TextureButton); GDREGISTER_CLASS(Container); - GDREGISTER_ABSTRACT_CLASS(BoxContainer); + GDREGISTER_CLASS(BoxContainer); GDREGISTER_CLASS(HBoxContainer); GDREGISTER_CLASS(VBoxContainer); GDREGISTER_CLASS(GridContainer); GDREGISTER_CLASS(CenterContainer); GDREGISTER_CLASS(ScrollContainer); GDREGISTER_CLASS(PanelContainer); - GDREGISTER_ABSTRACT_CLASS(FlowContainer); + GDREGISTER_CLASS(FlowContainer); GDREGISTER_CLASS(HFlowContainer); GDREGISTER_CLASS(VFlowContainer); @@ -421,7 +424,7 @@ void register_scene_types() { GDREGISTER_CLASS(MarginContainer); GDREGISTER_CLASS(SubViewportContainer); - GDREGISTER_ABSTRACT_CLASS(SplitContainer); + GDREGISTER_CLASS(SplitContainer); GDREGISTER_CLASS(HSplitContainer); GDREGISTER_CLASS(VSplitContainer); @@ -576,6 +579,7 @@ void register_scene_types() { GDREGISTER_CLASS(NavigationRegion3D); GDREGISTER_CLASS(NavigationAgent3D); GDREGISTER_CLASS(NavigationObstacle3D); + GDREGISTER_CLASS(NavigationLink3D); OS::get_singleton()->yield(); // may take time to init #endif // _3D_DISABLED @@ -638,21 +642,22 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeTexture2DArray); GDREGISTER_CLASS(VisualShaderNodeTexture3D); GDREGISTER_CLASS(VisualShaderNodeCubemap); - GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeUniform); - GDREGISTER_CLASS(VisualShaderNodeUniformRef); - GDREGISTER_CLASS(VisualShaderNodeFloatUniform); - GDREGISTER_CLASS(VisualShaderNodeIntUniform); - GDREGISTER_CLASS(VisualShaderNodeBooleanUniform); - GDREGISTER_CLASS(VisualShaderNodeColorUniform); - GDREGISTER_CLASS(VisualShaderNodeVec2Uniform); - GDREGISTER_CLASS(VisualShaderNodeVec3Uniform); - GDREGISTER_CLASS(VisualShaderNodeVec4Uniform); - GDREGISTER_CLASS(VisualShaderNodeTransformUniform); - GDREGISTER_CLASS(VisualShaderNodeTextureUniform); - GDREGISTER_CLASS(VisualShaderNodeTextureUniformTriplanar); - GDREGISTER_CLASS(VisualShaderNodeTexture2DArrayUniform); - GDREGISTER_CLASS(VisualShaderNodeTexture3DUniform); - GDREGISTER_CLASS(VisualShaderNodeCubemapUniform); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeParameter); + GDREGISTER_CLASS(VisualShaderNodeParameterRef); + GDREGISTER_CLASS(VisualShaderNodeFloatParameter); + GDREGISTER_CLASS(VisualShaderNodeIntParameter); + GDREGISTER_CLASS(VisualShaderNodeBooleanParameter); + GDREGISTER_CLASS(VisualShaderNodeColorParameter); + GDREGISTER_CLASS(VisualShaderNodeVec2Parameter); + GDREGISTER_CLASS(VisualShaderNodeVec3Parameter); + GDREGISTER_CLASS(VisualShaderNodeVec4Parameter); + GDREGISTER_CLASS(VisualShaderNodeTransformParameter); + GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeTextureParameter); + GDREGISTER_CLASS(VisualShaderNodeTexture2DParameter); + GDREGISTER_CLASS(VisualShaderNodeTextureParameterTriplanar); + GDREGISTER_CLASS(VisualShaderNodeTexture2DArrayParameter); + GDREGISTER_CLASS(VisualShaderNodeTexture3DParameter); + GDREGISTER_CLASS(VisualShaderNodeCubemapParameter); GDREGISTER_CLASS(VisualShaderNodeLinearSceneDepth); GDREGISTER_CLASS(VisualShaderNodeIf); GDREGISTER_CLASS(VisualShaderNodeSwitch); @@ -836,7 +841,9 @@ void register_scene_types() { GDREGISTER_CLASS(PhysicsMaterial); GDREGISTER_CLASS(World3D); GDREGISTER_CLASS(Environment); - GDREGISTER_CLASS(CameraEffects); + GDREGISTER_VIRTUAL_CLASS(CameraAttributes); + GDREGISTER_CLASS(CameraAttributesPhysical); + GDREGISTER_CLASS(CameraAttributesPractical); GDREGISTER_CLASS(World2D); GDREGISTER_VIRTUAL_CLASS(Texture); GDREGISTER_VIRTUAL_CLASS(Texture2D); @@ -931,6 +938,7 @@ void register_scene_types() { GDREGISTER_CLASS(NavigationRegion2D); GDREGISTER_CLASS(NavigationAgent2D); GDREGISTER_CLASS(NavigationObstacle2D); + GDREGISTER_CLASS(NavigationLink2D); OS::get_singleton()->yield(); // may take time to init @@ -1081,10 +1089,12 @@ void register_scene_types() { ClassDB::add_compatibility_class("VisibilityNotifier2D", "VisibleOnScreenNotifier2D"); ClassDB::add_compatibility_class("VisibilityNotifier3D", "VisibleOnScreenNotifier3D"); ClassDB::add_compatibility_class("VisualServer", "RenderingServer"); + ClassDB::add_compatibility_class("World", "World3D"); + + // VisualShader classes. ClassDB::add_compatibility_class("VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant"); ClassDB::add_compatibility_class("VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc"); ClassDB::add_compatibility_class("VisualShaderNodeScalarOp", "VisualShaderNodeFloatOp"); - ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform"); ClassDB::add_compatibility_class("VisualShaderNodeScalarClamp", "VisualShaderNodeClamp"); ClassDB::add_compatibility_class("VisualShaderNodeVectorClamp", "VisualShaderNodeClamp"); ClassDB::add_compatibility_class("VisualShaderNodeScalarInterp", "VisualShaderNodeMix"); @@ -1098,7 +1108,17 @@ void register_scene_types() { ClassDB::add_compatibility_class("VisualShaderNodeScalarTransformMult", "VisualShaderNodeTransformOp"); ClassDB::add_compatibility_class("VisualShaderNodeScalarDerivativeFunc", "VisualShaderNodeDerivativeFunc"); ClassDB::add_compatibility_class("VisualShaderNodeVectorDerivativeFunc", "VisualShaderNodeDerivativeFunc"); - ClassDB::add_compatibility_class("World", "World3D"); + + ClassDB::add_compatibility_class("VisualShaderNodeBooleanUniform", "VisualShaderNodeBooleanParameter"); + ClassDB::add_compatibility_class("VisualShaderNodeColorUniform", "VisualShaderNodeColorParameter"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatParameter"); + ClassDB::add_compatibility_class("VisualShaderNodeCubeMapUniform", "VisualShaderNodeCubeMapParameter"); + ClassDB::add_compatibility_class("VisualShaderNodeTextureUniform", "VisualShaderNodeTexture2DParameter"); + ClassDB::add_compatibility_class("VisualShaderNodeTextureUniformTriplanar", "VisualShaderNodeTextureParameterTriplanar"); + ClassDB::add_compatibility_class("VisualShaderNodeTransformUniform", "VisualShaderNodeTransformParameter"); + ClassDB::add_compatibility_class("VisualShaderNodeVec3Uniform", "VisualShaderNodeVec3Parameter"); + ClassDB::add_compatibility_class("VisualShaderNodeUniform", "VisualShaderNodeParameter"); + ClassDB::add_compatibility_class("VisualShaderNodeUniformRef", "VisualShaderNodeParameterRef"); // Renamed during 4.0 alpha, added to ease transition between alphas. ClassDB::add_compatibility_class("AudioStreamOGGVorbis", "AudioStreamOggVorbis"); @@ -1110,6 +1130,7 @@ void register_scene_types() { ClassDB::add_compatibility_class("StreamTexture2DArray", "CompressedTexture2DArray"); ClassDB::add_compatibility_class("StreamTexture3D", "CompressedTexture3D"); ClassDB::add_compatibility_class("StreamTextureLayered", "CompressedTextureLayered"); + ClassDB::add_compatibility_class("VisualShaderNodeFloatUniform", "VisualShaderNodeFloatParameter"); #endif /* DISABLE_DEPRECATED */ OS::get_singleton()->yield(); // may take time to init diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 9b1adde00a..0505f6b559 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -33,13 +33,18 @@ #include "core/io/image_loader.h" #include "core/variant/typed_array.h" -void BitMap::create(const Size2 &p_size) { +void BitMap::create(const Size2i &p_size) { ERR_FAIL_COND(p_size.width < 1); ERR_FAIL_COND(p_size.height < 1); + ERR_FAIL_COND(static_cast<int64_t>(p_size.width) * static_cast<int64_t>(p_size.height) > INT32_MAX); + + Error err = bitmask.resize((((p_size.width * p_size.height) - 1) / 8) + 1); + ERR_FAIL_COND(err != OK); + width = p_size.width; height = p_size.height; - bitmask.resize((((width * height) - 1) / 8) + 1); + memset(bitmask.ptrw(), 0, bitmask.size()); } @@ -49,7 +54,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol img->convert(Image::FORMAT_LA8); ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); - create(img->get_size()); + create(Size2i(img->get_width(), img->get_height())); const uint8_t *r = img->get_data().ptr(); uint8_t *w = bitmask.ptrw(); @@ -63,7 +68,7 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshol } } -void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) { +void BitMap::set_bit_rect(const Rect2i &p_rect, bool p_value) { Rect2i current = Rect2i(0, 0, width, height).intersection(p_rect); uint8_t *data = bitmask.ptrw(); @@ -91,7 +96,7 @@ int BitMap::get_true_bit_count() const { const uint8_t *d = bitmask.ptr(); int c = 0; - //fast, almost branchless version + // Fast, almost branchless version. for (int i = 0; i < ds; i++) { c += (d[i] & (1 << 7)) >> 7; @@ -107,14 +112,15 @@ int BitMap::get_true_bit_count() const { return c; } -void BitMap::set_bit(const Point2 &p_pos, bool p_value) { - int x = p_pos.x; - int y = p_pos.y; +void BitMap::set_bitv(const Point2i &p_pos, bool p_value) { + set_bit(p_pos.x, p_pos.y, p_value); +} - ERR_FAIL_INDEX(x, width); - ERR_FAIL_INDEX(y, height); +void BitMap::set_bit(int p_x, int p_y, bool p_value) { + ERR_FAIL_INDEX(p_x, width); + ERR_FAIL_INDEX(p_y, height); - int ofs = width * y + x; + int ofs = width * p_y + p_x; int bbyte = ofs / 8; int bbit = ofs % 8; @@ -129,21 +135,23 @@ void BitMap::set_bit(const Point2 &p_pos, bool p_value) { bitmask.write[bbyte] = b; } -bool BitMap::get_bit(const Point2 &p_pos) const { - int x = Math::fast_ftoi(p_pos.x); - int y = Math::fast_ftoi(p_pos.y); - ERR_FAIL_INDEX_V(x, width, false); - ERR_FAIL_INDEX_V(y, height, false); +bool BitMap::get_bitv(const Point2i &p_pos) const { + return get_bit(p_pos.x, p_pos.y); +} + +bool BitMap::get_bit(int p_x, int p_y) const { + ERR_FAIL_INDEX_V(p_x, width, false); + ERR_FAIL_INDEX_V(p_y, height, false); - int ofs = width * y + x; + int ofs = width * p_y + p_x; int bbyte = ofs / 8; int bbit = ofs % 8; return (bitmask[bbyte] & (1 << bbit)) != 0; } -Size2 BitMap::get_size() const { - return Size2(width, height); +Size2i BitMap::get_size() const { + return Size2i(width, height); } void BitMap::_set_data(const Dictionary &p_d) { @@ -161,13 +169,13 @@ Dictionary BitMap::_get_data() const { return d; } -Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) const { +Vector<Vector2> BitMap::_march_square(const Rect2i &p_rect, const Point2i &p_start) const { int stepx = 0; int stepy = 0; int prevx = 0; int prevy = 0; - int startx = start.x; - int starty = start.y; + int startx = p_start.x; + int starty = p_start.y; int curx = startx; int cury = starty; unsigned int count = 0; @@ -176,7 +184,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) Vector<Vector2> _points; do { int sv = 0; - { //square value + { // Square value /* checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent @@ -187,13 +195,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) +---+---+ */ Point2i tl = Point2i(curx - 1, cury - 1); - sv += (rect.has_point(tl) && get_bit(tl)) ? 1 : 0; + sv += (p_rect.has_point(tl) && get_bitv(tl)) ? 1 : 0; Point2i tr = Point2i(curx, cury - 1); - sv += (rect.has_point(tr) && get_bit(tr)) ? 2 : 0; + sv += (p_rect.has_point(tr) && get_bitv(tr)) ? 2 : 0; Point2i bl = Point2i(curx - 1, cury); - sv += (rect.has_point(bl) && get_bit(bl)) ? 4 : 0; + sv += (p_rect.has_point(bl) && get_bitv(bl)) ? 4 : 0; Point2i br = Point2i(curx, cury); - sv += (rect.has_point(br) && get_bit(br)) ? 8 : 0; + sv += (p_rect.has_point(br) && get_bitv(br)) ? 8 : 0; ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>()); } @@ -303,16 +311,16 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) default: ERR_PRINT("this shouldn't happen."); } - //little optimization - // if previous direction is same as current direction, - // then we should modify the last vec to current + // Small optimization: + // If the previous direction is same as the current direction, + // then we should modify the last vector to current. curx += stepx; cury += stepy; if (stepx == prevx && stepy == prevy) { - _points.write[_points.size() - 1].x = (float)(curx - rect.position.x); - _points.write[_points.size() - 1].y = (float)(cury + rect.position.y); + _points.write[_points.size() - 1].x = (float)(curx - p_rect.position.x); + _points.write[_points.size() - 1].y = (float)(cury + p_rect.position.y); } else { - _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y))); + _points.push_back(Vector2((float)(curx - p_rect.position.x), (float)(cury + p_rect.position.y))); } count++; @@ -348,7 +356,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) { int index = -1; float dist = 0.0; - //not looping first and last point + // Not looping first and last point. for (size_t i = 1, size = v.size(); i < size - 1; ++i) { float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]); if (cdist > dist) { @@ -385,9 +393,9 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) { static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, float epsilon) { int size = points.size(); - // if there are less than 3 points, then we have nothing + // If there are less than 3 points, then we have nothing. ERR_FAIL_COND_V(size < 3, Vector<Vector2>()); - // if there are less than 9 points (but more than 3), then we don't need to reduce it + // If there are less than 9 points (but more than 3), then we don't need to reduce it. if (size < 9) { return points; } @@ -412,9 +420,9 @@ struct FillBitsStackEntry { }; static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) { - // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps + // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps. Vector<FillBitsStackEntry> stack; - // Tracking size since we won't be shrinking the stack vector + // Tracking size since we won't be shrinking the stack vector. int stack_size = 0; Point2i pos = p_pos; @@ -433,10 +441,10 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_ for (int i = next_i; i <= pos.x + 1; i++) { for (int j = next_j; j <= pos.y + 1; j++) { if (popped) { - // The next loop over j must start normally + // The next loop over j must start normally. next_j = pos.y; popped = false; - // Skip because an iteration was already executed with current counter values + // Skip because an iteration was already executed with current counter values. continue; } @@ -447,11 +455,11 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_ continue; } - if (p_map->get_bit(Vector2(i, j))) { + if (p_map->get_bit(i, j)) { continue; - } else if (p_src->get_bit(Vector2(i, j))) { - p_map->set_bit(Vector2(i, j), true); + } else if (p_src->get_bit(i, j)) { + p_map->set_bit(i, j, true); FillBitsStackEntry se = { pos, i, j }; stack.resize(MAX(stack_size + 1, stack.size())); @@ -482,7 +490,7 @@ static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_ print_verbose("BitMap: Max stack size: " + itos(stack.size())); } -Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const { +Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon) const { Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect); print_verbose("BitMap: Rect: " + r); @@ -494,7 +502,7 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, flo Vector<Vector<Vector2>> polygons; for (int i = r.position.y; i < r.position.y + r.size.height; i++) { for (int j = r.position.x; j < r.position.x + r.size.width; j++) { - if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) { + if (!fill->get_bit(j, i) && get_bit(j, i)) { fill_bits(this, fill, Point2i(j, i), r); Vector<Vector2> polygon = _march_square(r, Point2i(j, i)); @@ -515,7 +523,7 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, flo return polygons; } -void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { +void BitMap::grow_mask(int p_pixels, const Rect2i &p_rect) { if (p_pixels == 0) { return; } @@ -532,7 +540,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { for (int i = r.position.y; i < r.position.y + r.size.height; i++) { for (int j = r.position.x; j < r.position.x + r.size.width; j++) { - if (bit_value == get_bit(Point2(j, i))) { + if (bit_value == get_bit(j, i)) { continue; } @@ -543,7 +551,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { bool outside = false; if ((x < p_rect.position.x) || (x >= p_rect.position.x + p_rect.size.x) || (y < p_rect.position.y) || (y >= p_rect.position.y + p_rect.size.y)) { - // outside of rectangle counts as bit not set + // Outside of rectangle counts as bit not set. if (!bit_value) { outside = true; } else { @@ -556,7 +564,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { continue; } - if (outside || (bit_value == copy->get_bit(Point2(x, y)))) { + if (outside || (bit_value == copy->get_bit(x, y))) { found = true; break; } @@ -567,20 +575,20 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { } if (found) { - set_bit(Point2(j, i), bit_value); + set_bit(j, i, bit_value); } } } } -void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) { +void BitMap::shrink_mask(int p_pixels, const Rect2i &p_rect) { grow_mask(-p_pixels, p_rect); } -TypedArray<PackedVector2Array> BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const { +TypedArray<PackedVector2Array> BitMap::_opaque_to_polygons_bind(const Rect2i &p_rect, float p_epsilon) const { Vector<Vector<Vector2>> result = clip_opaque_to_polygons(p_rect, p_epsilon); - // Convert result to bindable types + // Convert result to bindable types. TypedArray<PackedVector2Array> result_array; result_array.resize(result.size()); @@ -603,15 +611,25 @@ TypedArray<PackedVector2Array> BitMap::_opaque_to_polygons_bind(const Rect2 &p_r return result_array; } -void BitMap::resize(const Size2 &p_new_size) { +void BitMap::resize(const Size2i &p_new_size) { + ERR_FAIL_COND(p_new_size.width < 0 || p_new_size.height < 0); + if (p_new_size == get_size()) { + return; + } + Ref<BitMap> new_bitmap; new_bitmap.instantiate(); new_bitmap->create(p_new_size); - int lw = MIN(width, p_new_size.width); - int lh = MIN(height, p_new_size.height); + // also allow for upscaling + int lw = (width == 0) ? 0 : p_new_size.width; + int lh = (height == 0) ? 0 : p_new_size.height; + + float scale_x = ((float)width / p_new_size.width); + float scale_y = ((float)height / p_new_size.height); for (int x = 0; x < lw; x++) { for (int y = 0; y < lh; y++) { - new_bitmap->set_bit(Vector2(x, y), get_bit(Vector2(x, y))); + bool new_bit = get_bit(x * scale_x, y * scale_y); + new_bitmap->set_bit(x, y, new_bit); } } @@ -627,14 +645,16 @@ Ref<Image> BitMap::convert_to_image() const { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { - image->set_pixel(i, j, get_bit(Point2(i, j)) ? Color(1, 1, 1) : Color(0, 0, 0)); + image->set_pixel(i, j, get_bit(i, j) ? Color(1, 1, 1) : Color(0, 0, 0)); } } return image; } -void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) { +void BitMap::blit(const Vector2i &p_pos, const Ref<BitMap> &p_bitmap) { + ERR_FAIL_COND_MSG(p_bitmap.is_null(), "It's not a reference to a valid BitMap object."); + int x = p_pos.x; int y = p_pos.y; int w = p_bitmap->get_size().width; @@ -650,8 +670,8 @@ void BitMap::blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap) { if (py < 0 || py >= height) { continue; } - if (p_bitmap->get_bit(Vector2(i, j))) { - set_bit(Vector2(x, y), true); + if (p_bitmap->get_bit(i, j)) { + set_bit(px, py, true); } } } @@ -661,8 +681,10 @@ void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1)); - ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit); - ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit); + ClassDB::bind_method(D_METHOD("set_bitv", "position", "bit"), &BitMap::set_bitv); + ClassDB::bind_method(D_METHOD("set_bit", "x", "y", "bit"), &BitMap::set_bit); + ClassDB::bind_method(D_METHOD("get_bitv", "position"), &BitMap::get_bitv); + ClassDB::bind_method(D_METHOD("get_bit", "x", "y"), &BitMap::get_bit); ClassDB::bind_method(D_METHOD("set_bit_rect", "rect", "bit"), &BitMap::set_bit_rect); ClassDB::bind_method(D_METHOD("get_true_bit_count"), &BitMap::get_true_bit_count); @@ -681,5 +703,3 @@ void BitMap::_bind_methods() { } BitMap::BitMap() {} - -////////////////////////////////////// diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index d8507dfa8b..291ed8c4d0 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -46,9 +46,9 @@ class BitMap : public Resource { int width = 0; int height = 0; - Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const; + Vector<Vector2> _march_square(const Rect2i &p_rect, const Point2i &p_start) const; - TypedArray<PackedVector2Array> _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const; + TypedArray<PackedVector2Array> _opaque_to_polygons_bind(const Rect2i &p_rect, float p_epsilon) const; protected: void _set_data(const Dictionary &p_d); @@ -57,24 +57,27 @@ protected: static void _bind_methods(); public: - void create(const Size2 &p_size); + void create(const Size2i &p_size); void create_from_image_alpha(const Ref<Image> &p_image, float p_threshold = 0.1); - void set_bit(const Point2 &p_pos, bool p_value); - bool get_bit(const Point2 &p_pos) const; - void set_bit_rect(const Rect2 &p_rect, bool p_value); + void set_bitv(const Point2i &p_pos, bool p_value); + void set_bit(int p_x, int p_y, bool p_value); + void set_bit_rect(const Rect2i &p_rect, bool p_value); + bool get_bitv(const Point2i &p_pos) const; + bool get_bit(int p_x, int p_y) const; + int get_true_bit_count() const; - Size2 get_size() const; - void resize(const Size2 &p_new_size); + Size2i get_size() const; + void resize(const Size2i &p_new_size); - void grow_mask(int p_pixels, const Rect2 &p_rect); - void shrink_mask(int p_pixels, const Rect2 &p_rect); + void grow_mask(int p_pixels, const Rect2i &p_rect); + void shrink_mask(int p_pixels, const Rect2i &p_rect); - void blit(const Vector2 &p_pos, const Ref<BitMap> &p_bitmap); + void blit(const Vector2i &p_pos, const Ref<BitMap> &p_bitmap); Ref<Image> convert_to_image() const; - Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const; + Vector<Vector<Vector2>> clip_opaque_to_polygons(const Rect2i &p_rect, float p_epsilon = 2.0) const; BitMap(); }; diff --git a/scene/resources/camera_attributes.cpp b/scene/resources/camera_attributes.cpp new file mode 100644 index 0000000000..3c322f32b6 --- /dev/null +++ b/scene/resources/camera_attributes.cpp @@ -0,0 +1,493 @@ +/*************************************************************************/ +/* camera_attributes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "camera_attributes.h" + +#include "core/config/project_settings.h" +#include "servers/rendering_server.h" + +void CameraAttributes::set_exposure_multiplier(float p_multiplier) { + exposure_multiplier = p_multiplier; + _update_exposure(); + emit_changed(); +} + +float CameraAttributes::get_exposure_multiplier() const { + return exposure_multiplier; +} + +void CameraAttributes::set_exposure_sensitivity(float p_sensitivity) { + exposure_sensitivity = p_sensitivity; + _update_exposure(); + emit_changed(); +} + +float CameraAttributes::get_exposure_sensitivity() const { + return exposure_sensitivity; +} + +void CameraAttributes::_update_exposure() { + float exposure_normalization = 1.0; + // Ignore physical properties if not using physical light units. + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + exposure_normalization = calculate_exposure_normalization(); + } + + RS::get_singleton()->camera_attributes_set_exposure(camera_attributes, exposure_multiplier, exposure_normalization); +} + +void CameraAttributes::set_auto_exposure_enabled(bool p_enabled) { + auto_exposure_enabled = p_enabled; + _update_auto_exposure(); + notify_property_list_changed(); +} + +bool CameraAttributes::is_auto_exposure_enabled() const { + return auto_exposure_enabled; +} + +void CameraAttributes::set_auto_exposure_speed(float p_auto_exposure_speed) { + auto_exposure_speed = p_auto_exposure_speed; + _update_auto_exposure(); +} + +float CameraAttributes::get_auto_exposure_speed() const { + return auto_exposure_speed; +} + +void CameraAttributes::set_auto_exposure_scale(float p_auto_exposure_scale) { + auto_exposure_scale = p_auto_exposure_scale; + _update_auto_exposure(); +} + +float CameraAttributes::get_auto_exposure_scale() const { + return auto_exposure_scale; +} + +RID CameraAttributes::get_rid() const { + return camera_attributes; +} + +void CameraAttributes::_validate_property(PropertyInfo &p_property) const { + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && p_property.name == "exposure_sensitivity") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + return; + } + + if (p_property.name.begins_with("auto_exposure_") && p_property.name != "auto_exposure_enabled" && !auto_exposure_enabled) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + return; + } +} + +void CameraAttributes::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_exposure_multiplier", "multiplier"), &CameraAttributes::set_exposure_multiplier); + ClassDB::bind_method(D_METHOD("get_exposure_multiplier"), &CameraAttributes::get_exposure_multiplier); + ClassDB::bind_method(D_METHOD("set_exposure_sensitivity", "sensitivity"), &CameraAttributes::set_exposure_sensitivity); + ClassDB::bind_method(D_METHOD("get_exposure_sensitivity"), &CameraAttributes::get_exposure_sensitivity); + + ClassDB::bind_method(D_METHOD("set_auto_exposure_enabled", "enabled"), &CameraAttributes::set_auto_exposure_enabled); + ClassDB::bind_method(D_METHOD("is_auto_exposure_enabled"), &CameraAttributes::is_auto_exposure_enabled); + ClassDB::bind_method(D_METHOD("set_auto_exposure_speed", "exposure_speed"), &CameraAttributes::set_auto_exposure_speed); + ClassDB::bind_method(D_METHOD("get_auto_exposure_speed"), &CameraAttributes::get_auto_exposure_speed); + ClassDB::bind_method(D_METHOD("set_auto_exposure_scale", "exposure_grey"), &CameraAttributes::set_auto_exposure_scale); + ClassDB::bind_method(D_METHOD("get_auto_exposure_scale"), &CameraAttributes::get_auto_exposure_scale); + + ADD_GROUP("Exposure", "exposure"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_sensitivity", PROPERTY_HINT_RANGE, "0.1,32000.0,0.1,suffix:ISO"), "set_exposure_sensitivity", "get_exposure_sensitivity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_multiplier", PROPERTY_HINT_RANGE, "0.0,2048.0,0.001"), "set_exposure_multiplier", "get_exposure_multiplier"); + + ADD_GROUP("Auto Exposure", "auto_exposure_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_auto_exposure_enabled", "is_auto_exposure_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_scale", "get_auto_exposure_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_auto_exposure_speed", "get_auto_exposure_speed"); +} + +CameraAttributes::CameraAttributes() { + camera_attributes = RS::get_singleton()->camera_attributes_create(); +} + +CameraAttributes::~CameraAttributes() { + RS::get_singleton()->free(camera_attributes); +} + +////////////////////////////////////////////////////// +/* CameraAttributesPractical */ + +void CameraAttributesPractical::set_dof_blur_far_enabled(bool p_enabled) { + dof_blur_far_enabled = p_enabled; + _update_dof_blur(); + notify_property_list_changed(); +} + +bool CameraAttributesPractical::is_dof_blur_far_enabled() const { + return dof_blur_far_enabled; +} + +void CameraAttributesPractical::set_dof_blur_far_distance(float p_distance) { + dof_blur_far_distance = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_far_distance() const { + return dof_blur_far_distance; +} + +void CameraAttributesPractical::set_dof_blur_far_transition(float p_distance) { + dof_blur_far_transition = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_far_transition() const { + return dof_blur_far_transition; +} + +void CameraAttributesPractical::set_dof_blur_near_enabled(bool p_enabled) { + dof_blur_near_enabled = p_enabled; + _update_dof_blur(); + notify_property_list_changed(); +} + +bool CameraAttributesPractical::is_dof_blur_near_enabled() const { + return dof_blur_near_enabled; +} + +void CameraAttributesPractical::set_dof_blur_near_distance(float p_distance) { + dof_blur_near_distance = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_near_distance() const { + return dof_blur_near_distance; +} + +void CameraAttributesPractical::set_dof_blur_near_transition(float p_distance) { + dof_blur_near_transition = p_distance; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_near_transition() const { + return dof_blur_near_transition; +} + +void CameraAttributesPractical::set_dof_blur_amount(float p_amount) { + dof_blur_amount = p_amount; + _update_dof_blur(); +} + +float CameraAttributesPractical::get_dof_blur_amount() const { + return dof_blur_amount; +} + +void CameraAttributesPractical::_update_dof_blur() { + RS::get_singleton()->camera_attributes_set_dof_blur( + get_rid(), + dof_blur_far_enabled, + dof_blur_far_distance, + dof_blur_far_transition, + dof_blur_near_enabled, + dof_blur_near_distance, + dof_blur_near_transition, + dof_blur_amount); +} + +float CameraAttributesPractical::calculate_exposure_normalization() const { + return exposure_sensitivity / 3072007.0; // Matches exposure normalization for default CameraAttributesPhysical at ISO 100. +} + +void CameraAttributesPractical::set_auto_exposure_min_sensitivity(float p_min) { + auto_exposure_min = p_min; + _update_auto_exposure(); +} + +float CameraAttributesPractical::get_auto_exposure_min_sensitivity() const { + return auto_exposure_min; +} + +void CameraAttributesPractical::set_auto_exposure_max_sensitivity(float p_max) { + auto_exposure_max = p_max; + _update_auto_exposure(); +} + +float CameraAttributesPractical::get_auto_exposure_max_sensitivity() const { + return auto_exposure_max; +} + +void CameraAttributesPractical::_update_auto_exposure() { + RS::get_singleton()->camera_attributes_set_auto_exposure( + get_rid(), + auto_exposure_enabled, + auto_exposure_min * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance + auto_exposure_max * ((12.5 / 100.0) / exposure_sensitivity), // Convert from Sensitivity to Luminance + auto_exposure_speed, + auto_exposure_scale); + emit_changed(); +} + +void CameraAttributesPractical::_validate_property(PropertyInfo &p_property) const { + if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) || + (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition"))) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + } +} + +void CameraAttributesPractical::_bind_methods() { + // DOF blur + + ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_far_enabled); + ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraAttributesPractical::is_dof_blur_far_enabled); + ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraAttributesPractical::set_dof_blur_far_distance); + ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraAttributesPractical::get_dof_blur_far_distance); + ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraAttributesPractical::set_dof_blur_far_transition); + ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraAttributesPractical::get_dof_blur_far_transition); + + ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraAttributesPractical::set_dof_blur_near_enabled); + ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraAttributesPractical::is_dof_blur_near_enabled); + ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraAttributesPractical::set_dof_blur_near_distance); + ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraAttributesPractical::get_dof_blur_near_distance); + ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraAttributesPractical::set_dof_blur_near_transition); + ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraAttributesPractical::get_dof_blur_near_transition); + ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraAttributesPractical::set_dof_blur_amount); + ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraAttributesPractical::get_dof_blur_amount); + + ClassDB::bind_method(D_METHOD("set_auto_exposure_max_sensitivity", "max_sensitivity"), &CameraAttributesPractical::set_auto_exposure_max_sensitivity); + ClassDB::bind_method(D_METHOD("get_auto_exposure_max_sensitivity"), &CameraAttributesPractical::get_auto_exposure_max_sensitivity); + ClassDB::bind_method(D_METHOD("set_auto_exposure_min_sensitivity", "min_sensitivity"), &CameraAttributesPractical::set_auto_exposure_min_sensitivity); + ClassDB::bind_method(D_METHOD("get_auto_exposure_min_sensitivity"), &CameraAttributesPractical::get_auto_exposure_min_sensitivity); + + ADD_GROUP("DOF Blur", "dof_blur_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); + + ADD_GROUP("Auto Exposure", "auto_exposure_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_sensitivity", PROPERTY_HINT_RANGE, "0,1600,0.01,or_greater,suffic:ISO"), "set_auto_exposure_min_sensitivity", "get_auto_exposure_min_sensitivity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_sensitivity", PROPERTY_HINT_RANGE, "0,64000,0.1,or_greater,suffic:ISO"), "set_auto_exposure_max_sensitivity", "get_auto_exposure_max_sensitivity"); +} + +CameraAttributesPractical::CameraAttributesPractical() { + _update_dof_blur(); + _update_exposure(); + set_auto_exposure_min_sensitivity(0.0); + set_auto_exposure_max_sensitivity(800.0); + notify_property_list_changed(); +} + +CameraAttributesPractical::~CameraAttributesPractical() { +} + +////////////////////////////////////////////////////// +/* CameraAttributesPhysical */ + +void CameraAttributesPhysical::set_aperture(float p_aperture) { + exposure_aperture = p_aperture; + _update_exposure(); + _update_frustum(); +} + +float CameraAttributesPhysical::get_aperture() const { + return exposure_aperture; +} + +void CameraAttributesPhysical::set_shutter_speed(float p_shutter_speed) { + exposure_shutter_speed = p_shutter_speed; + _update_exposure(); +} + +float CameraAttributesPhysical::get_shutter_speed() const { + return exposure_shutter_speed; +} + +void CameraAttributesPhysical::set_focal_length(float p_focal_length) { + frustum_focal_length = p_focal_length; + _update_frustum(); + emit_changed(); +} + +float CameraAttributesPhysical::get_focal_length() const { + return frustum_focal_length; +} + +void CameraAttributesPhysical::set_focus_distance(float p_focus_distance) { + frustum_focus_distance = p_focus_distance; + _update_frustum(); +} + +float CameraAttributesPhysical::get_focus_distance() const { + return frustum_focus_distance; +} + +void CameraAttributesPhysical::set_near(real_t p_near) { + frustum_near = p_near; + _update_frustum(); + emit_changed(); +} + +real_t CameraAttributesPhysical::get_near() const { + return frustum_near; +} + +void CameraAttributesPhysical::set_far(real_t p_far) { + frustum_far = p_far; + _update_frustum(); + emit_changed(); +} + +real_t CameraAttributesPhysical::get_far() const { + return frustum_far; +} + +real_t CameraAttributesPhysical::get_fov() const { + return frustum_fov; +} + +void CameraAttributesPhysical::_update_frustum() { + //https://en.wikipedia.org/wiki/Circle_of_confusion#Circle_of_confusion_diameter_limit_based_on_d/1500 + Vector2i sensor_size = Vector2i(36, 24); // Matches high-end DSLR, could be made variable if there is demand. + float CoC = sensor_size.length() / 1500.0; + + frustum_fov = Math::rad_to_deg(2 * atan(sensor_size.height / (2 * frustum_focal_length))); + + // Based on https://en.wikipedia.org/wiki/Depth_of_field. + float u = MAX(frustum_focus_distance * 1000.0, frustum_focal_length + 1.0); // Focus distance expressed in mm and clamped to at least 1 mm away from lens. + float hyperfocal_length = frustum_focal_length + ((frustum_focal_length * frustum_focal_length) / (exposure_aperture * CoC)); + + // This computes the start and end of the depth of field. Anything between these two points has a Circle of Confusino so small + // that it is not picked up by the camera sensors. + // To be properly physically-based, we would run the DoF shader at all depths. To be efficient, we are only running it where the CoC + // will be visible, this introduces some value shifts in the near field that we have to compensate for below. + float near = ((hyperfocal_length * u) / (hyperfocal_length + (u - frustum_focal_length))) / 1000.0; // In meters. + float far = ((hyperfocal_length * u) / (hyperfocal_length - (u - frustum_focal_length))) / 1000.0; // In meters. + float scale = (frustum_focal_length / (u - frustum_focal_length)) * (frustum_focal_length / exposure_aperture); + + bool use_far = (far < frustum_far) && (far > 0.0); + bool use_near = near > frustum_near; + RS::get_singleton()->camera_attributes_set_dof_blur( + get_rid(), + use_far, + u / 1000.0, // Focus distance clampd to focal length expressed in meters. + -1.0, // Negative to tell Bokeh effect to use physically-based scaling. + use_near, + u / 1000.0, + -1.0, + scale / 5.0); // Arbitrary scaling to get close to how much blur there should be. +} + +float CameraAttributesPhysical::calculate_exposure_normalization() const { + const float e = (exposure_aperture * exposure_aperture) * exposure_shutter_speed * (100.0 / exposure_sensitivity); + return 1.0 / (e * 1.2); +} + +void CameraAttributesPhysical::set_auto_exposure_min_exposure_value(float p_min) { + auto_exposure_min = p_min; + _update_auto_exposure(); +} + +float CameraAttributesPhysical::get_auto_exposure_min_exposure_value() const { + return auto_exposure_min; +} + +void CameraAttributesPhysical::set_auto_exposure_max_exposure_value(float p_max) { + auto_exposure_max = p_max; + _update_auto_exposure(); +} + +float CameraAttributesPhysical::get_auto_exposure_max_exposure_value() const { + return auto_exposure_max; +} + +void CameraAttributesPhysical::_update_auto_exposure() { + RS::get_singleton()->camera_attributes_set_auto_exposure( + get_rid(), + auto_exposure_enabled, + pow(2.0, auto_exposure_min) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance + pow(2.0, auto_exposure_max) * (12.5 / exposure_sensitivity), // Convert from EV100 to Luminance + auto_exposure_speed, + auto_exposure_scale); + emit_changed(); +} + +void CameraAttributesPhysical::_validate_property(PropertyInfo &property) const { + if (!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units") && (property.name == "exposure_aperture" || property.name == "exposure_shutter_speed")) { + property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL; + return; + } +} + +void CameraAttributesPhysical::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_aperture", "aperture"), &CameraAttributesPhysical::set_aperture); + ClassDB::bind_method(D_METHOD("get_aperture"), &CameraAttributesPhysical::get_aperture); + ClassDB::bind_method(D_METHOD("set_shutter_speed", "shutter_speed"), &CameraAttributesPhysical::set_shutter_speed); + ClassDB::bind_method(D_METHOD("get_shutter_speed"), &CameraAttributesPhysical::get_shutter_speed); + + ClassDB::bind_method(D_METHOD("set_focal_length", "focal_length"), &CameraAttributesPhysical::set_focal_length); + ClassDB::bind_method(D_METHOD("get_focal_length"), &CameraAttributesPhysical::get_focal_length); + ClassDB::bind_method(D_METHOD("set_focus_distance", "focus_distance"), &CameraAttributesPhysical::set_focus_distance); + ClassDB::bind_method(D_METHOD("get_focus_distance"), &CameraAttributesPhysical::get_focus_distance); + ClassDB::bind_method(D_METHOD("set_near", "near"), &CameraAttributesPhysical::set_near); + ClassDB::bind_method(D_METHOD("get_near"), &CameraAttributesPhysical::get_near); + ClassDB::bind_method(D_METHOD("set_far", "far"), &CameraAttributesPhysical::set_far); + ClassDB::bind_method(D_METHOD("get_far"), &CameraAttributesPhysical::get_far); + ClassDB::bind_method(D_METHOD("get_fov"), &CameraAttributesPhysical::get_fov); + + ClassDB::bind_method(D_METHOD("set_auto_exposure_max_exposure_value", "exposure_value_max"), &CameraAttributesPhysical::set_auto_exposure_max_exposure_value); + ClassDB::bind_method(D_METHOD("get_auto_exposure_max_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_max_exposure_value); + ClassDB::bind_method(D_METHOD("set_auto_exposure_min_exposure_value", "exposure_value_min"), &CameraAttributesPhysical::set_auto_exposure_min_exposure_value); + ClassDB::bind_method(D_METHOD("get_auto_exposure_min_exposure_value"), &CameraAttributesPhysical::get_auto_exposure_min_exposure_value); + + ADD_GROUP("Frustum", "frustum_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focus_distance", PROPERTY_HINT_RANGE, "0.01,4000.0,0.01,suffix:m"), "set_focus_distance", "get_focus_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_focal_length", PROPERTY_HINT_RANGE, "1.0,800.0,0.01,exp,suffix:mm"), "set_focal_length", "get_focal_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frustum_far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far"); + + ADD_GROUP("Exposure", "exposure"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_aperture", PROPERTY_HINT_RANGE, "0.5,64.0,0.01,exp,suffix:f-stop"), "set_aperture", "get_aperture"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure_shutter_speed", PROPERTY_HINT_RANGE, "0.1,8000.0,0.001,suffix:1/s"), "set_shutter_speed", "get_shutter_speed"); + + ADD_GROUP("Auto Exposure", "auto_exposure_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_min_exposure_value", "get_auto_exposure_min_exposure_value"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_exposure_value", PROPERTY_HINT_RANGE, "-16.0,16.0,0.01,or_greater,suffix:EV100"), "set_auto_exposure_max_exposure_value", "get_auto_exposure_max_exposure_value"); +}; + +CameraAttributesPhysical::CameraAttributesPhysical() { + _update_exposure(); + _update_frustum(); + set_auto_exposure_min_exposure_value(-8); + set_auto_exposure_max_exposure_value(10); // Use a wide range by default to feel more like a real camera. + notify_property_list_changed(); +} + +CameraAttributesPhysical::~CameraAttributesPhysical() { +} diff --git a/scene/resources/camera_attributes.h b/scene/resources/camera_attributes.h new file mode 100644 index 0000000000..c4c783af29 --- /dev/null +++ b/scene/resources/camera_attributes.h @@ -0,0 +1,183 @@ +/*************************************************************************/ +/* camera_attributes.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef CAMERA_ATTRIBUTES_H +#define CAMERA_ATTRIBUTES_H + +#include "core/io/resource.h" +#include "core/templates/rid.h" + +class CameraAttributes : public Resource { + GDCLASS(CameraAttributes, Resource); + +private: + RID camera_attributes; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; + + float exposure_multiplier = 1.0; + float exposure_sensitivity = 100.0; // In ISO. + void _update_exposure(); + + bool auto_exposure_enabled = false; + float auto_exposure_min = 0.01; + float auto_exposure_max = 64.0; + float auto_exposure_speed = 0.5; + float auto_exposure_scale = 0.4; + virtual void _update_auto_exposure(){}; + +public: + virtual RID get_rid() const override; + virtual float calculate_exposure_normalization() const { return 1.0; } + + void set_exposure_multiplier(float p_multiplier); + float get_exposure_multiplier() const; + void set_exposure_sensitivity(float p_sensitivity); + float get_exposure_sensitivity() const; + + void set_auto_exposure_enabled(bool p_enabled); + bool is_auto_exposure_enabled() const; + void set_auto_exposure_speed(float p_auto_exposure_speed); + float get_auto_exposure_speed() const; + void set_auto_exposure_scale(float p_auto_exposure_scale); + float get_auto_exposure_scale() const; + + CameraAttributes(); + ~CameraAttributes(); +}; + +class CameraAttributesPractical : public CameraAttributes { + GDCLASS(CameraAttributesPractical, CameraAttributes); + +private: + // DOF blur + bool dof_blur_far_enabled = false; + float dof_blur_far_distance = 10.0; + float dof_blur_far_transition = 5.0; + + bool dof_blur_near_enabled = false; + float dof_blur_near_distance = 2.0; + float dof_blur_near_transition = 1.0; + + float dof_blur_amount = 0.1; + void _update_dof_blur(); + + virtual void _update_auto_exposure() override; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; + +public: + // DOF blur + void set_dof_blur_far_enabled(bool p_enabled); + bool is_dof_blur_far_enabled() const; + void set_dof_blur_far_distance(float p_distance); + float get_dof_blur_far_distance() const; + void set_dof_blur_far_transition(float p_distance); + float get_dof_blur_far_transition() const; + + void set_dof_blur_near_enabled(bool p_enabled); + bool is_dof_blur_near_enabled() const; + void set_dof_blur_near_distance(float p_distance); + float get_dof_blur_near_distance() const; + void set_dof_blur_near_transition(float p_distance); + float get_dof_blur_near_transition() const; + void set_dof_blur_amount(float p_amount); + float get_dof_blur_amount() const; + + void set_auto_exposure_min_sensitivity(float p_min); + float get_auto_exposure_min_sensitivity() const; + void set_auto_exposure_max_sensitivity(float p_max); + float get_auto_exposure_max_sensitivity() const; + + virtual float calculate_exposure_normalization() const override; + + CameraAttributesPractical(); + ~CameraAttributesPractical(); +}; + +class CameraAttributesPhysical : public CameraAttributes { + GDCLASS(CameraAttributesPhysical, CameraAttributes); + +private: + // Exposure + float exposure_aperture = 16.0; // In f-stops; + float exposure_shutter_speed = 100.0; // In 1 / seconds; + + // Camera properties. + float frustum_focal_length = 35.0; // In millimeters. + float frustum_focus_distance = 10.0; // In Meters. + real_t frustum_near = 0.05; + real_t frustum_far = 4000.0; + real_t frustum_fov = 75.0; + void _update_frustum(); + + virtual void _update_auto_exposure() override; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; + +public: + void set_aperture(float p_aperture); + float get_aperture() const; + + void set_shutter_speed(float p_shutter_speed); + float get_shutter_speed() const; + + void set_focal_length(float p_focal_length); + float get_focal_length() const; + + void set_focus_distance(float p_focus_distance); + float get_focus_distance() const; + + void set_near(real_t p_near); + real_t get_near() const; + + void set_far(real_t p_far); + real_t get_far() const; + + real_t get_fov() const; + + void set_auto_exposure_min_exposure_value(float p_min); + float get_auto_exposure_min_exposure_value() const; + void set_auto_exposure_max_exposure_value(float p_max); + float get_auto_exposure_max_exposure_value() const; + + virtual float calculate_exposure_normalization() const override; + + CameraAttributesPhysical(); + ~CameraAttributesPhysical(); +}; + +#endif // CAMERA_ATTRIBUTES_H diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp deleted file mode 100644 index 0b11366591..0000000000 --- a/scene/resources/camera_effects.cpp +++ /dev/null @@ -1,206 +0,0 @@ -/*************************************************************************/ -/* camera_effects.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "camera_effects.h" - -#include "servers/rendering_server.h" - -RID CameraEffects::get_rid() const { - return camera_effects; -} - -// DOF blur - -void CameraEffects::set_dof_blur_far_enabled(bool p_enabled) { - dof_blur_far_enabled = p_enabled; - _update_dof_blur(); - notify_property_list_changed(); -} - -bool CameraEffects::is_dof_blur_far_enabled() const { - return dof_blur_far_enabled; -} - -void CameraEffects::set_dof_blur_far_distance(float p_distance) { - dof_blur_far_distance = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_far_distance() const { - return dof_blur_far_distance; -} - -void CameraEffects::set_dof_blur_far_transition(float p_distance) { - dof_blur_far_transition = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_far_transition() const { - return dof_blur_far_transition; -} - -void CameraEffects::set_dof_blur_near_enabled(bool p_enabled) { - dof_blur_near_enabled = p_enabled; - _update_dof_blur(); - notify_property_list_changed(); -} - -bool CameraEffects::is_dof_blur_near_enabled() const { - return dof_blur_near_enabled; -} - -void CameraEffects::set_dof_blur_near_distance(float p_distance) { - dof_blur_near_distance = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_near_distance() const { - return dof_blur_near_distance; -} - -void CameraEffects::set_dof_blur_near_transition(float p_distance) { - dof_blur_near_transition = p_distance; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_near_transition() const { - return dof_blur_near_transition; -} - -void CameraEffects::set_dof_blur_amount(float p_amount) { - dof_blur_amount = p_amount; - _update_dof_blur(); -} - -float CameraEffects::get_dof_blur_amount() const { - return dof_blur_amount; -} - -void CameraEffects::_update_dof_blur() { - RS::get_singleton()->camera_effects_set_dof_blur( - camera_effects, - dof_blur_far_enabled, - dof_blur_far_distance, - dof_blur_far_transition, - dof_blur_near_enabled, - dof_blur_near_distance, - dof_blur_near_transition, - dof_blur_amount); -} - -// Custom exposure - -void CameraEffects::set_override_exposure_enabled(bool p_enabled) { - override_exposure_enabled = p_enabled; - _update_override_exposure(); - notify_property_list_changed(); -} - -bool CameraEffects::is_override_exposure_enabled() const { - return override_exposure_enabled; -} - -void CameraEffects::set_override_exposure(float p_exposure) { - override_exposure = p_exposure; - _update_override_exposure(); -} - -float CameraEffects::get_override_exposure() const { - return override_exposure; -} - -void CameraEffects::_update_override_exposure() { - RS::get_singleton()->camera_effects_set_custom_exposure( - camera_effects, - override_exposure_enabled, - override_exposure); -} - -// Private methods, constructor and destructor - -void CameraEffects::_validate_property(PropertyInfo &p_property) const { - if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) || - (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition")) || - (!override_exposure_enabled && p_property.name == "override_exposure")) { - p_property.usage = PROPERTY_USAGE_NO_EDITOR; - } -} - -void CameraEffects::_bind_methods() { - // DOF blur - - ClassDB::bind_method(D_METHOD("set_dof_blur_far_enabled", "enabled"), &CameraEffects::set_dof_blur_far_enabled); - ClassDB::bind_method(D_METHOD("is_dof_blur_far_enabled"), &CameraEffects::is_dof_blur_far_enabled); - ClassDB::bind_method(D_METHOD("set_dof_blur_far_distance", "distance"), &CameraEffects::set_dof_blur_far_distance); - ClassDB::bind_method(D_METHOD("get_dof_blur_far_distance"), &CameraEffects::get_dof_blur_far_distance); - ClassDB::bind_method(D_METHOD("set_dof_blur_far_transition", "distance"), &CameraEffects::set_dof_blur_far_transition); - ClassDB::bind_method(D_METHOD("get_dof_blur_far_transition"), &CameraEffects::get_dof_blur_far_transition); - - ClassDB::bind_method(D_METHOD("set_dof_blur_near_enabled", "enabled"), &CameraEffects::set_dof_blur_near_enabled); - ClassDB::bind_method(D_METHOD("is_dof_blur_near_enabled"), &CameraEffects::is_dof_blur_near_enabled); - ClassDB::bind_method(D_METHOD("set_dof_blur_near_distance", "distance"), &CameraEffects::set_dof_blur_near_distance); - ClassDB::bind_method(D_METHOD("get_dof_blur_near_distance"), &CameraEffects::get_dof_blur_near_distance); - ClassDB::bind_method(D_METHOD("set_dof_blur_near_transition", "distance"), &CameraEffects::set_dof_blur_near_transition); - ClassDB::bind_method(D_METHOD("get_dof_blur_near_transition"), &CameraEffects::get_dof_blur_near_transition); - - ClassDB::bind_method(D_METHOD("set_dof_blur_amount", "amount"), &CameraEffects::set_dof_blur_amount); - ClassDB::bind_method(D_METHOD("get_dof_blur_amount"), &CameraEffects::get_dof_blur_amount); - - ADD_GROUP("DOF Blur", "dof_blur_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp,suffix:m"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); - - // Override exposure - - ClassDB::bind_method(D_METHOD("set_override_exposure_enabled", "enabled"), &CameraEffects::set_override_exposure_enabled); - ClassDB::bind_method(D_METHOD("is_override_exposure_enabled"), &CameraEffects::is_override_exposure_enabled); - ClassDB::bind_method(D_METHOD("set_override_exposure", "exposure"), &CameraEffects::set_override_exposure); - ClassDB::bind_method(D_METHOD("get_override_exposure"), &CameraEffects::get_override_exposure); - - ADD_GROUP("Override Exposure", "override_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_exposure_enabled"), "set_override_exposure_enabled", "is_override_exposure_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "override_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_override_exposure", "get_override_exposure"); -} - -CameraEffects::CameraEffects() { - camera_effects = RS::get_singleton()->camera_effects_create(); - - _update_dof_blur(); - _update_override_exposure(); -} - -CameraEffects::~CameraEffects() { - RS::get_singleton()->free(camera_effects); -} diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index ee53578517..0ea5264935 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -313,7 +313,7 @@ void Curve::set_max_value(real_t p_max) { emit_signal(SNAME(SIGNAL_RANGE_CHANGED)); } -real_t Curve::interpolate(real_t p_offset) const { +real_t Curve::sample(real_t p_offset) const { if (_points.size() == 0) { return 0; } @@ -333,10 +333,10 @@ real_t Curve::interpolate(real_t p_offset) const { return _points[0].position.y; } - return interpolate_local_nocheck(i, local); + return sample_local_nocheck(i, local); } -real_t Curve::interpolate_local_nocheck(int p_index, real_t p_local_offset) const { +real_t Curve::sample_local_nocheck(int p_index, real_t p_local_offset) const { const Point a = _points[p_index]; const Point b = _points[p_index + 1]; @@ -440,7 +440,7 @@ void Curve::bake() { for (int i = 1; i < _bake_resolution - 1; ++i) { real_t x = i / static_cast<real_t>(_bake_resolution); - real_t y = interpolate(x); + real_t y = sample(x); _baked_cache.write[i] = y; } @@ -459,7 +459,7 @@ void Curve::set_bake_resolution(int p_resolution) { _baked_cache_dirty = true; } -real_t Curve::interpolate_baked(real_t p_offset) const { +real_t Curve::sample_baked(real_t p_offset) const { if (_baked_cache_dirty) { // Last-second bake if not done already const_cast<Curve *>(this)->bake(); @@ -486,7 +486,7 @@ real_t Curve::interpolate_baked(real_t p_offset) const { fi = 0; } - // Interpolate + // Sample if (i + 1 < _baked_cache.size()) { real_t t = fi - i; return Math::lerp(_baked_cache[i], _baked_cache[i + 1], t); @@ -595,8 +595,8 @@ void Curve::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Curve::get_point_position); ClassDB::bind_method(D_METHOD("set_point_value", "index", "y"), &Curve::set_point_value); ClassDB::bind_method(D_METHOD("set_point_offset", "index", "offset"), &Curve::set_point_offset); - ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate); - ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked); + ClassDB::bind_method(D_METHOD("sample", "offset"), &Curve::sample); + ClassDB::bind_method(D_METHOD("sample_baked", "offset"), &Curve::sample_baked); ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent); ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_right_tangent); ClassDB::bind_method(D_METHOD("get_point_left_mode", "index"), &Curve::get_point_left_mode); @@ -720,7 +720,7 @@ void Curve2D::clear_points() { } } -Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const { +Vector2 Curve2D::sample(int p_index, const real_t p_offset) const { int pc = points.size(); ERR_FAIL_COND_V(pc == 0, Vector2()); @@ -738,14 +738,14 @@ Vector2 Curve2D::interpolate(int p_index, const real_t p_offset) const { return p0.bezier_interpolate(p1, p2, p3, p_offset); } -Vector2 Curve2D::interpolatef(real_t p_findex) const { +Vector2 Curve2D::samplef(real_t p_findex) const { if (p_findex < 0) { p_findex = 0; } else if (p_findex >= points.size()) { p_findex = points.size(); } - return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0)); + return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0)); } void Curve2D::mark_dirty() { @@ -883,7 +883,7 @@ real_t Curve2D::get_baked_length() const { return baked_max_ofs; } -Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const { +Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const { if (baked_cache_dirty) { _bake(); } @@ -923,7 +923,7 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const { real_t offset_end = baked_dist_cache[idx + 1]; real_t idx_interval = offset_end - offset_begin; - ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector2(), "failed to find baked segment"); + ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector2(), "Couldn't find baked segment."); real_t frac = (p_offset - offset_begin) / idx_interval; @@ -1176,14 +1176,14 @@ void Curve2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve2D::get_point_out); ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve2D::remove_point); ClassDB::bind_method(D_METHOD("clear_points"), &Curve2D::clear_points); - ClassDB::bind_method(D_METHOD("interpolate", "idx", "t"), &Curve2D::interpolate); - ClassDB::bind_method(D_METHOD("interpolatef", "fofs"), &Curve2D::interpolatef); + ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve2D::sample); + ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve2D::samplef); //ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve2D::bake,DEFVAL(10)); ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve2D::set_bake_interval); ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve2D::get_bake_interval); ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length); - ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve2D::interpolate_baked, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve2D::sample_baked, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points); ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve2D::get_closest_point); ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve2D::get_closest_offset); @@ -1309,7 +1309,7 @@ void Curve3D::clear_points() { } } -Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const { +Vector3 Curve3D::sample(int p_index, real_t p_offset) const { int pc = points.size(); ERR_FAIL_COND_V(pc == 0, Vector3()); @@ -1327,14 +1327,14 @@ Vector3 Curve3D::interpolate(int p_index, real_t p_offset) const { return p0.bezier_interpolate(p1, p2, p3, p_offset); } -Vector3 Curve3D::interpolatef(real_t p_findex) const { +Vector3 Curve3D::samplef(real_t p_findex) const { if (p_findex < 0) { p_findex = 0; } else if (p_findex >= points.size()) { p_findex = points.size(); } - return interpolate((int)p_findex, Math::fmod(p_findex, (real_t)1.0)); + return sample((int)p_findex, Math::fmod(p_findex, (real_t)1.0)); } void Curve3D::mark_dirty() { @@ -1536,7 +1536,7 @@ real_t Curve3D::get_baked_length() const { return baked_max_ofs; } -Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const { +Vector3 Curve3D::sample_baked(real_t p_offset, bool p_cubic) const { if (baked_cache_dirty) { _bake(); } @@ -1576,7 +1576,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const { real_t offset_end = baked_dist_cache[idx + 1]; real_t idx_interval = offset_end - offset_begin; - ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "failed to find baked segment"); + ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "Couldn't find baked segment."); real_t frac = (p_offset - offset_begin) / idx_interval; @@ -1589,7 +1589,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const { } } -real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const { +real_t Curve3D::sample_baked_tilt(real_t p_offset) const { if (baked_cache_dirty) { _bake(); } @@ -1629,14 +1629,14 @@ real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const { real_t offset_end = baked_dist_cache[idx + 1]; real_t idx_interval = offset_end - offset_begin; - ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "failed to find baked segment"); + ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "Couldn't find baked segment."); real_t frac = (p_offset - offset_begin) / idx_interval; return Math::lerp(r[idx], r[idx + 1], (real_t)frac); } -Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt) const { +Vector3 Curve3D::sample_baked_up_vector(real_t p_offset, bool p_apply_tilt) const { if (baked_cache_dirty) { _bake(); } @@ -1671,7 +1671,7 @@ Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt) real_t offset_end = baked_dist_cache[idx + 1]; real_t idx_interval = offset_end - offset_begin; - ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "failed to find baked segment"); + ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "Couldn't find baked segment."); real_t frac = (p_offset - offset_begin) / idx_interval; @@ -1983,8 +1983,8 @@ void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_out", "idx"), &Curve3D::get_point_out); ClassDB::bind_method(D_METHOD("remove_point", "idx"), &Curve3D::remove_point); ClassDB::bind_method(D_METHOD("clear_points"), &Curve3D::clear_points); - ClassDB::bind_method(D_METHOD("interpolate", "idx", "t"), &Curve3D::interpolate); - ClassDB::bind_method(D_METHOD("interpolatef", "fofs"), &Curve3D::interpolatef); + ClassDB::bind_method(D_METHOD("sample", "idx", "t"), &Curve3D::sample); + ClassDB::bind_method(D_METHOD("samplef", "fofs"), &Curve3D::samplef); //ClassDB::bind_method(D_METHOD("bake","subdivs"),&Curve3D::bake,DEFVAL(10)); ClassDB::bind_method(D_METHOD("set_bake_interval", "distance"), &Curve3D::set_bake_interval); ClassDB::bind_method(D_METHOD("get_bake_interval"), &Curve3D::get_bake_interval); @@ -1992,8 +1992,8 @@ void Curve3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_up_vector_enabled"), &Curve3D::is_up_vector_enabled); ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve3D::get_baked_length); - ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("interpolate_baked_up_vector", "offset", "apply_tilt"), &Curve3D::interpolate_baked_up_vector, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("sample_baked", "offset", "cubic"), &Curve3D::sample_baked, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("sample_baked_up_vector", "offset", "apply_tilt"), &Curve3D::sample_baked_up_vector, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points); ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts); ClassDB::bind_method(D_METHOD("get_baked_up_vectors"), &Curve3D::get_baked_up_vectors); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 08807b1b6e..88b6dda096 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -100,8 +100,8 @@ public: real_t get_max_value() const { return _max_value; } void set_max_value(real_t p_max); - real_t interpolate(real_t p_offset) const; - real_t interpolate_local_nocheck(int p_index, real_t p_local_offset) const; + real_t sample(real_t p_offset) const; + real_t sample_local_nocheck(int p_index, real_t p_local_offset) const; void clean_dupes(); @@ -123,7 +123,7 @@ public: void bake(); int get_bake_resolution() const { return _bake_resolution; } void set_bake_resolution(int p_resolution); - real_t interpolate_baked(real_t p_offset) const; + real_t sample_baked(real_t p_offset) const; void ensure_default_setup(real_t p_min, real_t p_max); @@ -208,14 +208,14 @@ public: void remove_point(int p_index); void clear_points(); - Vector2 interpolate(int p_index, real_t p_offset) const; - Vector2 interpolatef(real_t p_findex) const; + Vector2 sample(int p_index, real_t p_offset) const; + Vector2 samplef(real_t p_findex) const; void set_bake_interval(real_t p_tolerance); real_t get_bake_interval() const; real_t get_baked_length() const; - Vector2 interpolate_baked(real_t p_offset, bool p_cubic = false) const; + Vector2 sample_baked(real_t p_offset, bool p_cubic = false) const; PackedVector2Array get_baked_points() const; //useful for going through Vector2 get_closest_point(const Vector2 &p_to_point) const; real_t get_closest_offset(const Vector2 &p_to_point) const; @@ -285,8 +285,8 @@ public: void remove_point(int p_index); void clear_points(); - Vector3 interpolate(int p_index, real_t p_offset) const; - Vector3 interpolatef(real_t p_findex) const; + Vector3 sample(int p_index, real_t p_offset) const; + Vector3 samplef(real_t p_findex) const; void set_bake_interval(real_t p_tolerance); real_t get_bake_interval() const; @@ -294,9 +294,9 @@ public: bool is_up_vector_enabled() const; real_t get_baked_length() const; - Vector3 interpolate_baked(real_t p_offset, bool p_cubic = false) const; - real_t interpolate_baked_tilt(real_t p_offset) const; - Vector3 interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const; + Vector3 sample_baked(real_t p_offset, bool p_cubic = false) const; + real_t sample_baked_tilt(real_t p_offset) const; + Vector3 sample_baked_up_vector(real_t p_offset, bool p_apply_tilt = false) const; PackedVector3Array get_baked_points() const; //useful for going through Vector<real_t> get_baked_tilts() const; //useful for going through PackedVector3Array get_baked_up_vectors() const; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 410f35e597..869d582935 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -51,10 +51,7 @@ static const int default_corner_radius = 3; static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = default_margin, float p_margin_top = default_margin, float p_margin_right = default_margin, float p_margin_bottom = default_margin, int p_corner_radius = default_corner_radius, bool p_draw_center = true, int p_border_width = 0) { Ref<StyleBoxFlat> style(memnew(StyleBoxFlat)); style->set_bg_color(p_color); - style->set_default_margin(SIDE_LEFT, p_margin_left * scale); - style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); - style->set_default_margin(SIDE_TOP, p_margin_top * scale); + style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); style->set_corner_radius_all(p_corner_radius); style->set_anti_aliased(true); @@ -93,12 +90,7 @@ static Ref<ImageTexture> generate_icon(int p_index) { static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBox> style(memnew(StyleBoxEmpty)); - - style->set_default_margin(SIDE_LEFT, p_margin_left * scale); - style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); - style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); - style->set_default_margin(SIDE_TOP, p_margin_top * scale); - + style->set_default_margin_individual(p_margin_left * scale, p_margin_top * scale, p_margin_right * scale, p_margin_bottom * scale); return style; } @@ -139,7 +131,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Panel theme->set_stylebox("panel", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); - theme->set_stylebox("panel_fg", "Panel", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); // Button @@ -280,15 +271,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // CheckBox Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty); - cbx_empty->set_default_margin(SIDE_LEFT, 4 * scale); - cbx_empty->set_default_margin(SIDE_RIGHT, 4 * scale); - cbx_empty->set_default_margin(SIDE_TOP, 4 * scale); - cbx_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); + cbx_empty->set_default_margin_all(4 * scale); Ref<StyleBox> cbx_focus = focus; - cbx_focus->set_default_margin(SIDE_LEFT, 4 * scale); - cbx_focus->set_default_margin(SIDE_RIGHT, 4 * scale); - cbx_focus->set_default_margin(SIDE_TOP, 4 * scale); - cbx_focus->set_default_margin(SIDE_BOTTOM, 4 * scale); + cbx_focus->set_default_margin_all(4 * scale); theme->set_stylebox("normal", "CheckBox", cbx_empty); theme->set_stylebox("pressed", "CheckBox", cbx_empty); @@ -318,16 +303,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1)); theme->set_constant("h_separation", "CheckBox", 4 * scale); - theme->set_constant("check_v_adjust", "CheckBox", 0 * scale); + theme->set_constant("check_v_offset", "CheckBox", 0 * scale); theme->set_constant("outline_size", "CheckBox", 0); // CheckButton Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty); - cb_empty->set_default_margin(SIDE_LEFT, 6 * scale); - cb_empty->set_default_margin(SIDE_RIGHT, 6 * scale); - cb_empty->set_default_margin(SIDE_TOP, 4 * scale); - cb_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); + cb_empty->set_default_margin_individual(6 * scale, 4 * scale, 6 * scale, 4 * scale); theme->set_stylebox("normal", "CheckButton", cb_empty); theme->set_stylebox("pressed", "CheckButton", cb_empty); @@ -336,15 +318,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("hover_pressed", "CheckButton", cb_empty); theme->set_stylebox("focus", "CheckButton", focus); - theme->set_icon("on", "CheckButton", icons["toggle_on"]); - theme->set_icon("on_disabled", "CheckButton", icons["toggle_on_disabled"]); - theme->set_icon("off", "CheckButton", icons["toggle_off"]); - theme->set_icon("off_disabled", "CheckButton", icons["toggle_off_disabled"]); + theme->set_icon("checked", "CheckButton", icons["toggle_on"]); + theme->set_icon("checked_disabled", "CheckButton", icons["toggle_on_disabled"]); + theme->set_icon("unchecked", "CheckButton", icons["toggle_off"]); + theme->set_icon("unchecked_disabled", "CheckButton", icons["toggle_off_disabled"]); - theme->set_icon("on_mirrored", "CheckButton", icons["toggle_on_mirrored"]); - theme->set_icon("on_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]); - theme->set_icon("off_mirrored", "CheckButton", icons["toggle_off_mirrored"]); - theme->set_icon("off_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]); + theme->set_icon("checked_mirrored", "CheckButton", icons["toggle_on_mirrored"]); + theme->set_icon("checked_disabled_mirrored", "CheckButton", icons["toggle_on_disabled_mirrored"]); + theme->set_icon("unchecked_mirrored", "CheckButton", icons["toggle_off_mirrored"]); + theme->set_icon("unchecked_disabled_mirrored", "CheckButton", icons["toggle_off_disabled_mirrored"]); theme->set_font("font", "CheckButton", Ref<Font>()); theme->set_font_size("font_size", "CheckButton", -1); @@ -358,7 +340,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1)); theme->set_constant("h_separation", "CheckButton", 4 * scale); - theme->set_constant("check_v_adjust", "CheckButton", 0 * scale); + theme->set_constant("check_v_offset", "CheckButton", 0 * scale); theme->set_constant("outline_size", "CheckButton", 0); // Label @@ -423,8 +405,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // ProgressBar - theme->set_stylebox("bg", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6)); - theme->set_stylebox("fg", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6)); + theme->set_stylebox("background", "ProgressBar", make_flat_stylebox(style_disabled_color, 2, 2, 2, 2, 6)); + theme->set_stylebox("fill", "ProgressBar", make_flat_stylebox(style_progress_color, 2, 2, 2, 2, 6)); theme->set_font("font", "ProgressBar", Ref<Font>()); theme->set_font_size("font_size", "ProgressBar", -1); @@ -588,7 +570,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxEmpty> empty; empty.instantiate(); - theme->set_stylebox("bg", "ScrollContainer", empty); + theme->set_stylebox("panel", "ScrollContainer", empty); // Window @@ -609,12 +591,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Dialogs - theme->set_constant("margin", "Dialogs", 8 * scale); - theme->set_constant("button_margin", "Dialogs", 32 * scale); - - // AcceptDialog - - theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 0, 0, 0, 0)); + // AcceptDialog is currently the base dialog, so this defines styles for all extending nodes. + theme->set_stylebox("panel", "AcceptDialog", make_flat_stylebox(style_popup_color, 8 * scale, 8 * scale, 8 * scale, 8 * scale)); + theme->set_constant("buttons_separation", "AcceptDialog", 10 * scale); // File Dialog @@ -625,9 +604,9 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("toggle_hidden", "FileDialog", icons["visibility_visible"]); theme->set_icon("folder", "FileDialog", icons["folder"]); theme->set_icon("file", "FileDialog", icons["file"]); - theme->set_color("folder_icon_modulate", "FileDialog", Color(1, 1, 1)); - theme->set_color("file_icon_modulate", "FileDialog", Color(1, 1, 1)); - theme->set_color("files_disabled", "FileDialog", Color(1, 1, 1, 0.25)); + theme->set_color("folder_icon_color", "FileDialog", Color(1, 1, 1)); + theme->set_color("file_icon_color", "FileDialog", Color(1, 1, 1)); + theme->set_color("file_disabled_color", "FileDialog", Color(1, 1, 1, 0.25)); // Popup @@ -642,16 +621,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxLine> separator_horizontal = memnew(StyleBoxLine); separator_horizontal->set_thickness(Math::round(scale)); separator_horizontal->set_color(style_separator_color); - separator_horizontal->set_default_margin(SIDE_LEFT, default_margin); - separator_horizontal->set_default_margin(SIDE_TOP, 0); - separator_horizontal->set_default_margin(SIDE_RIGHT, default_margin); - separator_horizontal->set_default_margin(SIDE_BOTTOM, 0); + separator_horizontal->set_default_margin_individual(default_margin, 0, default_margin, 0); Ref<StyleBoxLine> separator_vertical = separator_horizontal->duplicate(); separator_vertical->set_vertical(true); - separator_vertical->set_default_margin(SIDE_LEFT, 0); - separator_vertical->set_default_margin(SIDE_TOP, default_margin); - separator_vertical->set_default_margin(SIDE_RIGHT, 0); - separator_vertical->set_default_margin(SIDE_BOTTOM, default_margin); + separator_vertical->set_default_margin_individual(0, default_margin, 0, default_margin); // Always display a border for PopupMenus so they can be distinguished from their background. Ref<StyleBoxFlat> style_popup_panel = make_flat_stylebox(style_popup_color); @@ -739,8 +712,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Tree - theme->set_stylebox("bg", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); - theme->set_stylebox("bg_focus", "Tree", focus); + theme->set_stylebox("panel", "Tree", make_flat_stylebox(style_normal_color, 4, 4, 4, 5)); + theme->set_stylebox("focus", "Tree", focus); theme->set_stylebox("selected", "Tree", make_flat_stylebox(style_selected_color)); theme->set_stylebox("selected_focus", "Tree", make_flat_stylebox(style_selected_color)); theme->set_stylebox("cursor", "Tree", focus); @@ -793,8 +766,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // ItemList - theme->set_stylebox("bg", "ItemList", make_flat_stylebox(style_normal_color)); - theme->set_stylebox("bg_focus", "ItemList", focus); + theme->set_stylebox("panel", "ItemList", make_flat_stylebox(style_normal_color)); + theme->set_stylebox("focus", "ItemList", focus); theme->set_constant("h_separation", "ItemList", 4); theme->set_constant("v_separation", "ItemList", 2); theme->set_constant("icon_margin", "ItemList", 4); @@ -831,6 +804,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("tab_unselected", "TabContainer", style_tab_unselected); theme->set_stylebox("tab_disabled", "TabContainer", style_tab_disabled); theme->set_stylebox("panel", "TabContainer", make_flat_stylebox(style_normal_color, 0, 0, 0, 0)); + theme->set_stylebox("tabbar_background", "TabContainer", make_empty_stylebox(0, 0, 0, 0)); theme->set_icon("increment", "TabContainer", icons["scroll_button_right"]); theme->set_icon("increment_highlight", "TabContainer", icons["scroll_button_right_hl"]); @@ -997,9 +971,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Containers + theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]); + theme->set_icon("v_grabber", "SplitContainer", icons["vsplitter"]); theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]); theme->set_icon("grabber", "HSplitContainer", icons["hsplitter"]); + theme->set_constant("separation", "BoxContainer", 4 * scale); theme->set_constant("separation", "HBoxContainer", 4 * scale); theme->set_constant("separation", "VBoxContainer", 4 * scale); theme->set_constant("margin_left", "MarginContainer", 0 * scale); @@ -1008,10 +985,17 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("margin_bottom", "MarginContainer", 0 * scale); theme->set_constant("h_separation", "GridContainer", 4 * scale); theme->set_constant("v_separation", "GridContainer", 4 * scale); + theme->set_constant("separation", "SplitContainer", 12 * scale); theme->set_constant("separation", "HSplitContainer", 12 * scale); theme->set_constant("separation", "VSplitContainer", 12 * scale); + theme->set_constant("minimum_grab_thickness", "SplitContainer", 6 * scale); + theme->set_constant("minimum_grab_thickness", "HSplitContainer", 6 * scale); + theme->set_constant("minimum_grab_thickness", "VSplitContainer", 6 * scale); + theme->set_constant("autohide", "SplitContainer", 1 * scale); theme->set_constant("autohide", "HSplitContainer", 1 * scale); theme->set_constant("autohide", "VSplitContainer", 1 * scale); + theme->set_constant("h_separation", "FlowContainer", 4 * scale); + theme->set_constant("v_separation", "FlowContainer", 4 * scale); theme->set_constant("h_separation", "HFlowContainer", 4 * scale); theme->set_constant("v_separation", "HFlowContainer", 4 * scale); theme->set_constant("h_separation", "VFlowContainer", 4 * scale); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index f7a7818b3b..ebdaaaa95f 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -94,13 +94,30 @@ Color Environment::get_bg_color() const { return bg_color; } -void Environment::set_bg_energy(float p_energy) { - bg_energy = p_energy; - RS::get_singleton()->environment_set_bg_energy(environment, p_energy); +void Environment::set_bg_energy_multiplier(float p_multiplier) { + bg_energy_multiplier = p_multiplier; + _update_bg_energy(); } -float Environment::get_bg_energy() const { - return bg_energy; +float Environment::get_bg_energy_multiplier() const { + return bg_energy_multiplier; +} + +void Environment::set_bg_intensity(float p_exposure_value) { + bg_intensity = p_exposure_value; + _update_bg_energy(); +} + +float Environment::get_bg_intensity() const { + return bg_intensity; +} + +void Environment::_update_bg_energy() { + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, bg_intensity); + } else { + RS::get_singleton()->environment_set_bg_energy(environment, bg_energy_multiplier, 1.0); + } } void Environment::set_canvas_max_layer(int p_max_layer) { @@ -214,63 +231,12 @@ float Environment::get_tonemap_white() const { return tonemap_white; } -void Environment::set_tonemap_auto_exposure_enabled(bool p_enabled) { - tonemap_auto_exposure_enabled = p_enabled; - _update_tonemap(); - notify_property_list_changed(); -} - -bool Environment::is_tonemap_auto_exposure_enabled() const { - return tonemap_auto_exposure_enabled; -} - -void Environment::set_tonemap_auto_exposure_min(float p_auto_exposure_min) { - tonemap_auto_exposure_min = p_auto_exposure_min; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_min() const { - return tonemap_auto_exposure_min; -} - -void Environment::set_tonemap_auto_exposure_max(float p_auto_exposure_max) { - tonemap_auto_exposure_max = p_auto_exposure_max; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_max() const { - return tonemap_auto_exposure_max; -} - -void Environment::set_tonemap_auto_exposure_speed(float p_auto_exposure_speed) { - tonemap_auto_exposure_speed = p_auto_exposure_speed; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_speed() const { - return tonemap_auto_exposure_speed; -} - -void Environment::set_tonemap_auto_exposure_grey(float p_auto_exposure_grey) { - tonemap_auto_exposure_grey = p_auto_exposure_grey; - _update_tonemap(); -} - -float Environment::get_tonemap_auto_exposure_grey() const { - return tonemap_auto_exposure_grey; -} - void Environment::_update_tonemap() { RS::get_singleton()->environment_set_tonemap( environment, RS::EnvironmentToneMapper(tone_mapper), tonemap_exposure, - tonemap_white, - tonemap_auto_exposure_enabled, - tonemap_auto_exposure_min, - tonemap_auto_exposure_max, - tonemap_auto_exposure_speed, - tonemap_auto_exposure_grey); + tonemap_white); } // SSR @@ -852,6 +818,15 @@ float Environment::get_fog_aerial_perspective() const { return fog_aerial_perspective; } +void Environment::set_fog_sky_affect(float p_sky_affect) { + fog_sky_affect = p_sky_affect; + _update_fog(); +} + +float Environment::get_fog_sky_affect() const { + return fog_sky_affect; +} + void Environment::_update_fog() { RS::get_singleton()->environment_set_fog( environment, @@ -862,13 +837,28 @@ void Environment::_update_fog() { fog_density, fog_height, fog_height_density, - fog_aerial_perspective); + fog_aerial_perspective, + fog_sky_affect); } // Volumetric Fog void Environment::_update_volumetric_fog() { - RS::get_singleton()->environment_set_volumetric_fog(environment, volumetric_fog_enabled, volumetric_fog_density, volumetric_fog_albedo, volumetric_fog_emission, volumetric_fog_emission_energy, volumetric_fog_anisotropy, volumetric_fog_length, volumetric_fog_detail_spread, volumetric_fog_gi_inject, volumetric_fog_temporal_reproject, volumetric_fog_temporal_reproject_amount, volumetric_fog_ambient_inject); + RS::get_singleton()->environment_set_volumetric_fog( + environment, + volumetric_fog_enabled, + volumetric_fog_density, + volumetric_fog_albedo, + volumetric_fog_emission, + volumetric_fog_emission_energy, + volumetric_fog_anisotropy, + volumetric_fog_length, + volumetric_fog_detail_spread, + volumetric_fog_gi_inject, + volumetric_fog_temporal_reproject, + volumetric_fog_temporal_reproject_amount, + volumetric_fog_ambient_inject, + volumetric_fog_sky_affect); } void Environment::set_volumetric_fog_enabled(bool p_enable) { @@ -946,6 +936,15 @@ float Environment::get_volumetric_fog_ambient_inject() const { return volumetric_fog_ambient_inject; } +void Environment::set_volumetric_fog_sky_affect(float p_sky_affect) { + volumetric_fog_sky_affect = p_sky_affect; + _update_volumetric_fog(); +} + +float Environment::get_volumetric_fog_sky_affect() const { + return volumetric_fog_sky_affect; +} + void Environment::set_volumetric_fog_temporal_reprojection_enabled(bool p_enable) { volumetric_fog_temporal_reproject = p_enable; _update_volumetric_fog(); @@ -1080,10 +1079,13 @@ void Environment::_validate_property(PropertyInfo &p_property) const { } } + if (p_property.name == "background_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } + static const char *hide_prefixes[] = { "fog_", "volumetric_fog_", - "auto_exposure_", "ssr_", "ssao_", "ssil_", @@ -1095,7 +1097,6 @@ void Environment::_validate_property(PropertyInfo &p_property) const { }; static const char *high_end_prefixes[] = { - "auto_exposure_", "ssr_", "ssao_", nullptr @@ -1162,8 +1163,10 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_sky_rotation"), &Environment::get_sky_rotation); ClassDB::bind_method(D_METHOD("set_bg_color", "color"), &Environment::set_bg_color); ClassDB::bind_method(D_METHOD("get_bg_color"), &Environment::get_bg_color); - ClassDB::bind_method(D_METHOD("set_bg_energy", "energy"), &Environment::set_bg_energy); - ClassDB::bind_method(D_METHOD("get_bg_energy"), &Environment::get_bg_energy); + ClassDB::bind_method(D_METHOD("set_bg_energy_multiplier", "energy"), &Environment::set_bg_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_bg_energy_multiplier"), &Environment::get_bg_energy_multiplier); + ClassDB::bind_method(D_METHOD("set_bg_intensity", "energy"), &Environment::set_bg_intensity); + ClassDB::bind_method(D_METHOD("get_bg_intensity"), &Environment::get_bg_intensity); ClassDB::bind_method(D_METHOD("set_canvas_max_layer", "layer"), &Environment::set_canvas_max_layer); ClassDB::bind_method(D_METHOD("get_canvas_max_layer"), &Environment::get_canvas_max_layer); ClassDB::bind_method(D_METHOD("set_camera_feed_id", "id"), &Environment::set_camera_feed_id); @@ -1172,14 +1175,16 @@ void Environment::_bind_methods() { ADD_GROUP("Background", "background_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "background_mode", PROPERTY_HINT_ENUM, "Clear Color,Custom Color,Sky,Canvas,Keep,Camera Feed"), "set_background", "get_background"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_bg_color", "get_bg_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy", "get_bg_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_bg_energy_multiplier", "get_bg_energy_multiplier"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "background_intensity", PROPERTY_HINT_RANGE, "0,100000,0.01,suffix:nt"), "set_bg_intensity", "get_bg_intensity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "background_canvas_max_layer", PROPERTY_HINT_RANGE, "-1000,1000,1"), "set_canvas_max_layer", "get_canvas_max_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "background_camera_feed_id", PROPERTY_HINT_RANGE, "1,10,1"), "set_camera_feed_id", "get_camera_feed_id"); ADD_GROUP("Sky", "sky_"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_sky", "get_sky"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_custom_fov", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_sky_custom_fov", "get_sky_custom_fov"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_sky_rotation", "get_sky_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "sky_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians"), "set_sky_rotation", "get_sky_rotation"); // Ambient light @@ -1211,27 +1216,11 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tonemap_exposure"), &Environment::get_tonemap_exposure); ClassDB::bind_method(D_METHOD("set_tonemap_white", "white"), &Environment::set_tonemap_white); ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_enabled", "enabled"), &Environment::set_tonemap_auto_exposure_enabled); - ClassDB::bind_method(D_METHOD("is_tonemap_auto_exposure_enabled"), &Environment::is_tonemap_auto_exposure_enabled); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_max", "exposure_max"), &Environment::set_tonemap_auto_exposure_max); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_max"), &Environment::get_tonemap_auto_exposure_max); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_min", "exposure_min"), &Environment::set_tonemap_auto_exposure_min); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_min"), &Environment::get_tonemap_auto_exposure_min); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_speed", "exposure_speed"), &Environment::set_tonemap_auto_exposure_speed); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_speed"), &Environment::get_tonemap_auto_exposure_speed); - ClassDB::bind_method(D_METHOD("set_tonemap_auto_exposure_grey", "exposure_grey"), &Environment::set_tonemap_auto_exposure_grey); - ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey); ADD_GROUP("Tonemap", "tonemap_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES"), "set_tonemapper", "get_tonemapper"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white"); - ADD_GROUP("Auto Exposure", "auto_exposure_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_exposure_enabled"), "set_tonemap_auto_exposure_enabled", "is_tonemap_auto_exposure_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_grey", "get_tonemap_auto_exposure_grey"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_min_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_min", "get_tonemap_auto_exposure_min"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_max_luma", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_auto_exposure_max", "get_tonemap_auto_exposure_max"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "auto_exposure_speed", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_tonemap_auto_exposure_speed", "get_tonemap_auto_exposure_speed"); // SSR @@ -1419,6 +1408,9 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("set_fog_aerial_perspective", "aerial_perspective"), &Environment::set_fog_aerial_perspective); ClassDB::bind_method(D_METHOD("get_fog_aerial_perspective"), &Environment::get_fog_aerial_perspective); + ClassDB::bind_method(D_METHOD("set_fog_sky_affect", "sky_affect"), &Environment::set_fog_sky_affect); + ClassDB::bind_method(D_METHOD("get_fog_sky_affect"), &Environment::get_fog_sky_affect); + ADD_GROUP("Fog", "fog_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fog_enabled"), "set_fog_enabled", "is_fog_enabled"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "fog_light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_fog_light_color", "get_fog_light_color"); @@ -1427,8 +1419,9 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_fog_density", "get_fog_density"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_aerial_perspective", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_aerial_perspective", "get_fog_aerial_perspective"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_lesser,or_greater,suffix:m"), "set_fog_height", "get_fog_height"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_lesser,or_greater"), "set_fog_height_density", "get_fog_height_density"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_sky_affect", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_fog_sky_affect", "get_fog_sky_affect"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height", PROPERTY_HINT_RANGE, "-1024,1024,0.01,or_less,or_greater,suffix:m"), "set_fog_height", "get_fog_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fog_height_density", PROPERTY_HINT_RANGE, "-16,16,0.0001,or_less,or_greater"), "set_fog_height_density", "get_fog_height_density"); ClassDB::bind_method(D_METHOD("set_volumetric_fog_enabled", "enabled"), &Environment::set_volumetric_fog_enabled); ClassDB::bind_method(D_METHOD("is_volumetric_fog_enabled"), &Environment::is_volumetric_fog_enabled); @@ -1450,6 +1443,8 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_volumetric_fog_gi_inject"), &Environment::get_volumetric_fog_gi_inject); ClassDB::bind_method(D_METHOD("set_volumetric_fog_ambient_inject", "enabled"), &Environment::set_volumetric_fog_ambient_inject); ClassDB::bind_method(D_METHOD("get_volumetric_fog_ambient_inject"), &Environment::get_volumetric_fog_ambient_inject); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_sky_affect", "sky_affect"), &Environment::set_volumetric_fog_sky_affect); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_sky_affect"), &Environment::get_volumetric_fog_sky_affect); ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_enabled", "enabled"), &Environment::set_volumetric_fog_temporal_reprojection_enabled); ClassDB::bind_method(D_METHOD("is_volumetric_fog_temporal_reprojection_enabled"), &Environment::is_volumetric_fog_temporal_reprojection_enabled); ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_amount", "temporal_reprojection_amount"), &Environment::set_volumetric_fog_temporal_reprojection_amount); @@ -1466,6 +1461,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_ambient_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_ambient_inject", "get_volumetric_fog_ambient_inject"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_sky_affect", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_volumetric_fog_sky_affect", "get_volumetric_fog_sky_affect"); ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.5,0.99,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount"); @@ -1549,6 +1545,7 @@ Environment::Environment() { _update_fog(); _update_adjustment(); _update_volumetric_fog(); + _update_bg_energy(); notify_property_list_changed(); } diff --git a/scene/resources/environment.h b/scene/resources/environment.h index d39cb1acd8..507a0cee39 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -92,9 +92,11 @@ private: float bg_sky_custom_fov = 0.0; Vector3 bg_sky_rotation; Color bg_color; - float bg_energy = 1.0; int bg_canvas_max_layer = 0; int bg_camera_feed_id = 1; + float bg_energy_multiplier = 1.0; + float bg_intensity = 30000.0; // Measured in nits or candela/m^2 + void _update_bg_energy(); // Ambient light Color ambient_color; @@ -108,11 +110,6 @@ private: ToneMapper tone_mapper = TONE_MAPPER_LINEAR; float tonemap_exposure = 1.0; float tonemap_white = 1.0; - bool tonemap_auto_exposure_enabled = false; - float tonemap_auto_exposure_min = 0.05; - float tonemap_auto_exposure_max = 8.0; - float tonemap_auto_exposure_speed = 0.5; - float tonemap_auto_exposure_grey = 0.4; void _update_tonemap(); // SSR @@ -182,6 +179,7 @@ private: float fog_height = 0.0; float fog_height_density = 0.0; //can be negative to invert effect float fog_aerial_perspective = 0.0; + float fog_sky_affect = 1.0; void _update_fog(); @@ -196,6 +194,7 @@ private: float volumetric_fog_detail_spread = 2.0; float volumetric_fog_gi_inject = 1.0; float volumetric_fog_ambient_inject = 0.0; + float volumetric_fog_sky_affect = 1.0; bool volumetric_fog_temporal_reproject = true; float volumetric_fog_temporal_reproject_amount = 0.9; void _update_volumetric_fog(); @@ -231,8 +230,10 @@ public: Vector3 get_sky_rotation() const; void set_bg_color(const Color &p_color); Color get_bg_color() const; - void set_bg_energy(float p_energy); - float get_bg_energy() const; + void set_bg_energy_multiplier(float p_energy); + float get_bg_energy_multiplier() const; + void set_bg_intensity(float p_energy); + float get_bg_intensity() const; void set_canvas_max_layer(int p_max_layer); int get_canvas_max_layer() const; void set_camera_feed_id(int p_id); @@ -257,16 +258,6 @@ public: float get_tonemap_exposure() const; void set_tonemap_white(float p_white); float get_tonemap_white() const; - void set_tonemap_auto_exposure_enabled(bool p_enabled); - bool is_tonemap_auto_exposure_enabled() const; - void set_tonemap_auto_exposure_min(float p_auto_exposure_min); - float get_tonemap_auto_exposure_min() const; - void set_tonemap_auto_exposure_max(float p_auto_exposure_max); - float get_tonemap_auto_exposure_max() const; - void set_tonemap_auto_exposure_speed(float p_auto_exposure_speed); - float get_tonemap_auto_exposure_speed() const; - void set_tonemap_auto_exposure_grey(float p_auto_exposure_grey); - float get_tonemap_auto_exposure_grey() const; // SSR void set_ssr_enabled(bool p_enabled); @@ -385,6 +376,8 @@ public: float get_fog_height_density() const; void set_fog_aerial_perspective(float p_aerial_perspective); float get_fog_aerial_perspective() const; + void set_fog_sky_affect(float p_sky_affect); + float get_fog_sky_affect() const; // Volumetric Fog void set_volumetric_fog_enabled(bool p_enable); @@ -407,6 +400,8 @@ public: float get_volumetric_fog_gi_inject() const; void set_volumetric_fog_ambient_inject(float p_ambient_inject); float get_volumetric_fog_ambient_inject() const; + void set_volumetric_fog_sky_affect(float p_sky_affect); + float get_volumetric_fog_sky_affect() const; void set_volumetric_fog_temporal_reprojection_enabled(bool p_enable); bool is_volumetric_fog_temporal_reprojection_enabled() const; void set_volumetric_fog_temporal_reprojection_amount(float p_amount); diff --git a/scene/resources/fog_material.cpp b/scene/resources/fog_material.cpp index 39ade85af6..0395ed0346 100644 --- a/scene/resources/fog_material.cpp +++ b/scene/resources/fog_material.cpp @@ -122,7 +122,7 @@ void FogMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_density_texture", "density_texture"), &FogMaterial::set_density_texture); ClassDB::bind_method(D_METHOD("get_density_texture"), &FogMaterial::get_density_texture); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_lesser"), "set_density", "get_density"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "density", PROPERTY_HINT_RANGE, "0.0,16.0,0.0001,or_greater,or_less"), "set_density", "get_density"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "albedo", PROPERTY_HINT_COLOR_NO_ALPHA), "set_albedo", "get_albedo"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height_falloff", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_height_falloff", "get_height_falloff"); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 8ec5678f0a..3d9e4e4a63 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -554,7 +554,6 @@ Font::Font() { } Font::~Font() { - reset_state(); } /*************************************************************************/ @@ -1427,7 +1426,7 @@ Error FontFile::load_bitmap_font(const String &p_path) { while (!f->eof_reached() && f->get_position() <= off + block_size) { if (c == '\0') { String base_dir = p_path.get_base_dir(); - String file = base_dir.plus_file(String::utf8(cs.ptr(), cs.length())); + String file = base_dir.path_join(String::utf8(cs.ptr(), cs.length())); if (RenderingServer::get_singleton() != nullptr) { Ref<Image> img; img.instantiate(); @@ -1660,7 +1659,7 @@ Error FontFile::load_bitmap_font(const String &p_path) { } if (keys.has("file")) { String base_dir = p_path.get_base_dir(); - String file = base_dir.plus_file(keys["file"]); + String file = base_dir.path_join(keys["file"]); if (RenderingServer::get_singleton() != nullptr) { Ref<Image> img; img.instantiate(); @@ -2433,11 +2432,10 @@ int32_t FontFile::get_glyph_index(int p_size, char32_t p_char, char32_t p_variat } FontFile::FontFile() { - /* NOP */ } FontFile::~FontFile() { - reset_state(); + _clear_cache(); } /*************************************************************************/ @@ -2688,7 +2686,6 @@ FontVariation::FontVariation() { } FontVariation::~FontVariation() { - reset_state(); } /*************************************************************************/ @@ -3081,5 +3078,4 @@ SystemFont::SystemFont() { } SystemFont::~SystemFont() { - reset_state(); } diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp index a9c44dc6bf..f04eb75d86 100644 --- a/scene/resources/gradient.cpp +++ b/scene/resources/gradient.cpp @@ -56,7 +56,7 @@ void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &Gradient::set_color); ClassDB::bind_method(D_METHOD("get_color", "point"), &Gradient::get_color); - ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Gradient::get_color_at_offset); + ClassDB::bind_method(D_METHOD("sample", "offset"), &Gradient::get_color_at_offset); ClassDB::bind_method(D_METHOD("get_point_count"), &Gradient::get_points_count); diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h index e4bac15e4b..2b91331ab0 100644 --- a/scene/resources/gradient.h +++ b/scene/resources/gradient.h @@ -122,7 +122,7 @@ public: } } - // Return interpolated value. + // Return sampled value. if (points[middle].offset > p_offset) { middle--; } diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 3638d1862c..de3d502102 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -154,7 +154,7 @@ Mesh::BlendShapeMode ImporterMesh::get_blend_shape_mode() const { return blend_shape_mode; } -void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) { +void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) { ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size()); ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX); Surface s; @@ -254,7 +254,20 @@ void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_ma mesh.unref(); } -void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle) { +#define VERTEX_SKIN_FUNC(bone_count, vert_idx, read_array, write_array, transform_array, bone_array, weight_array) \ + Vector3 transformed_vert = Vector3(); \ + for (unsigned int weight_idx = 0; weight_idx < bone_count; weight_idx++) { \ + int bone_idx = bone_array[vert_idx * bone_count + weight_idx]; \ + float w = weight_array[vert_idx * bone_count + weight_idx]; \ + if (w < FLT_EPSILON) { \ + continue; \ + } \ + ERR_FAIL_INDEX(bone_idx, static_cast<int>(transform_array.size())); \ + transformed_vert += transform_array[bone_idx].xform(read_array[vert_idx]) * w; \ + } \ + write_array[vert_idx] = transformed_vert; + +void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_bone_transform_array) { if (!SurfaceTool::simplify_scale_func) { return; } @@ -265,6 +278,12 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli return; } + LocalVector<Transform3D> bone_transform_vector; + for (int i = 0; i < p_bone_transform_array.size(); i++) { + ERR_FAIL_COND(p_bone_transform_array[i].get_type() != Variant::TRANSFORM3D); + bone_transform_vector.push_back(p_bone_transform_array[i]); + } + for (int i = 0; i < surfaces.size(); i++) { if (surfaces[i].primitive != Mesh::PRIMITIVE_TRIANGLES) { continue; @@ -276,6 +295,8 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli 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]; + Vector<int> bones = surfaces[i].arrays[RS::ARRAY_BONES]; + Vector<float> weights = surfaces[i].arrays[RS::ARRAY_WEIGHTS]; unsigned int index_count = indices.size(); unsigned int vertex_count = vertices.size(); @@ -301,6 +322,22 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli } } + if (bones.size() > 0 && weights.size() && bone_transform_vector.size() > 0) { + Vector3 *vertices_ptrw = vertices.ptrw(); + + // Apply bone transforms to regular surface. + unsigned int bone_weight_length = surfaces[i].flags & Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS ? 8 : 4; + + const int *bo = bones.ptr(); + const float *we = weights.ptr(); + + for (unsigned int j = 0; j < vertex_count; j++) { + VERTEX_SKIN_FUNC(bone_weight_length, j, vertices_ptr, vertices_ptrw, bone_transform_vector, bo, we) + } + + vertices_ptr = vertices.ptr(); + } + float normal_merge_threshold = Math::cos(Math::deg_to_rad(p_normal_merge_angle)); float normal_pre_split_threshold = Math::cos(Math::deg_to_rad(MIN(180.0f, p_normal_split_angle * 2.0f))); float normal_split_threshold = Math::cos(Math::deg_to_rad(p_normal_split_angle)); @@ -1230,7 +1267,7 @@ void ImporterMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ImporterMesh::set_blend_shape_mode); ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ImporterMesh::get_blend_shape_mode); - ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(TypedArray<Array>()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_surface_count"), &ImporterMesh::get_surface_count); ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &ImporterMesh::get_surface_primitive_type); @@ -1246,7 +1283,7 @@ void ImporterMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name); ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material); - ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle"), &ImporterMesh::generate_lods); + ClassDB::bind_method(D_METHOD("generate_lods", "normal_merge_angle", "normal_split_angle", "bone_transform_array"), &ImporterMesh::generate_lods); ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>())); ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear); diff --git a/scene/resources/importer_mesh.h b/scene/resources/importer_mesh.h index bf1d0301d1..088a77edd1 100644 --- a/scene/resources/importer_mesh.h +++ b/scene/resources/importer_mesh.h @@ -93,7 +93,7 @@ public: int get_blend_shape_count() const; String get_blend_shape_name(int p_blend_shape) const; - void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String(), const uint32_t p_flags = 0); + void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String(), const uint32_t p_flags = 0); int get_surface_count() const; void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode); @@ -112,7 +112,7 @@ public: void set_surface_material(int p_surface, const Ref<Material> &p_material); - void generate_lods(float p_normal_merge_angle, float p_normal_split_angle); + void generate_lods(float p_normal_merge_angle, float p_normal_split_angle, Array p_skin_pose_transform_array); void create_shadow_mesh(); Ref<ImporterMesh> get_shadow_mesh() const; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index bd0e470112..e47bfef576 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -31,6 +31,8 @@ #include "material.h" #include "core/config/engine.h" +#include "core/config/project_settings.h" +#include "core/error/error_macros.h" #include "core/version.h" #include "scene/main/scene_tree.h" #include "scene/scene_string_names.h" @@ -154,18 +156,9 @@ Material::~Material() { bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { if (shader.is_valid()) { - StringName pr = shader->remap_uniform(p_name); - if (!pr) { - String n = p_name; - if (n.find("param/") == 0) { //backwards compatibility - pr = n.substr(6, n.length()); - } - if (n.find("shader_uniform/") == 0) { //backwards compatibility - pr = n.replace_first("shader_uniform/", ""); - } - } + StringName pr = shader->remap_parameter(p_name); if (pr) { - set_shader_uniform(pr, p_value); + set_shader_parameter(pr, p_value); return true; } } @@ -175,24 +168,9 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const { if (shader.is_valid()) { - StringName pr = shader->remap_uniform(p_name); - if (!pr) { - String n = p_name; - if (n.find("param/") == 0) { //backwards compatibility - pr = n.substr(6, n.length()); - } - if (n.find("shader_uniform/") == 0) { //backwards compatibility - pr = n.replace_first("shader_uniform/", ""); - } - } - + StringName pr = shader->remap_parameter(p_name); if (pr) { - HashMap<StringName, Variant>::ConstIterator E = param_cache.find(pr); - if (E) { - r_ret = E->value; - } else { - r_ret = Variant(); - } + r_ret = get_shader_parameter(pr); return true; } } @@ -234,6 +212,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { PropertyInfo info; info.usage = PROPERTY_USAGE_GROUP; info.name = last_group.capitalize(); + info.hint_string = "shader_parameter/"; List<PropertyInfo> none_subgroup; none_subgroup.push_back(info); @@ -248,6 +227,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { PropertyInfo info; info.usage = PROPERTY_USAGE_SUBGROUP; info.name = last_subgroup.capitalize(); + info.hint_string = "shader_parameter/"; List<PropertyInfo> subgroup; subgroup.push_back(info); @@ -267,12 +247,13 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { PropertyInfo info; info.usage = PROPERTY_USAGE_GROUP; - info.name = "Shader Param"; + info.name = "Shader Parameters"; + info.hint_string = "shader_parameter/"; groups["<None>"]["<None>"].push_back(info); } PropertyInfo info = E->get(); - info.name = info.name; + info.name = "shader_parameter/" + info.name; groups[last_group][last_subgroup].push_back(info); } @@ -299,9 +280,9 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const { bool ShaderMaterial::_property_can_revert(const StringName &p_name) const { if (shader.is_valid()) { - StringName pr = shader->remap_uniform(p_name); + StringName pr = shader->remap_parameter(p_name); if (pr) { - Variant default_value = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr); + Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr); Variant current_value; _get(p_name, current_value); return default_value.get_type() != Variant::NIL && default_value != current_value; @@ -312,9 +293,9 @@ bool ShaderMaterial::_property_can_revert(const StringName &p_name) const { bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const { if (shader.is_valid()) { - StringName pr = shader->remap_uniform(p_name); + StringName pr = shader->remap_parameter(p_name); if (pr) { - r_property = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr); + r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr); return true; } } @@ -349,7 +330,7 @@ Ref<Shader> ShaderMaterial::get_shader() const { return shader; } -void ShaderMaterial::set_shader_uniform(const StringName &p_param, const Variant &p_value) { +void ShaderMaterial::set_shader_parameter(const StringName &p_param, const Variant &p_value) { if (p_value.get_type() == Variant::NIL) { param_cache.erase(p_param); RS::get_singleton()->material_set_param(_get_material(), p_param, Variant()); @@ -369,7 +350,7 @@ void ShaderMaterial::set_shader_uniform(const StringName &p_param, const Variant } } -Variant ShaderMaterial::get_shader_uniform(const StringName &p_param) const { +Variant ShaderMaterial::get_shader_parameter(const StringName &p_param) const { if (param_cache.has(p_param)) { return param_cache[p_param]; } else { @@ -384,20 +365,20 @@ void ShaderMaterial::_shader_changed() { void ShaderMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader); ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader); - ClassDB::bind_method(D_METHOD("set_shader_uniform", "param", "value"), &ShaderMaterial::set_shader_uniform); - ClassDB::bind_method(D_METHOD("get_shader_uniform", "param"), &ShaderMaterial::get_shader_uniform); + ClassDB::bind_method(D_METHOD("set_shader_parameter", "param", "value"), &ShaderMaterial::set_shader_parameter); + ClassDB::bind_method(D_METHOD("get_shader_parameter", "param"), &ShaderMaterial::get_shader_parameter); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"), "set_shader", "get_shader"); } void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { String f = p_function.operator String(); - if ((f == "get_shader_uniform" || f == "set_shader_uniform") && p_idx == 0) { + if ((f == "get_shader_parameter" || f == "set_shader_parameter") && p_idx == 0) { if (shader.is_valid()) { List<PropertyInfo> pl; shader->get_shader_uniform_list(&pl); for (const PropertyInfo &E : pl) { - r_options->push_back(E.name.replace_first("shader_uniform/", "").quote()); + r_options->push_back(E.name.replace_first("shader_parameter/", "").quote()); } } } @@ -920,6 +901,7 @@ void BaseMaterial3D::_update_shader() { if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } + code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n"; } break; case BILLBOARD_FIXED_Y: { code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);\n"; @@ -927,6 +909,7 @@ void BaseMaterial3D::_update_shader() { if (flags[FLAG_BILLBOARD_KEEP_SCALE]) { code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; } + code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n"; } break; case BILLBOARD_PARTICLES: { //make billboard @@ -935,6 +918,8 @@ void BaseMaterial3D::_update_shader() { code += " mat_world = mat_world * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; //set modelview code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat_world;\n"; + //set modelview normal + code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n"; //handle animation code += " float h_frames = float(particles_anim_h_frames);\n"; @@ -945,7 +930,7 @@ void BaseMaterial3D::_update_shader() { code += " particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n"; code += " } else {\n"; code += " particle_frame = mod(particle_frame, particle_total_frames);\n"; - code += " }"; + code += " }\n"; code += " UV /= vec2(h_frames, v_frames);\n"; code += " UV += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame + 0.5) / h_frames) / v_frames);\n"; } break; @@ -1504,13 +1489,27 @@ Color BaseMaterial3D::get_emission() const { return emission; } -void BaseMaterial3D::set_emission_energy(float p_emission_energy) { - emission_energy = p_emission_energy; - RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy); +void BaseMaterial3D::set_emission_energy_multiplier(float p_emission_energy_multiplier) { + emission_energy_multiplier = p_emission_energy_multiplier; + if (GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier * emission_intensity); + } else { + RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, p_emission_energy_multiplier); + } } -float BaseMaterial3D::get_emission_energy() const { - return emission_energy; +float BaseMaterial3D::get_emission_energy_multiplier() const { + return emission_energy_multiplier; +} + +void BaseMaterial3D::set_emission_intensity(float p_emission_intensity) { + ERR_FAIL_COND_EDMSG(!GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units"), "Cannot set material emission intensity when Physical Light Units disabled."); + emission_intensity = p_emission_intensity; + RS::get_singleton()->material_set_param(_get_material(), shader_names->emission_energy, emission_energy_multiplier * emission_intensity); +} + +float BaseMaterial3D::get_emission_intensity() const { + return emission_intensity; } void BaseMaterial3D::set_normal_scale(float p_normal_scale) { @@ -1884,6 +1883,10 @@ void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const { _validate_high_end("subsurf_scatter", p_property); _validate_high_end("heightmap", p_property); + if (p_property.name == "emission_intensity" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NONE; + } + if (p_property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -2463,8 +2466,11 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emission", "emission"), &BaseMaterial3D::set_emission); ClassDB::bind_method(D_METHOD("get_emission"), &BaseMaterial3D::get_emission); - ClassDB::bind_method(D_METHOD("set_emission_energy", "emission_energy"), &BaseMaterial3D::set_emission_energy); - ClassDB::bind_method(D_METHOD("get_emission_energy"), &BaseMaterial3D::get_emission_energy); + ClassDB::bind_method(D_METHOD("set_emission_energy_multiplier", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_emission_energy_multiplier"), &BaseMaterial3D::get_emission_energy_multiplier); + + ClassDB::bind_method(D_METHOD("set_emission_intensity", "emission_energy_multiplier"), &BaseMaterial3D::set_emission_intensity); + ClassDB::bind_method(D_METHOD("get_emission_intensity"), &BaseMaterial3D::get_emission_intensity); ClassDB::bind_method(D_METHOD("set_normal_scale", "normal_scale"), &BaseMaterial3D::set_normal_scale); ClassDB::bind_method(D_METHOD("get_normal_scale"), &BaseMaterial3D::get_normal_scale); @@ -2681,7 +2687,9 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Emission", "emission_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy", "get_emission_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy_multiplier", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_emission_energy_multiplier", "get_emission_energy_multiplier"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_intensity", PROPERTY_HINT_RANGE, "0,100000.0,0.01,or_greater,suffix:nt"), "set_emission_intensity", "get_emission_intensity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_EMISSION); @@ -2943,7 +2951,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_roughness(1.0); set_metallic(0.0); set_emission(Color(0, 0, 0)); - set_emission_energy(1.0); + set_emission_energy_multiplier(1.0); set_normal_scale(1); set_rim(1.0); set_rim_tint(0.5); @@ -2971,6 +2979,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_transparency(TRANSPARENCY_DISABLED); set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF); + // Alpha scissor threshold of 0.5 matches the glTF specification and Label3D default. + // <https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphacutoff> set_alpha_scissor_threshold(0.5); set_alpha_hash_scale(1.0); set_alpha_antialiasing_edge(0.3); @@ -3094,6 +3104,8 @@ bool StandardMaterial3D::_set(const StringName &p_name, const Variant &p_value) { "depth_flip_binormal", "heightmap_flip_binormal" }, { "depth_texture", "heightmap_texture" }, + { "emission_energy", "emission_energy_multiplier" }, + { nullptr, nullptr }, }; diff --git a/scene/resources/material.h b/scene/resources/material.h index c6be1b8766..6c81293ee3 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -115,8 +115,8 @@ public: void set_shader(const Ref<Shader> &p_shader); Ref<Shader> get_shader() const; - void set_shader_uniform(const StringName &p_param, const Variant &p_value); - Variant get_shader_uniform(const StringName &p_param) const; + void set_shader_parameter(const StringName &p_param, const Variant &p_value); + Variant get_shader_parameter(const StringName &p_param) const; virtual Shader::Mode get_shader_mode() const override; @@ -467,7 +467,8 @@ private: float metallic = 0.0f; float roughness = 0.0f; Color emission; - float emission_energy = 0.0f; + float emission_energy_multiplier = 1.0f; + float emission_intensity = 1000.0f; // In nits, equivalent to indoor lighting. float normal_scale = 0.0f; float rim = 0.0f; float rim_tint = 0.0f; @@ -573,8 +574,11 @@ public: void set_emission(const Color &p_emission); Color get_emission() const; - void set_emission_energy(float p_emission_energy); - float get_emission_energy() const; + void set_emission_energy_multiplier(float p_emission_energy_multiplier); + float get_emission_energy_multiplier() const; + + void set_emission_intensity(float p_emission_intensity); + float get_emission_intensity() const; void set_normal_scale(float p_normal_scale); float get_normal_scale() const; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 7f318af899..b42e65c8df 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1614,7 +1614,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const emit_changed(); } -void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, uint32_t p_flags) { +void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, uint32_t p_flags) { ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX); RS::SurfaceData surface; diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index fd3c2c4fa4..5ed4164117 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -265,7 +265,7 @@ protected: static void _bind_methods(); public: - void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0); + void add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes = TypedArray<Array>(), const Dictionary &p_lods = Dictionary(), uint32_t p_flags = 0); void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>()); diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 6c9c8ffdba..90ea879012 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -32,7 +32,7 @@ #ifdef DEBUG_ENABLED #include "servers/navigation_server_3d.h" -#endif +#endif // DEBUG_ENABLED void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) { ERR_FAIL_COND(p_mesh.is_null()); @@ -341,94 +341,8 @@ void NavigationMesh::clear_polygons() { polygons.clear(); } -#ifndef DISABLE_DEPRECATED -Ref<Mesh> NavigationMesh::get_debug_mesh() { - if (debug_mesh.is_valid()) { - return debug_mesh; - } - - Vector<Vector3> vertices = get_vertices(); - const Vector3 *vr = vertices.ptr(); - List<Face3> faces; - for (int i = 0; i < get_polygon_count(); i++) { - Vector<int> p = get_polygon(i); - - for (int j = 2; j < p.size(); j++) { - Face3 f; - f.vertex[0] = vr[p[0]]; - f.vertex[1] = vr[p[j - 1]]; - f.vertex[2] = vr[p[j]]; - - faces.push_back(f); - } - } - - HashMap<_EdgeKey, bool, _EdgeKey> edge_map; - Vector<Vector3> tmeshfaces; - tmeshfaces.resize(faces.size() * 3); - - { - Vector3 *tw = tmeshfaces.ptrw(); - int tidx = 0; - - for (const Face3 &f : faces) { - for (int j = 0; j < 3; j++) { - tw[tidx++] = f.vertex[j]; - _EdgeKey ek; - ek.from = f.vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - ek.to = f.vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - if (ek.from < ek.to) { - SWAP(ek.from, ek.to); - } - - HashMap<_EdgeKey, bool, _EdgeKey>::Iterator F = edge_map.find(ek); - - if (F) { - F->value = false; - - } else { - edge_map[ek] = true; - } - } - } - } - List<Vector3> lines; - - for (const KeyValue<_EdgeKey, bool> &E : edge_map) { - if (E.value) { - lines.push_back(E.key.from); - lines.push_back(E.key.to); - } - } - - Vector<Vector3> varr; - varr.resize(lines.size()); - { - Vector3 *w = varr.ptrw(); - int idx = 0; - for (const Vector3 &E : lines) { - w[idx++] = E; - } - } - - debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - - if (!lines.size()) { - return debug_mesh; - } - - Array arr; - arr.resize(Mesh::ARRAY_MAX); - arr[Mesh::ARRAY_VERTEX] = varr; - - debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, arr); - - return debug_mesh; -} -#endif // DISABLE_DEPRECATED - #ifdef DEBUG_ENABLED -Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() { +Ref<ArrayMesh> NavigationMesh::get_debug_mesh() { if (debug_mesh.is_valid()) { // Blocks further updates for now, code below is intended for dynamic updates e.g. when settings change. return debug_mesh; @@ -479,8 +393,6 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() { for (int i = 0; i < polygon_count; i++) { polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf())); - Vector<int> polygon = get_polygon(i); - face_color_array.push_back(polygon_color); face_color_array.push_back(polygon_color); face_color_array.push_back(polygon_color); @@ -490,7 +402,7 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() { debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array); Ref<StandardMaterial3D> debug_geometry_face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material(); - debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_face_material); + debug_mesh->surface_set_material(0, debug_geometry_face_material); // if enabled build geometry edge line surface bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines(); @@ -515,12 +427,12 @@ Ref<ArrayMesh> NavigationMesh::_get_debug_mesh() { line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array; debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array); Ref<StandardMaterial3D> debug_geometry_edge_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material(); - debug_mesh->surface_set_material(debug_mesh->get_surface_count(), debug_geometry_edge_material); + debug_mesh->surface_set_material(1, debug_geometry_edge_material); } return debug_mesh; } -#endif +#endif // DEBUG_ENABLED void NavigationMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sample_partition_type", "sample_partition_type"), &NavigationMesh::set_sample_partition_type); diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index c66025dc6d..5ddbd75dcb 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -202,11 +202,9 @@ public: Vector<int> get_polygon(int p_idx); void clear_polygons(); -#ifndef DISABLE_DEPRECATED - Ref<Mesh> get_debug_mesh(); -#endif // DISABLE_DEPRECATED - - Ref<ArrayMesh> _get_debug_mesh(); +#ifdef DEBUG_ENABLED + Ref<ArrayMesh> get_debug_mesh(); +#endif // DEBUG_ENABLED NavigationMesh(); }; diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 33334801c3..e0bedad595 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1755,7 +1755,7 @@ Node *PackedScene::instantiate(GenEditState p_edit_state) const { s->set_scene_file_path(get_path()); } - s->notification(Node::NOTIFICATION_INSTANCED); + s->notification(Node::NOTIFICATION_SCENE_INSTANTIATED); return s; } diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index ed19101de4..e51c786786 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -1684,35 +1684,35 @@ void ParticleProcessMaterial::_bind_methods() { ADD_GROUP("Gravity", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity"); ADD_GROUP("Initial Velocity", "initial_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY); ADD_GROUP("Angular Velocity", "angular_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY); ADD_GROUP("Orbit Velocity", "orbit_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY); ADD_GROUP("Linear Accel", "linear_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL); ADD_GROUP("Radial Accel", "radial_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL); ADD_GROUP("Tangential Accel", "tangential_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL); ADD_GROUP("Damping", ""); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_less,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); ADD_GROUP("Scale", ""); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE); @@ -1741,11 +1741,11 @@ void ParticleProcessMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE); ADD_GROUP("Animation", "anim_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_less,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET); ADD_GROUP("Sub Emitter", "sub_emitter_"); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index fc5cf2a028..c017c90370 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -1822,7 +1822,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { float r = radius; if (curve.is_valid() && curve->get_point_count() > 0) { - r *= curve->interpolate_baked(v); + r *= curve->sample_baked(v); } float x = sin(u * Math_TAU); float z = cos(u * Math_TAU); @@ -1863,7 +1863,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { // add top float scale_pos = 1.0; if (curve.is_valid() && curve->get_point_count() > 0) { - scale_pos = curve->interpolate_baked(0); + scale_pos = curve->sample_baked(0); } if (scale_pos > CMP_EPSILON) { @@ -1925,7 +1925,7 @@ void TubeTrailMesh::_create_mesh_array(Array &p_arr) const { float scale_neg = 1.0; if (curve.is_valid() && curve->get_point_count() > 0) { - scale_neg = curve->interpolate_baked(1.0); + scale_neg = curve->sample_baked(1.0); } // add bottom @@ -2138,7 +2138,7 @@ void RibbonTrailMesh::_create_mesh_array(Array &p_arr) const { float s = size; if (curve.is_valid() && curve->get_point_count() > 0) { - s *= curve->interpolate_baked(v); + s *= curve->sample_baked(v); } points.push_back(Vector3(-s * 0.5, y, 0)); @@ -2663,9 +2663,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { vertices_ptr[p_idx] = point; normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0); if (has_depth) { - uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0))); + uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0))); } else { - uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0))); + uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0))); } tangents_ptr[p_idx * 4 + 0] = 1.0; tangents_ptr[p_idx * 4 + 1] = 0.0; @@ -2680,7 +2680,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0); vertices_ptr[p_idx] = point; normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0); - uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4))); + uvs_ptr[p_idx] = Vector2(Math::remap(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4))); tangents_ptr[p_idx * 4 + 0] = -1.0; tangents_ptr[p_idx * 4 + 1] = 0.0; tangents_ptr[p_idx * 4 + 2] = 0.0; @@ -2721,9 +2721,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { vertices_ptr[p_idx + m] = quad_faces[m]; normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0); if (m < 2) { - uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9); + uvs_ptr[p_idx + m] = Vector2(Math::remap(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9); } else { - uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0); + uvs_ptr[p_idx + m] = Vector2(Math::remap(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0); } tangents_ptr[(p_idx + m) * 4 + 0] = d.x; tangents_ptr[(p_idx + m) * 4 + 1] = -d.y; @@ -2760,9 +2760,9 @@ void TextMesh::_create_mesh_array(Array &p_arr) const { vertices_ptr[p_idx + k] = quad_faces[k]; normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0); if (has_depth) { - uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0))); + uvs_ptr[p_idx + k] = Vector2(Math::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0))); } else { - uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0))); + uvs_ptr[p_idx + k] = Vector2(Math::remap(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::remap(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0))); } tangents_ptr[(p_idx + k) * 4 + 0] = 1.0; tangents_ptr[(p_idx + k) * 4 + 1] = 0.0; diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index a64b262cb4..6ebf96db8e 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -41,7 +41,7 @@ void RectangleShape2D::_update_shape() { bool RectangleShape2D::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "extents") { // Compatibility with Godot 3.x. // Convert to `size`, twice as big. - set_size((Vector2)p_value * 2); + set_size((Size2)p_value * 2); return true; } return false; @@ -57,13 +57,13 @@ bool RectangleShape2D::_get(const StringName &p_name, Variant &r_property) const } #endif // DISABLE_DEPRECATED -void RectangleShape2D::set_size(const Vector2 &p_size) { +void RectangleShape2D::set_size(const Size2 &p_size) { ERR_FAIL_COND_MSG(p_size.x < 0 || p_size.y < 0, "RectangleShape2D size cannot be negative."); size = p_size; _update_shape(); } -Vector2 RectangleShape2D::get_size() const { +Size2 RectangleShape2D::get_size() const { return size; } @@ -106,6 +106,6 @@ void RectangleShape2D::_bind_methods() { RectangleShape2D::RectangleShape2D() : Shape2D(PhysicsServer2D::get_singleton()->rectangle_shape_create()) { - size = Vector2(20, 20); + size = Size2(20, 20); _update_shape(); } diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h index fa85aef428..9cc7b999be 100644 --- a/scene/resources/rectangle_shape_2d.h +++ b/scene/resources/rectangle_shape_2d.h @@ -36,7 +36,7 @@ class RectangleShape2D : public Shape2D { GDCLASS(RectangleShape2D, Shape2D); - Vector2 size; + Size2 size; void _update_shape(); protected: @@ -47,8 +47,8 @@ protected: #endif // DISABLE_DEPRECATED public: - void set_size(const Vector2 &p_size); - Vector2 get_size() const; + void set_size(const Size2 &p_size); + Size2 get_size() const; virtual void draw(const RID &p_to_rid, const Color &p_color) override; virtual Rect2 get_rect() const override; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 2b1d91e4ef..0d798d2e27 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -451,7 +451,7 @@ Error ResourceLoaderText::load() { if (!path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path - path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path)); } if (remaps.has(path)) { @@ -861,7 +861,7 @@ void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_d if (!using_uid && !path.contains("://") && path.is_relative_path()) { // path is relative to file being loaded, so convert to a resource path - path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); + path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path)); } if (p_add_types) { @@ -938,7 +938,7 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String } bool relative = false; if (!path.begins_with("res://")) { - path = base_path.plus_file(path).simplify_path(); + path = base_path.path_join(path).simplify_path(); relative = true; } diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 48d06934e3..4d566178a5 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -107,7 +107,7 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr _update_shader(); List<PropertyInfo> local; - RenderingServer::get_singleton()->shader_get_shader_uniform_list(shader, &local); + RenderingServer::get_singleton()->get_shader_parameter_list(shader, &local); params_cache.clear(); params_cache_dirty = false; @@ -138,35 +138,35 @@ RID Shader::get_rid() const { return shader; } -void Shader::set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index) { +void Shader::set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index) { if (p_texture.is_valid()) { - if (!default_textures.has(p_param)) { - default_textures[p_param] = HashMap<int, Ref<Texture2D>>(); + if (!default_textures.has(p_name)) { + default_textures[p_name] = HashMap<int, Ref<Texture2D>>(); } - default_textures[p_param][p_index] = p_texture; - RS::get_singleton()->shader_set_default_texture_param(shader, p_param, p_texture->get_rid(), p_index); + default_textures[p_name][p_index] = p_texture; + RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, p_texture->get_rid(), p_index); } else { - if (default_textures.has(p_param) && default_textures[p_param].has(p_index)) { - default_textures[p_param].erase(p_index); + if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) { + default_textures[p_name].erase(p_index); - if (default_textures[p_param].is_empty()) { - default_textures.erase(p_param); + if (default_textures[p_name].is_empty()) { + default_textures.erase(p_name); } } - RS::get_singleton()->shader_set_default_texture_param(shader, p_param, RID(), p_index); + RS::get_singleton()->shader_set_default_texture_parameter(shader, p_name, RID(), p_index); } emit_changed(); } -Ref<Texture2D> Shader::get_default_texture_param(const StringName &p_param, int p_index) const { - if (default_textures.has(p_param) && default_textures[p_param].has(p_index)) { - return default_textures[p_param][p_index]; +Ref<Texture2D> Shader::get_default_texture_parameter(const StringName &p_name, int p_index) const { + if (default_textures.has(p_name) && default_textures[p_name].has(p_index)) { + return default_textures[p_name][p_index]; } return Ref<Texture2D>(); } -void Shader::get_default_texture_param_list(List<StringName> *r_textures) const { +void Shader::get_default_texture_parameter_list(List<StringName> *r_textures) const { for (const KeyValue<StringName, HashMap<int, Ref<Texture2D>>> &E : default_textures) { r_textures->push_back(E.key); } @@ -176,8 +176,8 @@ bool Shader::is_text_shader() const { return true; } -bool Shader::has_uniform(const StringName &p_param) const { - return params_cache.has("shader_uniform/" + p_param); +bool Shader::has_parameter(const StringName &p_name) const { + return params_cache.has("shader_parameter/" + p_name); } void Shader::_update_shader() const { @@ -189,10 +189,10 @@ void Shader::_bind_methods() { ClassDB::bind_method(D_METHOD("set_code", "code"), &Shader::set_code); ClassDB::bind_method(D_METHOD("get_code"), &Shader::get_code); - ClassDB::bind_method(D_METHOD("set_default_texture_param", "param", "texture", "index"), &Shader::set_default_texture_param, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("get_default_texture_param", "param", "index"), &Shader::get_default_texture_param, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("set_default_texture_parameter", "name", "texture", "index"), &Shader::set_default_texture_parameter, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_default_texture_parameter", "name", "index"), &Shader::get_default_texture_parameter, DEFVAL(0)); - ClassDB::bind_method(D_METHOD("has_uniform", "name"), &Shader::has_uniform); + ClassDB::bind_method(D_METHOD("has_parameter", "name"), &Shader::has_parameter); ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code"); diff --git a/scene/resources/shader.h b/scene/resources/shader.h index abc953de5f..57be142a95 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -79,23 +79,52 @@ public: String get_code() const; void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const; - bool has_uniform(const StringName &p_param) const; + bool has_parameter(const StringName &p_name) const; - void set_default_texture_param(const StringName &p_uniform, const Ref<Texture2D> &p_texture, int p_index = 0); - Ref<Texture2D> get_default_texture_param(const StringName &p_uniform, int p_index = 0) const; - void get_default_texture_param_list(List<StringName> *r_textures) const; + void set_default_texture_parameter(const StringName &p_name, const Ref<Texture2D> &p_texture, int p_index = 0); + Ref<Texture2D> get_default_texture_parameter(const StringName &p_name, int p_index = 0) const; + void get_default_texture_parameter_list(List<StringName> *r_textures) const; virtual bool is_text_shader() const; - _FORCE_INLINE_ StringName remap_uniform(const StringName &p_uniform) const { + // Finds the shader parameter name for the given property name, which should start with "shader_parameter/". + _FORCE_INLINE_ StringName remap_parameter(const StringName &p_property) const { if (params_cache_dirty) { get_shader_uniform_list(nullptr); } - const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_uniform); - if (E) { - return E->value; + String n = p_property; + + // Backwards compatibility with old shader parameter names. + // Note: The if statements are important to make sure we are only replacing text exactly at index 0. + if (n.find("param/") == 0) { + n = n.replace_first("param/", "shader_parameter/"); + } + if (n.find("shader_param/") == 0) { + n = n.replace_first("shader_param/", "shader_parameter/"); + } + if (n.find("shader_uniform/") == 0) { + n = n.replace_first("shader_uniform/", "shader_parameter/"); + } + + { + // Additional backwards compatibility for projects between #62972 and #64092 (about a month of v4.0 development). + // These projects did not have any prefix for shader uniforms due to a bug. + // This code should be removed during beta or rc of 4.0. + const HashMap<StringName, StringName>::Iterator E = params_cache.find(n); + if (E) { + return E->value; + } + } + + if (n.begins_with("shader_parameter/")) { + n = n.replace_first("shader_parameter/", ""); + const HashMap<StringName, StringName>::Iterator E = params_cache.find(n); + if (E) { + return E->value; + } } + return StringName(); } diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp index 38ec19828f..068c756849 100644 --- a/scene/resources/skeleton_modification_stack_2d.cpp +++ b/scene/resources/skeleton_modification_stack_2d.cpp @@ -138,7 +138,7 @@ void SkeletonModificationStack2D::set_editor_gizmos_dirty(bool p_dirty) { if (!editor_gizmo_dirty && p_dirty) { editor_gizmo_dirty = p_dirty; if (skeleton) { - skeleton->update(); + skeleton->queue_redraw(); } } else { editor_gizmo_dirty = p_dirty; diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 737c50e570..d21f04fab8 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -30,10 +30,11 @@ #include "sky_material.h" +#include "core/config/project_settings.h" #include "core/version.h" Mutex ProceduralSkyMaterial::shader_mutex; -RID ProceduralSkyMaterial::shader; +RID ProceduralSkyMaterial::shader_cache[2]; void ProceduralSkyMaterial::set_sky_top_color(const Color &p_sky_top) { sky_top_color = p_sky_top; @@ -62,13 +63,13 @@ float ProceduralSkyMaterial::get_sky_curve() const { return sky_curve; } -void ProceduralSkyMaterial::set_sky_energy(float p_energy) { - sky_energy = p_energy; - RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy); +void ProceduralSkyMaterial::set_sky_energy_multiplier(float p_multiplier) { + sky_energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "sky_energy", sky_energy_multiplier); } -float ProceduralSkyMaterial::get_sky_energy() const { - return sky_energy; +float ProceduralSkyMaterial::get_sky_energy_multiplier() const { + return sky_energy_multiplier; } void ProceduralSkyMaterial::set_sky_cover(const Ref<Texture2D> &p_sky_cover) { @@ -117,13 +118,13 @@ float ProceduralSkyMaterial::get_ground_curve() const { return ground_curve; } -void ProceduralSkyMaterial::set_ground_energy(float p_energy) { - ground_energy = p_energy; - RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy); +void ProceduralSkyMaterial::set_ground_energy_multiplier(float p_multiplier) { + ground_energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "ground_energy", ground_energy_multiplier); } -float ProceduralSkyMaterial::get_ground_energy() const { - return ground_energy; +float ProceduralSkyMaterial::get_ground_energy_multiplier() const { + return ground_energy_multiplier; } void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) { @@ -146,7 +147,11 @@ float ProceduralSkyMaterial::get_sun_curve() const { void ProceduralSkyMaterial::set_use_debanding(bool p_use_debanding) { use_debanding = p_use_debanding; - RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding); + _update_shader(); + // Only set if shader already compiled + if (shader_set) { + RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]); + } } bool ProceduralSkyMaterial::get_use_debanding() const { @@ -160,7 +165,8 @@ Shader::Mode ProceduralSkyMaterial::get_shader_mode() const { RID ProceduralSkyMaterial::get_rid() const { _update_shader(); if (!shader_set) { - RS::get_singleton()->material_set_shader(_get_material(), shader); + RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]); + RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]); shader_set = true; } return _get_material(); @@ -168,7 +174,13 @@ RID ProceduralSkyMaterial::get_rid() const { RID ProceduralSkyMaterial::get_shader_rid() const { _update_shader(); - return shader; + return shader_cache[int(use_debanding)]; +} + +void ProceduralSkyMaterial::_validate_property(PropertyInfo &p_property) const { + if ((p_property.name == "sky_luminance" || p_property.name == "ground_luminance") && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } } void ProceduralSkyMaterial::_bind_methods() { @@ -181,8 +193,8 @@ void ProceduralSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_sky_curve", "curve"), &ProceduralSkyMaterial::set_sky_curve); ClassDB::bind_method(D_METHOD("get_sky_curve"), &ProceduralSkyMaterial::get_sky_curve); - ClassDB::bind_method(D_METHOD("set_sky_energy", "energy"), &ProceduralSkyMaterial::set_sky_energy); - ClassDB::bind_method(D_METHOD("get_sky_energy"), &ProceduralSkyMaterial::get_sky_energy); + ClassDB::bind_method(D_METHOD("set_sky_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_sky_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_sky_energy_multiplier"), &ProceduralSkyMaterial::get_sky_energy_multiplier); ClassDB::bind_method(D_METHOD("set_sky_cover", "sky_cover"), &ProceduralSkyMaterial::set_sky_cover); ClassDB::bind_method(D_METHOD("get_sky_cover"), &ProceduralSkyMaterial::get_sky_cover); @@ -199,8 +211,8 @@ void ProceduralSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ground_curve", "curve"), &ProceduralSkyMaterial::set_ground_curve); ClassDB::bind_method(D_METHOD("get_ground_curve"), &ProceduralSkyMaterial::get_ground_curve); - ClassDB::bind_method(D_METHOD("set_ground_energy", "energy"), &ProceduralSkyMaterial::set_ground_energy); - ClassDB::bind_method(D_METHOD("get_ground_energy"), &ProceduralSkyMaterial::get_ground_energy); + ClassDB::bind_method(D_METHOD("set_ground_energy_multiplier", "energy"), &ProceduralSkyMaterial::set_ground_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_ground_energy_multiplier"), &ProceduralSkyMaterial::get_ground_energy_multiplier); ClassDB::bind_method(D_METHOD("set_sun_angle_max", "degrees"), &ProceduralSkyMaterial::set_sun_angle_max); ClassDB::bind_method(D_METHOD("get_sun_angle_max"), &ProceduralSkyMaterial::get_sun_angle_max); @@ -215,7 +227,7 @@ void ProceduralSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_curve", PROPERTY_HINT_EXP_EASING), "set_sky_curve", "get_sky_curve"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy", "get_sky_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sky_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_sky_energy_multiplier", "get_sky_energy_multiplier"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "sky_cover", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_sky_cover", "get_sky_cover"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_cover_modulate"), "set_sky_cover_modulate", "get_sky_cover_modulate"); @@ -223,7 +235,7 @@ void ProceduralSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_bottom_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_bottom_color", "get_ground_bottom_color"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_horizon_color", "get_ground_horizon_color"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_curve", PROPERTY_HINT_EXP_EASING), "set_ground_curve", "get_ground_curve"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy", "get_ground_energy"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ground_energy_multiplier", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_ground_energy_multiplier", "get_ground_energy_multiplier"); ADD_GROUP("Sun", "sun_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_angle_max", PROPERTY_HINT_RANGE, "0,360,0.01,degrees"), "set_sun_angle_max", "get_sun_angle_max"); @@ -234,26 +246,29 @@ void ProceduralSkyMaterial::_bind_methods() { } void ProceduralSkyMaterial::cleanup_shader() { - if (shader.is_valid()) { - RS::get_singleton()->free(shader); + if (shader_cache[0].is_valid()) { + RS::get_singleton()->free(shader_cache[0]); + RS::get_singleton()->free(shader_cache[1]); } } void ProceduralSkyMaterial::_update_shader() { shader_mutex.lock(); - if (shader.is_null()) { - shader = RS::get_singleton()->shader_create(); + if (shader_cache[0].is_null()) { + for (int i = 0; i < 2; i++) { + shader_cache[i] = RS::get_singleton()->shader_create(); - // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). - RS::get_singleton()->shader_set_code(shader, R"( + // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). + RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"( // NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s ProceduralSkyMaterial. shader_type sky; +%s uniform vec4 sky_top_color : source_color = vec4(0.385, 0.454, 0.55, 1.0); uniform vec4 sky_horizon_color : source_color = vec4(0.646, 0.656, 0.67, 1.0); uniform float sky_curve : hint_range(0, 1) = 0.15; -uniform float sky_energy = 1.0; +uniform float sky_energy = 1.0; // In Lux. uniform sampler2D sky_cover : source_color, hint_default_black; uniform vec4 sky_cover_modulate : source_color = vec4(1.0, 1.0, 1.0, 1.0); uniform vec4 ground_bottom_color : source_color = vec4(0.2, 0.169, 0.133, 1.0); @@ -262,14 +277,6 @@ uniform float ground_curve : hint_range(0, 1) = 0.02; uniform float ground_energy = 1.0; uniform float sun_angle_max = 30.0; uniform float sun_curve : hint_range(0, 1) = 0.15; -uniform bool use_debanding = true; - -// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare -vec3 interleaved_gradient_noise(vec2 pos) { - const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); - float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0; - return vec3(res, -res, res) / 255.0; -} void sky() { float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0)); @@ -325,11 +332,10 @@ void sky() { ground *= ground_energy; COLOR = mix(ground, sky, step(0.0, EYEDIR.y)); - if (use_debanding) { - COLOR += interleaved_gradient_noise(FRAGCOORD.xy); - } } -)"); +)", + i ? "render_mode use_debanding;" : "")); + } } shader_mutex.unlock(); } @@ -338,13 +344,13 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() { set_sky_top_color(Color(0.385, 0.454, 0.55)); set_sky_horizon_color(Color(0.6463, 0.6558, 0.6708)); set_sky_curve(0.15); - set_sky_energy(1.0); + set_sky_energy_multiplier(1.0); set_sky_cover_modulate(Color(1, 1, 1)); set_ground_bottom_color(Color(0.2, 0.169, 0.133)); set_ground_horizon_color(Color(0.6463, 0.6558, 0.6708)); set_ground_curve(0.02); - set_ground_energy(1.0); + set_ground_energy_multiplier(1.0); set_sun_angle_max(30.0); set_sun_curve(0.15); @@ -528,18 +534,22 @@ Color PhysicalSkyMaterial::get_ground_color() const { return ground_color; } -void PhysicalSkyMaterial::set_exposure(float p_exposure) { - exposure = p_exposure; - RS::get_singleton()->material_set_param(_get_material(), "exposure", exposure); +void PhysicalSkyMaterial::set_energy_multiplier(float p_multiplier) { + energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier); } -float PhysicalSkyMaterial::get_exposure() const { - return exposure; +float PhysicalSkyMaterial::get_energy_multiplier() const { + return energy_multiplier; } void PhysicalSkyMaterial::set_use_debanding(bool p_use_debanding) { use_debanding = p_use_debanding; - RS::get_singleton()->material_set_param(_get_material(), "use_debanding", use_debanding); + _update_shader(); + // Only set if shader already compiled + if (shader_set) { + RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]); + } } bool PhysicalSkyMaterial::get_use_debanding() const { @@ -563,7 +573,8 @@ Shader::Mode PhysicalSkyMaterial::get_shader_mode() const { RID PhysicalSkyMaterial::get_rid() const { _update_shader(); if (!shader_set) { - RS::get_singleton()->material_set_shader(_get_material(), shader); + RS::get_singleton()->material_set_shader(_get_material(), shader_cache[1 - int(use_debanding)]); + RS::get_singleton()->material_set_shader(_get_material(), shader_cache[int(use_debanding)]); shader_set = true; } return _get_material(); @@ -571,11 +582,17 @@ RID PhysicalSkyMaterial::get_rid() const { RID PhysicalSkyMaterial::get_shader_rid() const { _update_shader(); - return shader; + return shader_cache[int(use_debanding)]; +} + +void PhysicalSkyMaterial::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "exposure_value" && !GLOBAL_GET("rendering/lights_and_shadows/use_physical_light_units")) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } } Mutex PhysicalSkyMaterial::shader_mutex; -RID PhysicalSkyMaterial::shader; +RID PhysicalSkyMaterial::shader_cache[2]; void PhysicalSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rayleigh_coefficient", "rayleigh"), &PhysicalSkyMaterial::set_rayleigh_coefficient); @@ -602,8 +619,8 @@ void PhysicalSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ground_color", "color"), &PhysicalSkyMaterial::set_ground_color); ClassDB::bind_method(D_METHOD("get_ground_color"), &PhysicalSkyMaterial::get_ground_color); - ClassDB::bind_method(D_METHOD("set_exposure", "exposure"), &PhysicalSkyMaterial::set_exposure); - ClassDB::bind_method(D_METHOD("get_exposure"), &PhysicalSkyMaterial::get_exposure); + ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PhysicalSkyMaterial::set_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PhysicalSkyMaterial::get_energy_multiplier); ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &PhysicalSkyMaterial::set_use_debanding); ClassDB::bind_method(D_METHOD("get_use_debanding"), &PhysicalSkyMaterial::get_use_debanding); @@ -623,27 +640,30 @@ void PhysicalSkyMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbidity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_turbidity", "get_turbidity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sun_disk_scale", PROPERTY_HINT_RANGE, "0,360,0.01"), "set_sun_disk_scale", "get_sun_disk_scale"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ground_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ground_color", "get_ground_color"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "exposure", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_exposure", "get_exposure"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "night_sky", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_night_sky", "get_night_sky"); } void PhysicalSkyMaterial::cleanup_shader() { - if (shader.is_valid()) { - RS::get_singleton()->free(shader); + if (shader_cache[0].is_valid()) { + RS::get_singleton()->free(shader_cache[0]); + RS::get_singleton()->free(shader_cache[1]); } } void PhysicalSkyMaterial::_update_shader() { shader_mutex.lock(); - if (shader.is_null()) { - shader = RS::get_singleton()->shader_create(); + if (shader_cache[0].is_null()) { + for (int i = 0; i < 2; i++) { + shader_cache[i] = RS::get_singleton()->shader_create(); - // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). - RS::get_singleton()->shader_set_code(shader, R"( + // Add a comment to describe the shader origin (useful when converting to ShaderMaterial). + RS::get_singleton()->shader_set_code(shader_cache[i], vformat(R"( // NOTE: Shader automatically converted from )" VERSION_NAME " " VERSION_FULL_CONFIG R"('s PhysicalSkyMaterial. shader_type sky; +%s uniform float rayleigh : hint_range(0, 64) = 2.0; uniform vec4 rayleigh_color : source_color = vec4(0.3, 0.405, 0.6, 1.0); @@ -654,16 +674,12 @@ uniform vec4 mie_color : source_color = vec4(0.69, 0.729, 0.812, 1.0); uniform float turbidity : hint_range(0, 1000) = 10.0; uniform float sun_disk_scale : hint_range(0, 360) = 1.0; uniform vec4 ground_color : source_color = vec4(0.1, 0.07, 0.034, 1.0); -uniform float exposure : hint_range(0, 128) = 0.1; -uniform bool use_debanding = true; +uniform float exposure : hint_range(0, 128) = 1.0; uniform sampler2D night_sky : source_color, hint_default_black; const vec3 UP = vec3( 0.0, 1.0, 0.0 ); -// Sun constants -const float SUN_ENERGY = 1000.0; - // Optical length at zenith for molecules. const float rayleigh_zenith_size = 8.4e3; const float mie_zenith_size = 1.25e3; @@ -673,17 +689,10 @@ float henyey_greenstein(float cos_theta, float g) { return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5)); } -// https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare -vec3 interleaved_gradient_noise(vec2 pos) { - const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); - float res = fract(magic.z * fract(dot(pos, magic.xy))) * 2.0 - 1.0; - return vec3(res, -res, res) / 255.0; -} - void sky() { if (LIGHT0_ENABLED) { float zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 ); - float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY; + float sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * LIGHT0_ENERGY; float sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0); // Rayleigh coefficients. @@ -721,22 +730,21 @@ void sky() { float sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale); float sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5); float sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta); - vec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR; + vec3 L0 = (sun_energy * extinction) * sundisk * LIGHT0_COLOR; L0 += texture(night_sky, SKY_COORDS).xyz * extinction; - vec3 color = (Lin + L0) * 0.04; + vec3 color = Lin + L0; COLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade)))); COLOR *= exposure; - if (use_debanding) { - COLOR += interleaved_gradient_noise(FRAGCOORD.xy); - } } else { // There is no sun, so display night_sky and nothing else. - COLOR = texture(night_sky, SKY_COORDS).xyz * 0.04; + COLOR = texture(night_sky, SKY_COORDS).xyz; COLOR *= exposure; } } -)"); +)", + i ? "render_mode use_debanding;" : "")); + } } shader_mutex.unlock(); @@ -751,7 +759,7 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { set_turbidity(10.0); set_sun_disk_scale(1.0); set_ground_color(Color(0.1, 0.07, 0.034)); - set_exposure(0.1); + set_energy_multiplier(1.0); set_use_debanding(true); } diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 61999af3c4..fbb202d8d8 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -41,26 +41,27 @@ private: Color sky_top_color; Color sky_horizon_color; float sky_curve = 0.0f; - float sky_energy = 0.0f; + float sky_energy_multiplier = 0.0f; Ref<Texture2D> sky_cover; Color sky_cover_modulate; Color ground_bottom_color; Color ground_horizon_color; float ground_curve = 0.0f; - float ground_energy = 0.0f; + float ground_energy_multiplier = 0.0f; float sun_angle_max = 0.0f; float sun_curve = 0.0f; bool use_debanding = true; static Mutex shader_mutex; - static RID shader; + static RID shader_cache[2]; static void _update_shader(); mutable bool shader_set = false; protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: void set_sky_top_color(const Color &p_sky_top); @@ -72,8 +73,8 @@ public: void set_sky_curve(float p_curve); float get_sky_curve() const; - void set_sky_energy(float p_energy); - float get_sky_energy() const; + void set_sky_energy_multiplier(float p_multiplier); + float get_sky_energy_multiplier() const; void set_sky_cover(const Ref<Texture2D> &p_sky_cover); Ref<Texture2D> get_sky_cover() const; @@ -90,8 +91,8 @@ public: void set_ground_curve(float p_curve); float get_ground_curve() const; - void set_ground_energy(float p_energy); - float get_ground_energy() const; + void set_ground_energy_multiplier(float p_energy); + float get_ground_energy_multiplier() const; void set_sun_angle_max(float p_angle); float get_sun_angle_max() const; @@ -138,6 +139,9 @@ public: void set_filtering_enabled(bool p_enabled); bool is_filtering_enabled() const; + void set_energy_multiplier(float p_multiplier); + float get_energy_multiplier() const; + virtual Shader::Mode get_shader_mode() const override; virtual RID get_shader_rid() const override; virtual RID get_rid() const override; @@ -156,7 +160,7 @@ class PhysicalSkyMaterial : public Material { private: static Mutex shader_mutex; - static RID shader; + static RID shader_cache[2]; float rayleigh = 0.0f; Color rayleigh_color; @@ -166,7 +170,7 @@ private: float turbidity = 0.0f; float sun_disk_scale = 0.0f; Color ground_color; - float exposure = 0.0f; + float energy_multiplier = 1.0f; bool use_debanding = true; Ref<Texture2D> night_sky; static void _update_shader(); @@ -174,6 +178,7 @@ private: protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: void set_rayleigh_coefficient(float p_rayleigh); @@ -200,8 +205,11 @@ public: void set_ground_color(Color p_ground_color); Color get_ground_color() const; - void set_exposure(float p_exposure); - float get_exposure() const; + void set_energy_multiplier(float p_multiplier); + float get_energy_multiplier() const; + + void set_exposure_value(float p_exposure); + float get_exposure_value() const; void set_use_debanding(bool p_use_debanding); bool get_use_debanding() const; diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index ff5210f1b3..cd893d8c23 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -41,6 +41,7 @@ float StyleBox::get_style_margin(Side p_side) const { } 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)) { @@ -63,6 +64,21 @@ void StyleBox::set_default_margin(Side p_side, float p_value) { emit_changed(); } +void StyleBox::set_default_margin_all(float p_value) { + for (int i = 0; i < 4; i++) { + margin[i] = p_value; + } + emit_changed(); +} + +void StyleBox::set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom) { + margin[SIDE_LEFT] = p_left; + margin[SIDE_TOP] = p_top; + margin[SIDE_RIGHT] = p_right; + margin[SIDE_BOTTOM] = p_bottom; + emit_changed(); +} + float StyleBox::get_default_margin(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); @@ -112,6 +128,7 @@ void StyleBox::_bind_methods() { ClassDB::bind_method(D_METHOD("test_mask", "point", "rect"), &StyleBox::test_mask); ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin); + ClassDB::bind_method(D_METHOD("set_default_margin_all", "offset"), &StyleBox::set_default_margin_all); ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin); ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin); @@ -165,6 +182,21 @@ void StyleBoxTexture::set_margin_size(Side p_side, float p_size) { emit_changed(); } +void StyleBoxTexture::set_margin_size_all(float p_size) { + for (int i = 0; i < 4; i++) { + margin[i] = p_size; + } + emit_changed(); +} + +void StyleBoxTexture::set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { + margin[SIDE_LEFT] = p_left; + margin[SIDE_TOP] = p_top; + margin[SIDE_RIGHT] = p_right; + margin[SIDE_BOTTOM] = p_bottom; + emit_changed(); +} + float StyleBoxTexture::get_margin_size(Side p_side) const { ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); @@ -292,11 +324,11 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_texture"), &StyleBoxTexture::get_texture); ClassDB::bind_method(D_METHOD("set_margin_size", "margin", "size"), &StyleBoxTexture::set_margin_size); + ClassDB::bind_method(D_METHOD("set_margin_size_all", "size"), &StyleBoxTexture::set_margin_size_all); ClassDB::bind_method(D_METHOD("get_margin_size", "margin"), &StyleBoxTexture::get_margin_size); ClassDB::bind_method(D_METHOD("set_expand_margin_size", "margin", "size"), &StyleBoxTexture::set_expand_margin_size); ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxTexture::set_expand_margin_size_all); - ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxTexture::set_expand_margin_size_individual); ClassDB::bind_method(D_METHOD("get_expand_margin_size", "margin"), &StyleBoxTexture::get_expand_margin_size); ClassDB::bind_method(D_METHOD("set_region_rect", "region"), &StyleBoxTexture::set_region_rect); @@ -687,7 +719,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0); // Only enable antialiasing if it is actually needed. This improve performances // and maximizes sharpness for non-skewed StyleBoxes with sharp corners. - const bool aa_on = (rounded_corners || !skew.is_equal_approx(Vector2())) && anti_aliased; + const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased; const bool blend_on = blend_border && draw_border; @@ -864,7 +896,6 @@ void StyleBoxFlat::_bind_methods() { ClassDB::bind_method(D_METHOD("set_border_blend", "blend"), &StyleBoxFlat::set_border_blend); ClassDB::bind_method(D_METHOD("get_border_blend"), &StyleBoxFlat::get_border_blend); - ClassDB::bind_method(D_METHOD("set_corner_radius_individual", "radius_top_left", "radius_top_right", "radius_bottom_right", "radius_bottom_left"), &StyleBoxFlat::set_corner_radius_individual); ClassDB::bind_method(D_METHOD("set_corner_radius_all", "radius"), &StyleBoxFlat::set_corner_radius_all); ClassDB::bind_method(D_METHOD("set_corner_radius", "corner", "radius"), &StyleBoxFlat::set_corner_radius); @@ -872,7 +903,6 @@ void StyleBoxFlat::_bind_methods() { ClassDB::bind_method(D_METHOD("set_expand_margin", "margin", "size"), &StyleBoxFlat::set_expand_margin_size); ClassDB::bind_method(D_METHOD("set_expand_margin_all", "size"), &StyleBoxFlat::set_expand_margin_size_all); - ClassDB::bind_method(D_METHOD("set_expand_margin_individual", "size_left", "size_top", "size_right", "size_bottom"), &StyleBoxFlat::set_expand_margin_size_individual); ClassDB::bind_method(D_METHOD("get_expand_margin", "margin"), &StyleBoxFlat::get_expand_margin_size); ClassDB::bind_method(D_METHOD("set_draw_center", "draw_center"), &StyleBoxFlat::set_draw_center); diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 88db4f5fbd..2c72446567 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -57,7 +57,10 @@ public: virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const; void set_default_margin(Side p_side, float p_value); + void set_default_margin_all(float p_value); + void set_default_margin_individual(float p_left, float p_top, float p_right, float p_bottom); float get_default_margin(Side p_side) const; + float get_margin(Side p_side) const; virtual Size2 get_center_size() const; @@ -112,6 +115,8 @@ public: float get_expand_margin_size(Side p_expand_side) const; void set_margin_size(Side p_side, float p_size); + void set_margin_size_all(float p_size); + void set_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); float get_margin_size(Side p_side) const; void set_region_rect(const Rect2 &p_region_rect); diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index 43d3f329fa..7e9a2591e4 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -77,7 +77,7 @@ void TextParagraph::_bind_methods() { ClassDB::bind_method(D_METHOD("set_break_flags", "flags"), &TextParagraph::set_break_flags); ClassDB::bind_method(D_METHOD("get_break_flags"), &TextParagraph::get_break_flags); - ADD_PROPERTY(PropertyInfo(Variant::INT, "break_flags", PROPERTY_HINT_FLAGS, "Mandatory,Word Bound,Grapheme Bound,Adaptive"), "set_break_flags", "get_break_flags"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "break_flags", PROPERTY_HINT_FLAGS, "Mandatory,Word Bound,Grapheme Bound,Adaptive,Trim Spaces"), "set_break_flags", "get_break_flags"); ClassDB::bind_method(D_METHOD("set_justification_flags", "flags"), &TextParagraph::set_justification_flags); ClassDB::bind_method(D_METHOD("get_justification_flags"), &TextParagraph::get_justification_flags); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 25f5006c4f..d53dc1a8fc 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -294,7 +294,7 @@ bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const { x = CLAMP(x, 0, aw); y = CLAMP(y, 0, ah); - return alpha_cache->get_bit(Point2(x, y)); + return alpha_cache->get_bit(x, y); } return true; @@ -561,7 +561,7 @@ bool PortableCompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const { x = CLAMP(x, 0, aw); y = CLAMP(y, 0, ah); - return alpha_cache->get_bit(Point2(x, y)); + return alpha_cache->get_bit(x, y); } return true; @@ -1017,7 +1017,7 @@ bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const { x = CLAMP(x, 0, aw); y = CLAMP(y, 0, ah); - return alpha_cache->get_bit(Point2(x, y)); + return alpha_cache->get_bit(x, y); } return true; @@ -1866,11 +1866,11 @@ void CurveTexture::_update() { for (int i = 0; i < _width; ++i) { float t = i / static_cast<float>(_width); if (texture_mode == TEXTURE_MODE_RGB) { - wd[i * 3 + 0] = curve.interpolate_baked(t); + wd[i * 3 + 0] = curve.sample_baked(t); wd[i * 3 + 1] = wd[i * 3 + 0]; wd[i * 3 + 2] = wd[i * 3 + 0]; } else { - wd[i] = curve.interpolate_baked(t); + wd[i] = curve.sample_baked(t); } } @@ -2054,7 +2054,7 @@ void CurveXYZTexture::_update() { Curve &curve_x = **_curve_x; for (int i = 0; i < _width; ++i) { float t = i / static_cast<float>(_width); - wd[i * 3 + 0] = curve_x.interpolate_baked(t); + wd[i * 3 + 0] = curve_x.sample_baked(t); } } else { @@ -2067,7 +2067,7 @@ void CurveXYZTexture::_update() { Curve &curve_y = **_curve_y; for (int i = 0; i < _width; ++i) { float t = i / static_cast<float>(_width); - wd[i * 3 + 1] = curve_y.interpolate_baked(t); + wd[i * 3 + 1] = curve_y.sample_baked(t); } } else { @@ -2080,7 +2080,7 @@ void CurveXYZTexture::_update() { Curve &curve_z = **_curve_z; for (int i = 0; i < _width; ++i) { float t = i / static_cast<float>(_width); - wd[i * 3 + 2] = curve_z.interpolate_baked(t); + wd[i * 3 + 2] = curve_z.sample_baked(t); } } else { @@ -2617,26 +2617,30 @@ void AnimatedTexture::_update_proxy() { time += delta; - float limit; - - if (fps == 0) { - limit = 0; - } else { - limit = 1.0 / fps; - } + float speed = speed_scale == 0 ? 0 : abs(1.0 / speed_scale); int iter_max = frame_count; while (iter_max && !pause) { - float frame_limit = limit + frames[current_frame].delay_sec; + float frame_limit = frames[current_frame].duration * speed; if (time > frame_limit) { - current_frame++; + if (speed_scale > 0.0) { + current_frame++; + } else { + current_frame--; + } if (current_frame >= frame_count) { - if (oneshot) { + if (one_shot) { current_frame = frame_count - 1; } else { current_frame = 0; } + } else if (current_frame < 0) { + if (one_shot) { + current_frame = 0; + } else { + current_frame = frame_count - 1; + } } time -= frame_limit; @@ -2684,13 +2688,13 @@ bool AnimatedTexture::get_pause() const { return pause; } -void AnimatedTexture::set_oneshot(bool p_oneshot) { +void AnimatedTexture::set_one_shot(bool p_one_shot) { RWLockWrite r(rw_lock); - oneshot = p_oneshot; + one_shot = p_one_shot; } -bool AnimatedTexture::get_oneshot() const { - return oneshot; +bool AnimatedTexture::get_one_shot() const { + return one_shot; } void AnimatedTexture::set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture) { @@ -2710,30 +2714,30 @@ Ref<Texture2D> AnimatedTexture::get_frame_texture(int p_frame) const { return frames[p_frame].texture; } -void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) { +void AnimatedTexture::set_frame_duration(int p_frame, float p_duration) { ERR_FAIL_INDEX(p_frame, MAX_FRAMES); RWLockRead r(rw_lock); - frames[p_frame].delay_sec = p_delay_sec; + frames[p_frame].duration = p_duration; } -float AnimatedTexture::get_frame_delay(int p_frame) const { +float AnimatedTexture::get_frame_duration(int p_frame) const { ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0); RWLockRead r(rw_lock); - return frames[p_frame].delay_sec; + return frames[p_frame].duration; } -void AnimatedTexture::set_fps(float p_fps) { - ERR_FAIL_COND(p_fps < 0 || p_fps >= 1000); +void AnimatedTexture::set_speed_scale(float p_scale) { + ERR_FAIL_COND(p_scale < -1000 || p_scale >= 1000); - fps = p_fps; + speed_scale = p_scale; } -float AnimatedTexture::get_fps() const { - return fps; +float AnimatedTexture::get_speed_scale() const { + return speed_scale; } int AnimatedTexture::get_width() const { @@ -2809,27 +2813,27 @@ void AnimatedTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pause", "pause"), &AnimatedTexture::set_pause); ClassDB::bind_method(D_METHOD("get_pause"), &AnimatedTexture::get_pause); - ClassDB::bind_method(D_METHOD("set_oneshot", "oneshot"), &AnimatedTexture::set_oneshot); - ClassDB::bind_method(D_METHOD("get_oneshot"), &AnimatedTexture::get_oneshot); + ClassDB::bind_method(D_METHOD("set_one_shot", "one_shot"), &AnimatedTexture::set_one_shot); + ClassDB::bind_method(D_METHOD("get_one_shot"), &AnimatedTexture::get_one_shot); - ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps); - ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps); + ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &AnimatedTexture::set_speed_scale); + ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedTexture::get_speed_scale); ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture); ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture); - ClassDB::bind_method(D_METHOD("set_frame_delay", "frame", "delay"), &AnimatedTexture::set_frame_delay); - ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay); + ClassDB::bind_method(D_METHOD("set_frame_duration", "frame", "duration"), &AnimatedTexture::set_frame_duration); + ClassDB::bind_method(D_METHOD("get_frame_duration", "frame"), &AnimatedTexture::get_frame_duration); ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames"); ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "oneshot"), "set_oneshot", "get_oneshot"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_greater,or_lesser"), "set_speed_scale", "get_speed_scale"); for (int i = 0; i < MAX_FRAMES; i++) { ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/duration", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_duration", "get_frame_duration", i); } BIND_CONSTANT(MAX_FRAMES); @@ -2955,7 +2959,7 @@ ImageTextureLayered::LayeredType ImageTextureLayered::get_layered_type() const { return layered_type; } -Error ImageTextureLayered::_create_from_images(const Array &p_images) { +Error ImageTextureLayered::_create_from_images(const TypedArray<Image> &p_images) { Vector<Ref<Image>> images; for (int i = 0; i < p_images.size(); i++) { Ref<Image> img = p_images[i]; @@ -2966,8 +2970,8 @@ Error ImageTextureLayered::_create_from_images(const Array &p_images) { return create_from_images(images); } -Array ImageTextureLayered::_get_images() const { - Array images; +TypedArray<Image> ImageTextureLayered::_get_images() const { + TypedArray<Image> images; for (int i = 0; i < layers; i++) { images.push_back(get_layer_data(i)); } @@ -3054,7 +3058,7 @@ void ImageTextureLayered::_bind_methods() { ClassDB::bind_method(D_METHOD("_get_images"), &ImageTextureLayered::_get_images); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_ARRAY_TYPE, "Image", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images"); } ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 133b312d27..da4b8046a5 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -422,9 +422,9 @@ class ImageTextureLayered : public TextureLayered { int layers = 0; bool mipmaps = false; - Error _create_from_images(const Array &p_images); + Error _create_from_images(const TypedArray<Image> &p_images); - Array _get_images() const; + TypedArray<Image> _get_images() const; protected: static void _bind_methods(); @@ -922,15 +922,15 @@ private: struct Frame { Ref<Texture2D> texture; - float delay_sec = 0.0; + float duration = 1.0; }; Frame frames[MAX_FRAMES]; int frame_count = 1.0; int current_frame = 0; bool pause = false; - bool oneshot = false; - float fps = 4.0; + bool one_shot = false; + float speed_scale = 1.0; float time = 0.0; @@ -952,17 +952,17 @@ public: void set_pause(bool p_pause); bool get_pause() const; - void set_oneshot(bool p_oneshot); - bool get_oneshot() const; + void set_one_shot(bool p_one_shot); + bool get_one_shot() const; void set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture); Ref<Texture2D> get_frame_texture(int p_frame) const; - void set_frame_delay(int p_frame, float p_delay_sec); - float get_frame_delay(int p_frame) const; + void set_frame_duration(int p_frame, float p_duration); + float get_frame_duration(int p_frame) const; - void set_fps(float p_fps); - float get_fps() const; + void set_speed_scale(float p_scale); + float get_speed_scale() const; virtual int get_width() const override; virtual int get_height() const override; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 552d856034..9138a82ba8 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -118,7 +118,7 @@ void TileMapPattern::remove_cell(const Vector2i &p_coords, bool p_update_size) { pattern.erase(p_coords); if (p_update_size) { - size = Vector2i(); + size = Size2i(); for (const KeyValue<Vector2i, TileMapCell> &E : pattern) { size = size.max(E.key + Vector2i(1, 1)); } @@ -157,11 +157,11 @@ TypedArray<Vector2i> TileMapPattern::get_used_cells() const { return a; } -Vector2i TileMapPattern::get_size() const { +Size2i TileMapPattern::get_size() const { return size; } -void TileMapPattern::set_size(const Vector2i &p_size) { +void TileMapPattern::set_size(const Size2i &p_size) { for (const KeyValue<Vector2i, TileMapCell> &E : pattern) { Vector2i coords = E.key; if (p_size.x <= coords.x || p_size.y <= coords.y) { @@ -178,7 +178,7 @@ bool TileMapPattern::is_empty() const { }; void TileMapPattern::clear() { - size = Vector2i(); + size = Size2i(); pattern.clear(); emit_changed(); }; @@ -4716,14 +4716,19 @@ void TileSetScenesCollectionSource::set_scene_tile_id(int p_id, int p_new_id) { void TileSetScenesCollectionSource::set_scene_tile_scene(int p_id, Ref<PackedScene> p_packed_scene) { ERR_FAIL_COND(!scenes.has(p_id)); if (p_packed_scene.is_valid()) { - // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work. - ERR_FAIL_COND(!p_packed_scene->get_state().is_valid()); - ERR_FAIL_COND(p_packed_scene->get_state()->get_node_count() < 1); - // Check if it extends CanvasItem. - String type = p_packed_scene->get_state()->get_node_type(0); + Ref<SceneState> scene_state = p_packed_scene->get_state(); + String type; + while (scene_state.is_valid() && type.is_empty()) { + // Make sure we have a root node. Supposed to be at 0 index because find_node_by_path() does not seem to work. + ERR_FAIL_COND(scene_state->get_node_count() < 1); + + type = scene_state->get_node_type(0); + scene_state = scene_state->get_base_scene_state(); + } + ERR_FAIL_COND_MSG(type.is_empty(), vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Could not get the type of the root node.", p_packed_scene->get_path())); bool extends_correct_class = ClassDB::is_parent_class(type, "Control") || ClassDB::is_parent_class(type, "Node2D"); - ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D.", p_packed_scene->get_path())); + ERR_FAIL_COND_MSG(!extends_correct_class, vformat("Invalid PackedScene for TileSetScenesCollectionSource: %s. Root node should extend Control or Node2D. Found %s instead.", p_packed_scene->get_path(), type)); scenes[p_id].scene = p_packed_scene; } else { diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 4c0823cdf2..e156679711 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -117,7 +117,7 @@ union TileMapCell { class TileMapPattern : public Resource { GDCLASS(TileMapPattern, Resource); - Vector2i size; + Size2i size; HashMap<Vector2i, TileMapCell> pattern; void _set_tile_data(const Vector<int> &p_data); @@ -140,8 +140,8 @@ public: TypedArray<Vector2i> get_used_cells() const; - Vector2i get_size() const; - void set_size(const Vector2i &p_size); + Size2i get_size() const; + void set_size(const Size2i &p_size); bool is_empty() const; void clear(); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 90f1a1bff1..262dbe28ed 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -723,10 +723,10 @@ void VisualShader::add_node(Type p_type, const Ref<VisualShaderNode> &p_node, co n.node = p_node; n.position = p_position; - Ref<VisualShaderNodeUniform> uniform = n.node; - if (uniform.is_valid()) { - String valid_name = validate_uniform_name(uniform->get_uniform_name(), uniform); - uniform->set_uniform_name(valid_name); + Ref<VisualShaderNodeParameter> parameter = n.node; + if (parameter.is_valid()) { + String valid_name = validate_parameter_name(parameter->get_parameter_name(), parameter); + parameter->set_parameter_name(valid_name); } Ref<VisualShaderNodeInput> input = n.node; @@ -1279,7 +1279,7 @@ String VisualShader::validate_port_name(const String &p_port_name, VisualShaderN return name; } -String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const { +String VisualShader::validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const { String name = p_name; //validate name first while (name.length() && !is_ascii_char(name[0])) { name = name.substr(1, name.length() - 1); @@ -1299,7 +1299,7 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua } if (name.is_empty()) { - name = p_uniform->get_caption(); + name = p_parameter->get_caption(); } int attempt = 1; @@ -1308,11 +1308,11 @@ String VisualShader::validate_uniform_name(const String &p_name, const Ref<Visua bool exists = false; for (int i = 0; i < TYPE_MAX; i++) { for (const KeyValue<int, Node> &E : graph[i].nodes) { - Ref<VisualShaderNodeUniform> node = E.value.node; - if (node == p_uniform) { //do not test on self + Ref<VisualShaderNodeParameter> node = E.value.node; + if (node == p_parameter) { //do not test on self continue; } - if (node.is_valid() && node->get_uniform_name() == name) { + if (node.is_valid() && node->get_parameter_name() == name) { exists = true; break; } @@ -1620,8 +1620,8 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui bool skip_global = input.is_valid() && for_preview; if (!skip_global) { - Ref<VisualShaderNodeUniform> uniform = vsnode; - if (!uniform.is_valid() || !uniform->is_global_code_generated()) { + Ref<VisualShaderNodeParameter> parameter = vsnode; + if (!parameter.is_valid() || !parameter->is_global_code_generated()) { if (global_code) { *global_code += vsnode->generate_global(get_mode(), type, node); } @@ -1680,8 +1680,8 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui VisualShaderNode *ptr = const_cast<VisualShaderNode *>(graph[type].nodes[from_node].node.ptr()); if (ptr->has_method("get_input_real_name")) { inputs[i] = ptr->call("get_input_real_name"); - } else if (ptr->has_method("get_uniform_name")) { - inputs[i] = ptr->call("get_uniform_name"); + } else if (ptr->has_method("get_parameter_name")) { + inputs[i] = ptr->call("get_parameter_name"); } else { inputs[i] = ""; } @@ -2150,8 +2150,8 @@ void VisualShader::_update_shader() const { static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky", "fog" }; String global_expressions; - HashSet<String> used_uniform_names; - List<VisualShaderNodeUniform *> uniforms; + HashSet<String> used_parameter_names; + List<VisualShaderNodeParameter *> parameters; HashMap<int, List<int>> emitters; HashMap<int, List<int>> varying_setters; @@ -2170,13 +2170,13 @@ void VisualShader::_update_shader() const { expr += "\n"; global_expressions += expr; } - Ref<VisualShaderNodeUniformRef> uniform_ref = E.value.node; - if (uniform_ref.is_valid()) { - used_uniform_names.insert(uniform_ref->get_uniform_name()); + Ref<VisualShaderNodeParameterRef> parameter_ref = E.value.node; + if (parameter_ref.is_valid()) { + used_parameter_names.insert(parameter_ref->get_parameter_name()); } - Ref<VisualShaderNodeUniform> uniform = E.value.node; - if (uniform.is_valid()) { - uniforms.push_back(uniform.ptr()); + Ref<VisualShaderNodeParameter> parameter = E.value.node; + if (parameter.is_valid()) { + parameters.push_back(parameter.ptr()); } Ref<VisualShaderNodeVaryingSetter> varying_setter = E.value.node; if (varying_setter.is_valid() && varying_setter->is_input_port_connected(0)) { @@ -2195,13 +2195,13 @@ void VisualShader::_update_shader() const { } } - for (int i = 0; i < uniforms.size(); i++) { - VisualShaderNodeUniform *uniform = uniforms[i]; - if (used_uniform_names.has(uniform->get_uniform_name())) { - global_code += uniform->generate_global(get_mode(), Type(i), -1); - const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true); + for (int i = 0; i < parameters.size(); i++) { + VisualShaderNodeParameter *parameter = parameters[i]; + if (used_parameter_names.has(parameter->get_parameter_name())) { + global_code += parameter->generate_global(get_mode(), Type(i), -1); + const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(true); } else { - const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false); + const_cast<VisualShaderNodeParameter *>(parameter)->set_global_code_generated(false); } } @@ -2520,7 +2520,7 @@ void VisualShader::_update_shader() const { const_cast<VisualShader *>(this)->set_code(final_code); for (int i = 0; i < default_tex_params.size(); i++) { for (int j = 0; j < default_tex_params[i].params.size(); j++) { - const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].params[j], j); + const_cast<VisualShader *>(this)->set_default_texture_parameter(default_tex_params[i].name, default_tex_params[i].params[j], j); } } if (previous_code != final_code) { @@ -3215,20 +3215,20 @@ void VisualShaderNodeInput::_bind_methods() { VisualShaderNodeInput::VisualShaderNodeInput() { } -////////////// UniformRef +////////////// ParameterRef -RBMap<RID, List<VisualShaderNodeUniformRef::Uniform>> uniforms; +RBMap<RID, List<VisualShaderNodeParameterRef::Parameter>> parameters; -void VisualShaderNodeUniformRef::add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type) { - uniforms[p_shader_rid].push_back({ p_name, p_type }); +void VisualShaderNodeParameterRef::add_parameter(RID p_shader_rid, const String &p_name, ParameterType p_type) { + parameters[p_shader_rid].push_back({ p_name, p_type }); } -void VisualShaderNodeUniformRef::clear_uniforms(RID p_shader_rid) { - uniforms[p_shader_rid].clear(); +void VisualShaderNodeParameterRef::clear_parameters(RID p_shader_rid) { + parameters[p_shader_rid].clear(); } -bool VisualShaderNodeUniformRef::has_uniform(RID p_shader_rid, const String &p_name) { - for (const VisualShaderNodeUniformRef::Uniform &E : uniforms[p_shader_rid]) { +bool VisualShaderNodeParameterRef::has_parameter(RID p_shader_rid, const String &p_name) { + for (const VisualShaderNodeParameterRef::Parameter &E : parameters[p_shader_rid]) { if (E.name == p_name) { return true; } @@ -3236,41 +3236,41 @@ bool VisualShaderNodeUniformRef::has_uniform(RID p_shader_rid, const String &p_n return false; } -String VisualShaderNodeUniformRef::get_caption() const { - return "UniformRef"; +String VisualShaderNodeParameterRef::get_caption() const { + return "ParameterRef"; } -int VisualShaderNodeUniformRef::get_input_port_count() const { +int VisualShaderNodeParameterRef::get_input_port_count() const { return 0; } -VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const { +VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_input_port_type(int p_port) const { return PortType::PORT_TYPE_SCALAR; } -String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const { +String VisualShaderNodeParameterRef::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeUniformRef::get_output_port_count() const { - switch (uniform_type) { - case UniformType::UNIFORM_TYPE_FLOAT: +int VisualShaderNodeParameterRef::get_output_port_count() const { + switch (param_type) { + case PARAMETER_TYPE_FLOAT: return 1; - case UniformType::UNIFORM_TYPE_INT: + case PARAMETER_TYPE_INT: return 1; - case UniformType::UNIFORM_TYPE_BOOLEAN: + case PARAMETER_TYPE_BOOLEAN: return 1; - case UniformType::UNIFORM_TYPE_VECTOR2: + case PARAMETER_TYPE_VECTOR2: return 1; - case UniformType::UNIFORM_TYPE_VECTOR3: + case PARAMETER_TYPE_VECTOR3: return 1; - case UniformType::UNIFORM_TYPE_VECTOR4: + case PARAMETER_TYPE_VECTOR4: return 1; - case UniformType::UNIFORM_TYPE_TRANSFORM: + case PARAMETER_TYPE_TRANSFORM: return 1; - case UniformType::UNIFORM_TYPE_COLOR: + case PARAMETER_TYPE_COLOR: return 2; - case UniformType::UNIFORM_TYPE_SAMPLER: + case UNIFORM_TYPE_SAMPLER: return 1; default: break; @@ -3278,30 +3278,30 @@ int VisualShaderNodeUniformRef::get_output_port_count() const { return 1; } -VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const { - switch (uniform_type) { - case UniformType::UNIFORM_TYPE_FLOAT: +VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_output_port_type(int p_port) const { + switch (param_type) { + case PARAMETER_TYPE_FLOAT: return PortType::PORT_TYPE_SCALAR; - case UniformType::UNIFORM_TYPE_INT: + case PARAMETER_TYPE_INT: return PortType::PORT_TYPE_SCALAR_INT; - case UniformType::UNIFORM_TYPE_BOOLEAN: + case PARAMETER_TYPE_BOOLEAN: return PortType::PORT_TYPE_BOOLEAN; - case UniformType::UNIFORM_TYPE_VECTOR2: + case PARAMETER_TYPE_VECTOR2: return PortType::PORT_TYPE_VECTOR_2D; - case UniformType::UNIFORM_TYPE_VECTOR3: + case PARAMETER_TYPE_VECTOR3: return PortType::PORT_TYPE_VECTOR_3D; - case UniformType::UNIFORM_TYPE_VECTOR4: + case PARAMETER_TYPE_VECTOR4: return PortType::PORT_TYPE_VECTOR_4D; - case UniformType::UNIFORM_TYPE_TRANSFORM: + case PARAMETER_TYPE_TRANSFORM: return PortType::PORT_TYPE_TRANSFORM; - case UniformType::UNIFORM_TYPE_COLOR: + case PARAMETER_TYPE_COLOR: if (p_port == 0) { return PortType::PORT_TYPE_VECTOR_3D; } else if (p_port == 1) { return PORT_TYPE_SCALAR; } break; - case UniformType::UNIFORM_TYPE_SAMPLER: + case UNIFORM_TYPE_SAMPLER: return PortType::PORT_TYPE_SAMPLER; default: break; @@ -3309,30 +3309,30 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port return PORT_TYPE_SCALAR; } -String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const { - switch (uniform_type) { - case UniformType::UNIFORM_TYPE_FLOAT: +String VisualShaderNodeParameterRef::get_output_port_name(int p_port) const { + switch (param_type) { + case PARAMETER_TYPE_FLOAT: return ""; - case UniformType::UNIFORM_TYPE_INT: + case PARAMETER_TYPE_INT: return ""; - case UniformType::UNIFORM_TYPE_BOOLEAN: + case PARAMETER_TYPE_BOOLEAN: return ""; - case UniformType::UNIFORM_TYPE_VECTOR2: + case PARAMETER_TYPE_VECTOR2: return ""; - case UniformType::UNIFORM_TYPE_VECTOR3: + case PARAMETER_TYPE_VECTOR3: return ""; - case UniformType::UNIFORM_TYPE_VECTOR4: + case PARAMETER_TYPE_VECTOR4: return ""; - case UniformType::UNIFORM_TYPE_TRANSFORM: + case PARAMETER_TYPE_TRANSFORM: return ""; - case UniformType::UNIFORM_TYPE_COLOR: + case PARAMETER_TYPE_COLOR: if (p_port == 0) { return "rgb"; } else if (p_port == 1) { return "alpha"; } break; - case UniformType::UNIFORM_TYPE_SAMPLER: + case UNIFORM_TYPE_SAMPLER: return ""; break; default: @@ -3341,85 +3341,85 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const { return ""; } -void VisualShaderNodeUniformRef::set_shader_rid(const RID &p_shader_rid) { +void VisualShaderNodeParameterRef::set_shader_rid(const RID &p_shader_rid) { shader_rid = p_shader_rid; } -void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) { - uniform_name = p_name; +void VisualShaderNodeParameterRef::set_parameter_name(const String &p_name) { + parameter_name = p_name; if (shader_rid.is_valid()) { - update_uniform_type(); + update_parameter_type(); } emit_changed(); } -void VisualShaderNodeUniformRef::update_uniform_type() { - if (uniform_name != "[None]") { - uniform_type = get_uniform_type_by_name(uniform_name); +void VisualShaderNodeParameterRef::update_parameter_type() { + if (parameter_name != "[None]") { + param_type = get_parameter_type_by_name(parameter_name); } else { - uniform_type = UniformType::UNIFORM_TYPE_FLOAT; + param_type = PARAMETER_TYPE_FLOAT; } } -String VisualShaderNodeUniformRef::get_uniform_name() const { - return uniform_name; +String VisualShaderNodeParameterRef::get_parameter_name() const { + return parameter_name; } -int VisualShaderNodeUniformRef::get_uniforms_count() const { +int VisualShaderNodeParameterRef::get_parameters_count() const { ERR_FAIL_COND_V(!shader_rid.is_valid(), 0); - return uniforms[shader_rid].size(); + return parameters[shader_rid].size(); } -String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const { +String VisualShaderNodeParameterRef::get_parameter_name_by_index(int p_idx) const { ERR_FAIL_COND_V(!shader_rid.is_valid(), String()); - if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) { - return uniforms[shader_rid][p_idx].name; + if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) { + return parameters[shader_rid][p_idx].name; } return ""; } -VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const { - ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT); +VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_name(const String &p_name) const { + ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT); - for (int i = 0; i < uniforms[shader_rid].size(); i++) { - if (uniforms[shader_rid][i].name == p_name) { - return uniforms[shader_rid][i].type; + for (int i = 0; i < parameters[shader_rid].size(); i++) { + if (parameters[shader_rid][i].name == p_name) { + return parameters[shader_rid][i].type; } } - return UniformType::UNIFORM_TYPE_FLOAT; + return PARAMETER_TYPE_FLOAT; } -VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const { - ERR_FAIL_COND_V(!shader_rid.is_valid(), UNIFORM_TYPE_FLOAT); +VisualShaderNodeParameterRef::ParameterType VisualShaderNodeParameterRef::get_parameter_type_by_index(int p_idx) const { + ERR_FAIL_COND_V(!shader_rid.is_valid(), PARAMETER_TYPE_FLOAT); - if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) { - return uniforms[shader_rid][p_idx].type; + if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) { + return parameters[shader_rid][p_idx].type; } - return UniformType::UNIFORM_TYPE_FLOAT; + return PARAMETER_TYPE_FLOAT; } -VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_by_index(int p_idx) const { +VisualShaderNodeParameterRef::PortType VisualShaderNodeParameterRef::get_port_type_by_index(int p_idx) const { ERR_FAIL_COND_V(!shader_rid.is_valid(), PORT_TYPE_SCALAR); - if (p_idx >= 0 && p_idx < uniforms[shader_rid].size()) { - switch (uniforms[shader_rid][p_idx].type) { - case UniformType::UNIFORM_TYPE_FLOAT: + if (p_idx >= 0 && p_idx < parameters[shader_rid].size()) { + switch (parameters[shader_rid][p_idx].type) { + case PARAMETER_TYPE_FLOAT: return PORT_TYPE_SCALAR; - case UniformType::UNIFORM_TYPE_INT: + case PARAMETER_TYPE_INT: return PORT_TYPE_SCALAR_INT; - case UniformType::UNIFORM_TYPE_SAMPLER: + case UNIFORM_TYPE_SAMPLER: return PORT_TYPE_SAMPLER; - case UniformType::UNIFORM_TYPE_VECTOR2: + case PARAMETER_TYPE_VECTOR2: return PORT_TYPE_VECTOR_2D; - case UniformType::UNIFORM_TYPE_VECTOR3: + case PARAMETER_TYPE_VECTOR3: return PORT_TYPE_VECTOR_3D; - case UniformType::UNIFORM_TYPE_VECTOR4: + case PARAMETER_TYPE_VECTOR4: return PORT_TYPE_VECTOR_4D; - case UniformType::UNIFORM_TYPE_TRANSFORM: + case PARAMETER_TYPE_TRANSFORM: return PORT_TYPE_TRANSFORM; - case UniformType::UNIFORM_TYPE_COLOR: + case PARAMETER_TYPE_COLOR: return PORT_TYPE_VECTOR_3D; default: break; @@ -3428,54 +3428,54 @@ VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_b return PORT_TYPE_SCALAR; } -String VisualShaderNodeUniformRef::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 { - switch (uniform_type) { - case UniformType::UNIFORM_TYPE_FLOAT: - if (uniform_name == "[None]") { +String VisualShaderNodeParameterRef::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 { + switch (param_type) { + case PARAMETER_TYPE_FLOAT: + if (parameter_name == "[None]") { return " " + p_output_vars[0] + " = 0.0;\n"; } break; - case UniformType::UNIFORM_TYPE_COLOR: { - String code = " " + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n"; - code += " " + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n"; + case PARAMETER_TYPE_COLOR: { + String code = " " + p_output_vars[0] + " = " + get_parameter_name() + ".rgb;\n"; + code += " " + p_output_vars[1] + " = " + get_parameter_name() + ".a;\n"; return code; } break; - case UniformType::UNIFORM_TYPE_SAMPLER: + case UNIFORM_TYPE_SAMPLER: return String(); default: break; } - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) { - uniform_type = (UniformType)p_uniform_type; +void VisualShaderNodeParameterRef::_set_parameter_type(int p_type) { + param_type = (ParameterType)p_type; } -int VisualShaderNodeUniformRef::_get_uniform_type() const { - return (int)uniform_type; +int VisualShaderNodeParameterRef::_get_parameter_type() const { + return (int)param_type; } -void VisualShaderNodeUniformRef::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name); - ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name); +void VisualShaderNodeParameterRef::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameterRef::set_parameter_name); + ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameterRef::get_parameter_name); - ClassDB::bind_method(D_METHOD("_set_uniform_type", "type"), &VisualShaderNodeUniformRef::_set_uniform_type); - ClassDB::bind_method(D_METHOD("_get_uniform_type"), &VisualShaderNodeUniformRef::_get_uniform_type); + ClassDB::bind_method(D_METHOD("_set_parameter_type", "type"), &VisualShaderNodeParameterRef::_set_parameter_type); + ClassDB::bind_method(D_METHOD("_get_parameter_type"), &VisualShaderNodeParameterRef::_get_parameter_type); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "uniform_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_uniform_type", "_get_uniform_type"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name", PROPERTY_HINT_ENUM, ""), "set_parameter_name", "get_parameter_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "param_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_parameter_type", "_get_parameter_type"); } -Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const { +Vector<StringName> VisualShaderNodeParameterRef::get_editable_properties() const { Vector<StringName> props; - props.push_back("uniform_name"); - props.push_back("uniform_type"); + props.push_back("parameter_name"); + props.push_back("param_type"); return props; } -VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() { +VisualShaderNodeParameterRef::VisualShaderNodeParameterRef() { } //////////////////////////////////////////// @@ -3687,17 +3687,17 @@ VisualShaderNodeOutput::VisualShaderNodeOutput() { /////////////////////////// -void VisualShaderNodeUniform::set_uniform_name(const String &p_name) { - uniform_name = p_name; +void VisualShaderNodeParameter::set_parameter_name(const String &p_name) { + parameter_name = p_name; emit_signal(SNAME("name_changed")); emit_changed(); } -String VisualShaderNodeUniform::get_uniform_name() const { - return uniform_name; +String VisualShaderNodeParameter::get_parameter_name() const { + return parameter_name; } -void VisualShaderNodeUniform::set_qualifier(VisualShaderNodeUniform::Qualifier p_qual) { +void VisualShaderNodeParameter::set_qualifier(VisualShaderNodeParameter::Qualifier p_qual) { ERR_FAIL_INDEX(int(p_qual), int(QUAL_MAX)); if (qualifier == p_qual) { return; @@ -3706,26 +3706,37 @@ void VisualShaderNodeUniform::set_qualifier(VisualShaderNodeUniform::Qualifier p emit_changed(); } -VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() const { +VisualShaderNodeParameter::Qualifier VisualShaderNodeParameter::get_qualifier() const { return qualifier; } -void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) { +void VisualShaderNodeParameter::set_global_code_generated(bool p_enabled) { global_code_generated = p_enabled; } -bool VisualShaderNodeUniform::is_global_code_generated() const { +bool VisualShaderNodeParameter::is_global_code_generated() const { return global_code_generated; } -void VisualShaderNodeUniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name); - ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name); +#ifndef DISABLE_DEPRECATED +// Kept for compatibility from 3.x to 4.0. +bool VisualShaderNodeParameter::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "uniform_name") { + set_parameter_name(p_value); + return true; + } + return false; +} +#endif + +void VisualShaderNodeParameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_parameter_name", "name"), &VisualShaderNodeParameter::set_parameter_name); + ClassDB::bind_method(D_METHOD("get_parameter_name"), &VisualShaderNodeParameter::get_parameter_name); - ClassDB::bind_method(D_METHOD("set_qualifier", "qualifier"), &VisualShaderNodeUniform::set_qualifier); - ClassDB::bind_method(D_METHOD("get_qualifier"), &VisualShaderNodeUniform::get_qualifier); + ClassDB::bind_method(D_METHOD("set_qualifier", "qualifier"), &VisualShaderNodeParameter::set_qualifier); + ClassDB::bind_method(D_METHOD("get_qualifier"), &VisualShaderNodeParameter::get_qualifier); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name"), "set_uniform_name", "get_uniform_name"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "parameter_name"), "set_parameter_name", "get_parameter_name"); ADD_PROPERTY(PropertyInfo(Variant::INT, "qualifier", PROPERTY_HINT_ENUM, "None,Global,Instance"), "set_qualifier", "get_qualifier"); BIND_ENUM_CONSTANT(QUAL_NONE); @@ -3734,7 +3745,7 @@ void VisualShaderNodeUniform::_bind_methods() { BIND_ENUM_CONSTANT(QUAL_MAX); } -String VisualShaderNodeUniform::_get_qual_str() const { +String VisualShaderNodeParameter::_get_qual_str() const { if (is_qualifier_supported(qualifier)) { switch (qualifier) { case QUAL_NONE: @@ -3750,11 +3761,11 @@ String VisualShaderNodeUniform::_get_qual_str() const { return String(); } -String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { +String VisualShaderNodeParameter::get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const { List<String> keyword_list; ShaderLanguage::get_keyword_list(&keyword_list); - if (keyword_list.find(uniform_name)) { - return RTR("Shader keywords cannot be used as uniform names.\nChoose another name."); + if (keyword_list.find(parameter_name)) { + return RTR("Shader keywords cannot be used as parameter names.\nChoose another name."); } if (!is_qualifier_supported(qualifier)) { String qualifier_str; @@ -3770,66 +3781,66 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T default: break; } - return vformat(RTR("This uniform type does not support the '%s' qualifier."), qualifier_str); + return vformat(RTR("This parameter type does not support the '%s' qualifier."), qualifier_str); } else if (qualifier == Qualifier::QUAL_GLOBAL) { - RS::GlobalShaderUniformType gvt = RS::get_singleton()->global_shader_uniform_get_type(uniform_name); + RS::GlobalShaderParameterType gvt = RS::get_singleton()->global_shader_parameter_get_type(parameter_name); if (gvt == RS::GLOBAL_VAR_TYPE_MAX) { - return vformat(RTR("Global uniform '%s' does not exist.\nCreate it in the Project Settings."), uniform_name); + return vformat(RTR("Global parameter '%s' does not exist.\nCreate it in the Project Settings."), parameter_name); } bool incompatible_type = false; switch (gvt) { case RS::GLOBAL_VAR_TYPE_FLOAT: { - if (!Object::cast_to<VisualShaderNodeFloatUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeFloatParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_INT: { - if (!Object::cast_to<VisualShaderNodeIntUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeIntParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_BOOL: { - if (!Object::cast_to<VisualShaderNodeBooleanUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeBooleanParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_COLOR: { - if (!Object::cast_to<VisualShaderNodeColorUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeColorParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_VEC3: { - if (!Object::cast_to<VisualShaderNodeVec3Uniform>(this)) { + if (!Object::cast_to<VisualShaderNodeVec3Parameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_VEC4: { - if (!Object::cast_to<VisualShaderNodeVec4Uniform>(this)) { + if (!Object::cast_to<VisualShaderNodeVec4Parameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM: { - if (!Object::cast_to<VisualShaderNodeTransformUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeTransformParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_SAMPLER2D: { - if (!Object::cast_to<VisualShaderNodeTextureUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeTextureParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_SAMPLER3D: { - if (!Object::cast_to<VisualShaderNodeTexture3DUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeTexture3DParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_SAMPLER2DARRAY: { - if (!Object::cast_to<VisualShaderNodeTexture2DArrayUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeTexture2DArrayParameter>(this)) { incompatible_type = true; } } break; case RS::GLOBAL_VAR_TYPE_SAMPLERCUBE: { - if (!Object::cast_to<VisualShaderNodeCubemapUniform>(this)) { + if (!Object::cast_to<VisualShaderNodeCubemapParameter>(this)) { incompatible_type = true; } } break; @@ -3837,29 +3848,29 @@ String VisualShaderNodeUniform::get_warning(Shader::Mode p_mode, VisualShader::T break; } if (incompatible_type) { - return vformat(RTR("Global uniform '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), uniform_name); + return vformat(RTR("Global parameter '%s' has an incompatible type for this kind of node.\nChange it in the Project Settings."), parameter_name); } } return String(); } -Vector<StringName> VisualShaderNodeUniform::get_editable_properties() const { +Vector<StringName> VisualShaderNodeParameter::get_editable_properties() const { Vector<StringName> props; props.push_back("qualifier"); return props; } -VisualShaderNodeUniform::VisualShaderNodeUniform() { +VisualShaderNodeParameter::VisualShaderNodeParameter() { } ////////////// ResizeableBase -void VisualShaderNodeResizableBase::set_size(const Vector2 &p_size) { +void VisualShaderNodeResizableBase::set_size(const Size2 &p_size) { size = p_size; } -Vector2 VisualShaderNodeResizableBase::get_size() const { +Size2 VisualShaderNodeResizableBase::get_size() const { return size; } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 09a3917a16..4116eaa196 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -36,7 +36,7 @@ #include "scene/gui/control.h" #include "scene/resources/shader.h" -class VisualShaderNodeUniform; +class VisualShaderNodeParameter; class VisualShaderNode; class VisualShader : public Shader { @@ -229,7 +229,7 @@ public: // internal methods String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const; String validate_port_name(const String &p_port_name, VisualShaderNode *p_node, int p_port_id, bool p_output) const; - String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const; + String validate_parameter_name(const String &p_name, const Ref<VisualShaderNodeParameter> &p_parameter) const; VisualShader(); }; @@ -499,8 +499,8 @@ public: VisualShaderNodeOutput(); }; -class VisualShaderNodeUniform : public VisualShaderNode { - GDCLASS(VisualShaderNodeUniform, VisualShaderNode); +class VisualShaderNodeParameter : public VisualShaderNode { + GDCLASS(VisualShaderNodeParameter, VisualShaderNode); public: enum Qualifier { @@ -511,7 +511,7 @@ public: }; private: - String uniform_name = ""; + String parameter_name = ""; Qualifier qualifier = QUAL_NONE; bool global_code_generated = false; @@ -519,9 +519,13 @@ protected: static void _bind_methods(); String _get_qual_str() const; +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); +#endif + public: - void set_uniform_name(const String &p_name); - String get_uniform_name() const; + void set_parameter_name(const String &p_name); + String get_parameter_name() const; void set_qualifier(Qualifier p_qual); Qualifier get_qualifier() const; @@ -535,44 +539,44 @@ public: virtual Vector<StringName> get_editable_properties() const override; virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const override; - VisualShaderNodeUniform(); + VisualShaderNodeParameter(); }; -VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier) +VARIANT_ENUM_CAST(VisualShaderNodeParameter::Qualifier) -class VisualShaderNodeUniformRef : public VisualShaderNode { - GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode); +class VisualShaderNodeParameterRef : public VisualShaderNode { + GDCLASS(VisualShaderNodeParameterRef, VisualShaderNode); public: - enum UniformType { - UNIFORM_TYPE_FLOAT, - UNIFORM_TYPE_INT, - UNIFORM_TYPE_BOOLEAN, - UNIFORM_TYPE_VECTOR2, - UNIFORM_TYPE_VECTOR3, - UNIFORM_TYPE_VECTOR4, - UNIFORM_TYPE_TRANSFORM, - UNIFORM_TYPE_COLOR, + enum ParameterType { + PARAMETER_TYPE_FLOAT, + PARAMETER_TYPE_INT, + PARAMETER_TYPE_BOOLEAN, + PARAMETER_TYPE_VECTOR2, + PARAMETER_TYPE_VECTOR3, + PARAMETER_TYPE_VECTOR4, + PARAMETER_TYPE_TRANSFORM, + PARAMETER_TYPE_COLOR, UNIFORM_TYPE_SAMPLER, }; - struct Uniform { + struct Parameter { String name; - UniformType type; + ParameterType type; }; private: RID shader_rid; - String uniform_name = "[None]"; - UniformType uniform_type = UniformType::UNIFORM_TYPE_FLOAT; + String parameter_name = "[None]"; + ParameterType param_type = ParameterType::PARAMETER_TYPE_FLOAT; protected: static void _bind_methods(); public: - static void add_uniform(RID p_shader_rid, const String &p_name, UniformType p_type); - static void clear_uniforms(RID p_shader_rid); - static bool has_uniform(RID p_shader_rid, const String &p_name); + static void add_parameter(RID p_shader_rid, const String &p_name, ParameterType p_type); + static void clear_parameters(RID p_shader_rid); + static bool has_parameter(RID p_shader_rid, const String &p_name); public: virtual String get_caption() const override; @@ -587,40 +591,40 @@ public: void set_shader_rid(const RID &p_shader); - void set_uniform_name(const String &p_name); - String get_uniform_name() const; + void set_parameter_name(const String &p_name); + String get_parameter_name() const; - void update_uniform_type(); + void update_parameter_type(); - void _set_uniform_type(int p_uniform_type); - int _get_uniform_type() const; + void _set_parameter_type(int p_parameter_type); + int _get_parameter_type() const; - int get_uniforms_count() const; - String get_uniform_name_by_index(int p_idx) const; - UniformType get_uniform_type_by_name(const String &p_name) const; - UniformType get_uniform_type_by_index(int p_idx) const; + int get_parameters_count() const; + String get_parameter_name_by_index(int p_idx) const; + ParameterType get_parameter_type_by_name(const String &p_name) const; + ParameterType get_parameter_type_by_index(int p_idx) const; PortType get_port_type_by_index(int p_idx) const; virtual Vector<StringName> get_editable_properties() 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; - VisualShaderNodeUniformRef(); + VisualShaderNodeParameterRef(); }; class VisualShaderNodeResizableBase : public VisualShaderNode { GDCLASS(VisualShaderNodeResizableBase, VisualShaderNode); protected: - Vector2 size = Size2(0, 0); + Size2 size = Size2(0, 0); bool allow_v_resize = true; protected: static void _bind_methods(); public: - void set_size(const Vector2 &p_size); - Vector2 get_size() const; + void set_size(const Size2 &p_size); + Size2 get_size() const; bool is_allow_v_resize() const; void set_allow_v_resize(bool p_enabled); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 3b2b58516d..de13912b75 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -1636,10 +1636,14 @@ String VisualShaderNodeLinearSceneDepth::get_output_port_name(int p_port) const return "linear depth"; } +bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const { + return false; +} + String VisualShaderNodeLinearSceneDepth::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; - code += " float _log_depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;\n"; + code += " float _log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n"; code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n"; code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n"; code += " _depth_view.xyz /= _depth_view.w;"; @@ -4712,44 +4716,44 @@ VisualShaderNodeTransformDecompose::VisualShaderNodeTransformDecompose() { set_input_port_default_value(0, Transform3D()); } -////////////// Float Uniform +////////////// Float Parameter -String VisualShaderNodeFloatUniform::get_caption() const { - return "FloatUniform"; +String VisualShaderNodeFloatParameter::get_caption() const { + return "FloatParameter"; } -int VisualShaderNodeFloatUniform::get_input_port_count() const { +int VisualShaderNodeFloatParameter::get_input_port_count() const { return 0; } -VisualShaderNodeFloatUniform::PortType VisualShaderNodeFloatUniform::get_input_port_type(int p_port) const { +VisualShaderNodeFloatParameter::PortType VisualShaderNodeFloatParameter::get_input_port_type(int p_port) const { return PORT_TYPE_SCALAR; } -String VisualShaderNodeFloatUniform::get_input_port_name(int p_port) const { +String VisualShaderNodeFloatParameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeFloatUniform::get_output_port_count() const { +int VisualShaderNodeFloatParameter::get_output_port_count() const { return 1; } -VisualShaderNodeFloatUniform::PortType VisualShaderNodeFloatUniform::get_output_port_type(int p_port) const { +VisualShaderNodeFloatParameter::PortType VisualShaderNodeFloatParameter::get_output_port_type(int p_port) const { return PORT_TYPE_SCALAR; } -String VisualShaderNodeFloatUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeFloatParameter::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { +String VisualShaderNodeFloatParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = ""; if (hint == HINT_RANGE) { - code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")"; + code += _get_qual_str() + "uniform float " + get_parameter_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ")"; } else if (hint == HINT_RANGE_STEP) { - code += _get_qual_str() + "uniform float " + get_uniform_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")"; + code += _get_qual_str() + "uniform float " + get_parameter_name() + " : hint_range(" + rtos(hint_range_min) + ", " + rtos(hint_range_max) + ", " + rtos(hint_range_step) + ")"; } else { - code += _get_qual_str() + "uniform float " + get_uniform_name(); + code += _get_qual_str() + "uniform float " + get_parameter_name(); } if (default_value_enabled) { code += " = " + rtos(default_value); @@ -4758,19 +4762,19 @@ String VisualShaderNodeFloatUniform::generate_global(Shader::Mode p_mode, Visual return code; } -String VisualShaderNodeFloatUniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeFloatParameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -bool VisualShaderNodeFloatUniform::is_show_prop_names() const { +bool VisualShaderNodeFloatParameter::is_show_prop_names() const { return true; } -bool VisualShaderNodeFloatUniform::is_use_prop_slots() const { +bool VisualShaderNodeFloatParameter::is_use_prop_slots() const { return true; } -void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) { +void VisualShaderNodeFloatParameter::set_hint(Hint p_hint) { ERR_FAIL_INDEX(int(p_hint), int(HINT_MAX)); if (hint == p_hint) { return; @@ -4779,11 +4783,11 @@ void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) { emit_changed(); } -VisualShaderNodeFloatUniform::Hint VisualShaderNodeFloatUniform::get_hint() const { +VisualShaderNodeFloatParameter::Hint VisualShaderNodeFloatParameter::get_hint() const { return hint; } -void VisualShaderNodeFloatUniform::set_min(float p_value) { +void VisualShaderNodeFloatParameter::set_min(float p_value) { if (Math::is_equal_approx(hint_range_min, p_value)) { return; } @@ -4791,11 +4795,11 @@ void VisualShaderNodeFloatUniform::set_min(float p_value) { emit_changed(); } -float VisualShaderNodeFloatUniform::get_min() const { +float VisualShaderNodeFloatParameter::get_min() const { return hint_range_min; } -void VisualShaderNodeFloatUniform::set_max(float p_value) { +void VisualShaderNodeFloatParameter::set_max(float p_value) { if (Math::is_equal_approx(hint_range_max, p_value)) { return; } @@ -4803,11 +4807,11 @@ void VisualShaderNodeFloatUniform::set_max(float p_value) { emit_changed(); } -float VisualShaderNodeFloatUniform::get_max() const { +float VisualShaderNodeFloatParameter::get_max() const { return hint_range_max; } -void VisualShaderNodeFloatUniform::set_step(float p_value) { +void VisualShaderNodeFloatParameter::set_step(float p_value) { if (Math::is_equal_approx(hint_range_step, p_value)) { return; } @@ -4815,11 +4819,11 @@ void VisualShaderNodeFloatUniform::set_step(float p_value) { emit_changed(); } -float VisualShaderNodeFloatUniform::get_step() const { +float VisualShaderNodeFloatParameter::get_step() const { return hint_range_step; } -void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) { +void VisualShaderNodeFloatParameter::set_default_value_enabled(bool p_enabled) { if (default_value_enabled == p_enabled) { return; } @@ -4827,11 +4831,11 @@ void VisualShaderNodeFloatUniform::set_default_value_enabled(bool p_enabled) { emit_changed(); } -bool VisualShaderNodeFloatUniform::is_default_value_enabled() const { +bool VisualShaderNodeFloatParameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeFloatUniform::set_default_value(float p_value) { +void VisualShaderNodeFloatParameter::set_default_value(float p_value) { if (Math::is_equal_approx(default_value, p_value)) { return; } @@ -4839,28 +4843,28 @@ void VisualShaderNodeFloatUniform::set_default_value(float p_value) { emit_changed(); } -float VisualShaderNodeFloatUniform::get_default_value() const { +float VisualShaderNodeFloatParameter::get_default_value() const { return default_value; } -void VisualShaderNodeFloatUniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatUniform::set_hint); - ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatUniform::get_hint); +void VisualShaderNodeFloatParameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeFloatParameter::set_hint); + ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeFloatParameter::get_hint); - ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeFloatUniform::set_min); - ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeFloatUniform::get_min); + ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeFloatParameter::set_min); + ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeFloatParameter::get_min); - ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeFloatUniform::set_max); - ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeFloatUniform::get_max); + ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeFloatParameter::set_max); + ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeFloatParameter::get_max); - ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatUniform::set_step); - ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatUniform::get_step); + ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeFloatParameter::set_step); + ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeFloatParameter::get_step); - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatUniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatUniform::is_default_value_enabled); + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeFloatParameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeFloatParameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatUniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatUniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeFloatParameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeFloatParameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range+Step"), "set_hint", "get_hint"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min"), "set_min", "get_min"); @@ -4875,16 +4879,16 @@ void VisualShaderNodeFloatUniform::_bind_methods() { BIND_ENUM_CONSTANT(HINT_MAX); } -bool VisualShaderNodeFloatUniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeFloatParameter::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } -bool VisualShaderNodeFloatUniform::is_convertible_to_constant() const { +bool VisualShaderNodeFloatParameter::is_convertible_to_constant() const { return true; // conversion is allowed } -Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeFloatParameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("hint"); if (hint == HINT_RANGE || hint == HINT_RANGE_STEP) { props.push_back("min"); @@ -4900,47 +4904,47 @@ Vector<StringName> VisualShaderNodeFloatUniform::get_editable_properties() const return props; } -VisualShaderNodeFloatUniform::VisualShaderNodeFloatUniform() { +VisualShaderNodeFloatParameter::VisualShaderNodeFloatParameter() { } -////////////// Integer Uniform +////////////// Integer Parametet -String VisualShaderNodeIntUniform::get_caption() const { - return "IntUniform"; +String VisualShaderNodeIntParameter::get_caption() const { + return "IntParameter"; } -int VisualShaderNodeIntUniform::get_input_port_count() const { +int VisualShaderNodeIntParameter::get_input_port_count() const { return 0; } -VisualShaderNodeIntUniform::PortType VisualShaderNodeIntUniform::get_input_port_type(int p_port) const { +VisualShaderNodeIntParameter::PortType VisualShaderNodeIntParameter::get_input_port_type(int p_port) const { return PORT_TYPE_SCALAR_INT; } -String VisualShaderNodeIntUniform::get_input_port_name(int p_port) const { +String VisualShaderNodeIntParameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeIntUniform::get_output_port_count() const { +int VisualShaderNodeIntParameter::get_output_port_count() const { return 1; } -VisualShaderNodeIntUniform::PortType VisualShaderNodeIntUniform::get_output_port_type(int p_port) const { +VisualShaderNodeIntParameter::PortType VisualShaderNodeIntParameter::get_output_port_type(int p_port) const { return PORT_TYPE_SCALAR_INT; } -String VisualShaderNodeIntUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeIntParameter::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { +String VisualShaderNodeIntParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code = ""; if (hint == HINT_RANGE) { - code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")"; + code += _get_qual_str() + "uniform int " + get_parameter_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ")"; } else if (hint == HINT_RANGE_STEP) { - code += _get_qual_str() + "uniform int " + get_uniform_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")"; + code += _get_qual_str() + "uniform int " + get_parameter_name() + " : hint_range(" + itos(hint_range_min) + ", " + itos(hint_range_max) + ", " + itos(hint_range_step) + ")"; } else { - code += _get_qual_str() + "uniform int " + get_uniform_name(); + code += _get_qual_str() + "uniform int " + get_parameter_name(); } if (default_value_enabled) { code += " = " + itos(default_value); @@ -4949,19 +4953,19 @@ String VisualShaderNodeIntUniform::generate_global(Shader::Mode p_mode, VisualSh return code; } -String VisualShaderNodeIntUniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeIntParameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -bool VisualShaderNodeIntUniform::is_show_prop_names() const { +bool VisualShaderNodeIntParameter::is_show_prop_names() const { return true; } -bool VisualShaderNodeIntUniform::is_use_prop_slots() const { +bool VisualShaderNodeIntParameter::is_use_prop_slots() const { return true; } -void VisualShaderNodeIntUniform::set_hint(Hint p_hint) { +void VisualShaderNodeIntParameter::set_hint(Hint p_hint) { ERR_FAIL_INDEX(int(p_hint), int(HINT_MAX)); if (hint == p_hint) { return; @@ -4970,11 +4974,11 @@ void VisualShaderNodeIntUniform::set_hint(Hint p_hint) { emit_changed(); } -VisualShaderNodeIntUniform::Hint VisualShaderNodeIntUniform::get_hint() const { +VisualShaderNodeIntParameter::Hint VisualShaderNodeIntParameter::get_hint() const { return hint; } -void VisualShaderNodeIntUniform::set_min(int p_value) { +void VisualShaderNodeIntParameter::set_min(int p_value) { if (hint_range_min == p_value) { return; } @@ -4982,11 +4986,11 @@ void VisualShaderNodeIntUniform::set_min(int p_value) { emit_changed(); } -int VisualShaderNodeIntUniform::get_min() const { +int VisualShaderNodeIntParameter::get_min() const { return hint_range_min; } -void VisualShaderNodeIntUniform::set_max(int p_value) { +void VisualShaderNodeIntParameter::set_max(int p_value) { if (hint_range_max == p_value) { return; } @@ -4994,11 +4998,11 @@ void VisualShaderNodeIntUniform::set_max(int p_value) { emit_changed(); } -int VisualShaderNodeIntUniform::get_max() const { +int VisualShaderNodeIntParameter::get_max() const { return hint_range_max; } -void VisualShaderNodeIntUniform::set_step(int p_value) { +void VisualShaderNodeIntParameter::set_step(int p_value) { if (hint_range_step == p_value) { return; } @@ -5006,11 +5010,11 @@ void VisualShaderNodeIntUniform::set_step(int p_value) { emit_changed(); } -int VisualShaderNodeIntUniform::get_step() const { +int VisualShaderNodeIntParameter::get_step() const { return hint_range_step; } -void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_default_value_enabled) { +void VisualShaderNodeIntParameter::set_default_value_enabled(bool p_default_value_enabled) { if (default_value_enabled == p_default_value_enabled) { return; } @@ -5018,11 +5022,11 @@ void VisualShaderNodeIntUniform::set_default_value_enabled(bool p_default_value_ emit_changed(); } -bool VisualShaderNodeIntUniform::is_default_value_enabled() const { +bool VisualShaderNodeIntParameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeIntUniform::set_default_value(int p_default_value) { +void VisualShaderNodeIntParameter::set_default_value(int p_default_value) { if (default_value == p_default_value) { return; } @@ -5030,28 +5034,28 @@ void VisualShaderNodeIntUniform::set_default_value(int p_default_value) { emit_changed(); } -int VisualShaderNodeIntUniform::get_default_value() const { +int VisualShaderNodeIntParameter::get_default_value() const { return default_value; } -void VisualShaderNodeIntUniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntUniform::set_hint); - ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntUniform::get_hint); +void VisualShaderNodeIntParameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_hint", "hint"), &VisualShaderNodeIntParameter::set_hint); + ClassDB::bind_method(D_METHOD("get_hint"), &VisualShaderNodeIntParameter::get_hint); - ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeIntUniform::set_min); - ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeIntUniform::get_min); + ClassDB::bind_method(D_METHOD("set_min", "value"), &VisualShaderNodeIntParameter::set_min); + ClassDB::bind_method(D_METHOD("get_min"), &VisualShaderNodeIntParameter::get_min); - ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeIntUniform::set_max); - ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeIntUniform::get_max); + ClassDB::bind_method(D_METHOD("set_max", "value"), &VisualShaderNodeIntParameter::set_max); + ClassDB::bind_method(D_METHOD("get_max"), &VisualShaderNodeIntParameter::get_max); - ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntUniform::set_step); - ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntUniform::get_step); + ClassDB::bind_method(D_METHOD("set_step", "value"), &VisualShaderNodeIntParameter::set_step); + ClassDB::bind_method(D_METHOD("get_step"), &VisualShaderNodeIntParameter::get_step); - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntUniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntUniform::is_default_value_enabled); + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeIntParameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeIntParameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntUniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntUniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeIntParameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeIntParameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,Range + Step"), "set_hint", "get_hint"); ADD_PROPERTY(PropertyInfo(Variant::INT, "min"), "set_min", "get_min"); @@ -5066,16 +5070,16 @@ void VisualShaderNodeIntUniform::_bind_methods() { BIND_ENUM_CONSTANT(HINT_MAX); } -bool VisualShaderNodeIntUniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeIntParameter::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } -bool VisualShaderNodeIntUniform::is_convertible_to_constant() const { +bool VisualShaderNodeIntParameter::is_convertible_to_constant() const { return true; // conversion is allowed } -Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeIntParameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("hint"); if (hint == HINT_RANGE || hint == HINT_RANGE_STEP) { props.push_back("min"); @@ -5091,40 +5095,40 @@ Vector<StringName> VisualShaderNodeIntUniform::get_editable_properties() const { return props; } -VisualShaderNodeIntUniform::VisualShaderNodeIntUniform() { +VisualShaderNodeIntParameter::VisualShaderNodeIntParameter() { } -////////////// Boolean Uniform +////////////// Boolean Parameter -String VisualShaderNodeBooleanUniform::get_caption() const { - return "BooleanUniform"; +String VisualShaderNodeBooleanParameter::get_caption() const { + return "BooleanParameter"; } -int VisualShaderNodeBooleanUniform::get_input_port_count() const { +int VisualShaderNodeBooleanParameter::get_input_port_count() const { return 0; } -VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_input_port_type(int p_port) const { +VisualShaderNodeBooleanParameter::PortType VisualShaderNodeBooleanParameter::get_input_port_type(int p_port) const { return PORT_TYPE_BOOLEAN; } -String VisualShaderNodeBooleanUniform::get_input_port_name(int p_port) const { +String VisualShaderNodeBooleanParameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeBooleanUniform::get_output_port_count() const { +int VisualShaderNodeBooleanParameter::get_output_port_count() const { return 1; } -VisualShaderNodeBooleanUniform::PortType VisualShaderNodeBooleanUniform::get_output_port_type(int p_port) const { +VisualShaderNodeBooleanParameter::PortType VisualShaderNodeBooleanParameter::get_output_port_type(int p_port) const { return PORT_TYPE_BOOLEAN; } -String VisualShaderNodeBooleanUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeBooleanParameter::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_default_value_enabled) { +void VisualShaderNodeBooleanParameter::set_default_value_enabled(bool p_default_value_enabled) { if (default_value_enabled == p_default_value_enabled) { return; } @@ -5132,11 +5136,11 @@ void VisualShaderNodeBooleanUniform::set_default_value_enabled(bool p_default_va emit_changed(); } -bool VisualShaderNodeBooleanUniform::is_default_value_enabled() const { +bool VisualShaderNodeBooleanParameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeBooleanUniform::set_default_value(bool p_default_value) { +void VisualShaderNodeBooleanParameter::set_default_value(bool p_default_value) { if (default_value == p_default_value) { return; } @@ -5144,12 +5148,12 @@ void VisualShaderNodeBooleanUniform::set_default_value(bool p_default_value) { emit_changed(); } -bool VisualShaderNodeBooleanUniform::get_default_value() const { +bool VisualShaderNodeBooleanParameter::get_default_value() const { return default_value; } -String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform bool " + get_uniform_name(); +String VisualShaderNodeBooleanParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform bool " + get_parameter_name(); if (default_value_enabled) { if (default_value) { code += " = true"; @@ -5161,39 +5165,39 @@ String VisualShaderNodeBooleanUniform::generate_global(Shader::Mode p_mode, Visu return code; } -String VisualShaderNodeBooleanUniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeBooleanParameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -bool VisualShaderNodeBooleanUniform::is_show_prop_names() const { +bool VisualShaderNodeBooleanParameter::is_show_prop_names() const { return true; } -bool VisualShaderNodeBooleanUniform::is_use_prop_slots() const { +bool VisualShaderNodeBooleanParameter::is_use_prop_slots() const { return true; } -void VisualShaderNodeBooleanUniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled); +void VisualShaderNodeBooleanParameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanParameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanParameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanUniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanUniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeBooleanParameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeBooleanParameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value"), "set_default_value", "get_default_value"); } -bool VisualShaderNodeBooleanUniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeBooleanParameter::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } -bool VisualShaderNodeBooleanUniform::is_convertible_to_constant() const { +bool VisualShaderNodeBooleanParameter::is_convertible_to_constant() const { return true; // conversion is allowed } -Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeBooleanParameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("default_value_enabled"); if (default_value_enabled) { props.push_back("default_value"); @@ -5201,47 +5205,47 @@ Vector<StringName> VisualShaderNodeBooleanUniform::get_editable_properties() con return props; } -VisualShaderNodeBooleanUniform::VisualShaderNodeBooleanUniform() { +VisualShaderNodeBooleanParameter::VisualShaderNodeBooleanParameter() { } -////////////// Color Uniform +////////////// Color Parameter -String VisualShaderNodeColorUniform::get_caption() const { - return "ColorUniform"; +String VisualShaderNodeColorParameter::get_caption() const { + return "ColorParameter"; } -int VisualShaderNodeColorUniform::get_input_port_count() const { +int VisualShaderNodeColorParameter::get_input_port_count() const { return 0; } -VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_input_port_type(int p_port) const { +VisualShaderNodeColorParameter::PortType VisualShaderNodeColorParameter::get_input_port_type(int p_port) const { return PORT_TYPE_SCALAR; } -String VisualShaderNodeColorUniform::get_input_port_name(int p_port) const { +String VisualShaderNodeColorParameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeColorUniform::get_output_port_count() const { +int VisualShaderNodeColorParameter::get_output_port_count() const { return 1; } -VisualShaderNodeColorUniform::PortType VisualShaderNodeColorUniform::get_output_port_type(int p_port) const { +VisualShaderNodeColorParameter::PortType VisualShaderNodeColorParameter::get_output_port_type(int p_port) const { return p_port == 0 ? PORT_TYPE_VECTOR_4D : PORT_TYPE_SCALAR; } -String VisualShaderNodeColorUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeColorParameter::get_output_port_name(int p_port) const { return "color"; } -bool VisualShaderNodeColorUniform::is_output_port_expandable(int p_port) const { +bool VisualShaderNodeColorParameter::is_output_port_expandable(int p_port) const { if (p_port == 0) { return true; } return false; } -void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) { +void VisualShaderNodeColorParameter::set_default_value_enabled(bool p_enabled) { if (default_value_enabled == p_enabled) { return; } @@ -5249,11 +5253,11 @@ void VisualShaderNodeColorUniform::set_default_value_enabled(bool p_enabled) { emit_changed(); } -bool VisualShaderNodeColorUniform::is_default_value_enabled() const { +bool VisualShaderNodeColorParameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) { +void VisualShaderNodeColorParameter::set_default_value(const Color &p_value) { if (default_value.is_equal_approx(p_value)) { return; } @@ -5261,12 +5265,12 @@ void VisualShaderNodeColorUniform::set_default_value(const Color &p_value) { emit_changed(); } -Color VisualShaderNodeColorUniform::get_default_value() const { +Color VisualShaderNodeColorParameter::get_default_value() const { return default_value; } -String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform vec4 " + get_uniform_name() + " : source_color"; +String VisualShaderNodeColorParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform vec4 " + get_parameter_name() + " : source_color"; if (default_value_enabled) { code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.r, default_value.g, default_value.b, default_value.a); } @@ -5274,35 +5278,35 @@ String VisualShaderNodeColorUniform::generate_global(Shader::Mode p_mode, Visual return code; } -String VisualShaderNodeColorUniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeColorParameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -bool VisualShaderNodeColorUniform::is_show_prop_names() const { +bool VisualShaderNodeColorParameter::is_show_prop_names() const { return true; } -void VisualShaderNodeColorUniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled); +void VisualShaderNodeColorParameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorParameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorParameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorUniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorUniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeColorParameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeColorParameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_value"), "set_default_value", "get_default_value"); } -bool VisualShaderNodeColorUniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeColorParameter::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } -bool VisualShaderNodeColorUniform::is_convertible_to_constant() const { +bool VisualShaderNodeColorParameter::is_convertible_to_constant() const { return true; // conversion is allowed } -Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeColorParameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("default_value_enabled"); if (default_value_enabled) { props.push_back("default_value"); @@ -5310,59 +5314,59 @@ Vector<StringName> VisualShaderNodeColorUniform::get_editable_properties() const return props; } -VisualShaderNodeColorUniform::VisualShaderNodeColorUniform() { +VisualShaderNodeColorParameter::VisualShaderNodeColorParameter() { } -////////////// Vector2 Uniform +////////////// Vector2 Parameter -String VisualShaderNodeVec2Uniform::get_caption() const { - return "Vector2Uniform"; +String VisualShaderNodeVec2Parameter::get_caption() const { + return "Vector2Parameter"; } -int VisualShaderNodeVec2Uniform::get_input_port_count() const { +int VisualShaderNodeVec2Parameter::get_input_port_count() const { return 0; } -VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_input_port_type(int p_port) const { +VisualShaderNodeVec2Parameter::PortType VisualShaderNodeVec2Parameter::get_input_port_type(int p_port) const { return PORT_TYPE_VECTOR_2D; } -String VisualShaderNodeVec2Uniform::get_input_port_name(int p_port) const { +String VisualShaderNodeVec2Parameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeVec2Uniform::get_output_port_count() const { +int VisualShaderNodeVec2Parameter::get_output_port_count() const { return 1; } -VisualShaderNodeVec2Uniform::PortType VisualShaderNodeVec2Uniform::get_output_port_type(int p_port) const { +VisualShaderNodeVec2Parameter::PortType VisualShaderNodeVec2Parameter::get_output_port_type(int p_port) const { return PORT_TYPE_VECTOR_2D; } -String VisualShaderNodeVec2Uniform::get_output_port_name(int p_port) const { +String VisualShaderNodeVec2Parameter::get_output_port_name(int p_port) const { return String(); } -void VisualShaderNodeVec2Uniform::set_default_value_enabled(bool p_enabled) { +void VisualShaderNodeVec2Parameter::set_default_value_enabled(bool p_enabled) { default_value_enabled = p_enabled; emit_changed(); } -bool VisualShaderNodeVec2Uniform::is_default_value_enabled() const { +bool VisualShaderNodeVec2Parameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeVec2Uniform::set_default_value(const Vector2 &p_value) { +void VisualShaderNodeVec2Parameter::set_default_value(const Vector2 &p_value) { default_value = p_value; emit_changed(); } -Vector2 VisualShaderNodeVec2Uniform::get_default_value() const { +Vector2 VisualShaderNodeVec2Parameter::get_default_value() const { return default_value; } -String VisualShaderNodeVec2Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform vec2 " + get_uniform_name(); +String VisualShaderNodeVec2Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform vec2 " + get_parameter_name(); if (default_value_enabled) { code += vformat(" = vec2(%.6f, %.6f)", default_value.x, default_value.y); } @@ -5370,39 +5374,39 @@ String VisualShaderNodeVec2Uniform::generate_global(Shader::Mode p_mode, VisualS return code; } -String VisualShaderNodeVec2Uniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeVec2Parameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -void VisualShaderNodeVec2Uniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec2Uniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec2Uniform::is_default_value_enabled); +void VisualShaderNodeVec2Parameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec2Parameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec2Parameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec2Uniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec2Uniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec2Parameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec2Parameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "default_value"), "set_default_value", "get_default_value"); } -bool VisualShaderNodeVec2Uniform::is_show_prop_names() const { +bool VisualShaderNodeVec2Parameter::is_show_prop_names() const { return true; } -bool VisualShaderNodeVec2Uniform::is_use_prop_slots() const { +bool VisualShaderNodeVec2Parameter::is_use_prop_slots() const { return true; } -bool VisualShaderNodeVec2Uniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeVec2Parameter::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } -bool VisualShaderNodeVec2Uniform::is_convertible_to_constant() const { +bool VisualShaderNodeVec2Parameter::is_convertible_to_constant() const { return true; // conversion is allowed } -Vector<StringName> VisualShaderNodeVec2Uniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeVec2Parameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("default_value_enabled"); if (default_value_enabled) { props.push_back("default_value"); @@ -5410,59 +5414,59 @@ Vector<StringName> VisualShaderNodeVec2Uniform::get_editable_properties() const return props; } -VisualShaderNodeVec2Uniform::VisualShaderNodeVec2Uniform() { +VisualShaderNodeVec2Parameter::VisualShaderNodeVec2Parameter() { } -////////////// Vector3 Uniform +////////////// Vector3 Parameter -String VisualShaderNodeVec3Uniform::get_caption() const { - return "Vector3Uniform"; +String VisualShaderNodeVec3Parameter::get_caption() const { + return "Vector3Parameter"; } -int VisualShaderNodeVec3Uniform::get_input_port_count() const { +int VisualShaderNodeVec3Parameter::get_input_port_count() const { return 0; } -VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_input_port_type(int p_port) const { +VisualShaderNodeVec3Parameter::PortType VisualShaderNodeVec3Parameter::get_input_port_type(int p_port) const { return PORT_TYPE_VECTOR_3D; } -String VisualShaderNodeVec3Uniform::get_input_port_name(int p_port) const { +String VisualShaderNodeVec3Parameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeVec3Uniform::get_output_port_count() const { +int VisualShaderNodeVec3Parameter::get_output_port_count() const { return 1; } -VisualShaderNodeVec3Uniform::PortType VisualShaderNodeVec3Uniform::get_output_port_type(int p_port) const { +VisualShaderNodeVec3Parameter::PortType VisualShaderNodeVec3Parameter::get_output_port_type(int p_port) const { return PORT_TYPE_VECTOR_3D; } -String VisualShaderNodeVec3Uniform::get_output_port_name(int p_port) const { +String VisualShaderNodeVec3Parameter::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -void VisualShaderNodeVec3Uniform::set_default_value_enabled(bool p_enabled) { +void VisualShaderNodeVec3Parameter::set_default_value_enabled(bool p_enabled) { default_value_enabled = p_enabled; emit_changed(); } -bool VisualShaderNodeVec3Uniform::is_default_value_enabled() const { +bool VisualShaderNodeVec3Parameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeVec3Uniform::set_default_value(const Vector3 &p_value) { +void VisualShaderNodeVec3Parameter::set_default_value(const Vector3 &p_value) { default_value = p_value; emit_changed(); } -Vector3 VisualShaderNodeVec3Uniform::get_default_value() const { +Vector3 VisualShaderNodeVec3Parameter::get_default_value() const { return default_value; } -String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform vec3 " + get_uniform_name(); +String VisualShaderNodeVec3Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform vec3 " + get_parameter_name(); if (default_value_enabled) { code += vformat(" = vec3(%.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z); } @@ -5470,39 +5474,39 @@ String VisualShaderNodeVec3Uniform::generate_global(Shader::Mode p_mode, VisualS return code; } -String VisualShaderNodeVec3Uniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeVec3Parameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -void VisualShaderNodeVec3Uniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Uniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Uniform::is_default_value_enabled); +void VisualShaderNodeVec3Parameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec3Parameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec3Parameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Uniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Uniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec3Parameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec3Parameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value"); } -bool VisualShaderNodeVec3Uniform::is_show_prop_names() const { +bool VisualShaderNodeVec3Parameter::is_show_prop_names() const { return true; } -bool VisualShaderNodeVec3Uniform::is_use_prop_slots() const { +bool VisualShaderNodeVec3Parameter::is_use_prop_slots() const { return true; } -bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeVec3Parameter::is_qualifier_supported(Qualifier p_qual) const { return true; // all qualifiers are supported } -bool VisualShaderNodeVec3Uniform::is_convertible_to_constant() const { +bool VisualShaderNodeVec3Parameter::is_convertible_to_constant() const { return true; // conversion is allowed } -Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeVec3Parameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("default_value_enabled"); if (default_value_enabled) { props.push_back("default_value"); @@ -5510,59 +5514,59 @@ Vector<StringName> VisualShaderNodeVec3Uniform::get_editable_properties() const return props; } -VisualShaderNodeVec3Uniform::VisualShaderNodeVec3Uniform() { +VisualShaderNodeVec3Parameter::VisualShaderNodeVec3Parameter() { } -////////////// Vector4 Uniform +////////////// Vector4 Parameter -String VisualShaderNodeVec4Uniform::get_caption() const { - return "Vector4Uniform"; +String VisualShaderNodeVec4Parameter::get_caption() const { + return "Vector4Parameter"; } -int VisualShaderNodeVec4Uniform::get_input_port_count() const { +int VisualShaderNodeVec4Parameter::get_input_port_count() const { return 0; } -VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_input_port_type(int p_port) const { +VisualShaderNodeVec4Parameter::PortType VisualShaderNodeVec4Parameter::get_input_port_type(int p_port) const { return PORT_TYPE_VECTOR_4D; } -String VisualShaderNodeVec4Uniform::get_input_port_name(int p_port) const { +String VisualShaderNodeVec4Parameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeVec4Uniform::get_output_port_count() const { +int VisualShaderNodeVec4Parameter::get_output_port_count() const { return 1; } -VisualShaderNodeVec4Uniform::PortType VisualShaderNodeVec4Uniform::get_output_port_type(int p_port) const { +VisualShaderNodeVec4Parameter::PortType VisualShaderNodeVec4Parameter::get_output_port_type(int p_port) const { return PORT_TYPE_VECTOR_4D; } -String VisualShaderNodeVec4Uniform::get_output_port_name(int p_port) const { +String VisualShaderNodeVec4Parameter::get_output_port_name(int p_port) const { return ""; // No output port means the editor will be used as port. } -void VisualShaderNodeVec4Uniform::set_default_value_enabled(bool p_enabled) { +void VisualShaderNodeVec4Parameter::set_default_value_enabled(bool p_enabled) { default_value_enabled = p_enabled; emit_changed(); } -bool VisualShaderNodeVec4Uniform::is_default_value_enabled() const { +bool VisualShaderNodeVec4Parameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeVec4Uniform::set_default_value(const Quaternion &p_value) { +void VisualShaderNodeVec4Parameter::set_default_value(const Vector4 &p_value) { default_value = p_value; emit_changed(); } -Quaternion VisualShaderNodeVec4Uniform::get_default_value() const { +Vector4 VisualShaderNodeVec4Parameter::get_default_value() const { return default_value; } -String VisualShaderNodeVec4Uniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform vec4 " + get_uniform_name(); +String VisualShaderNodeVec4Parameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform vec4 " + get_parameter_name(); if (default_value_enabled) { code += vformat(" = vec4(%.6f, %.6f, %.6f, %.6f)", default_value.x, default_value.y, default_value.z, default_value.w); } @@ -5570,39 +5574,39 @@ String VisualShaderNodeVec4Uniform::generate_global(Shader::Mode p_mode, VisualS return code; } -String VisualShaderNodeVec4Uniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeVec4Parameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -void VisualShaderNodeVec4Uniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec4Uniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec4Uniform::is_default_value_enabled); +void VisualShaderNodeVec4Parameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeVec4Parameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeVec4Parameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec4Uniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec4Uniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeVec4Parameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeVec4Parameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "default_value"), "set_default_value", "get_default_value"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR4, "default_value"), "set_default_value", "get_default_value"); } -bool VisualShaderNodeVec4Uniform::is_show_prop_names() const { +bool VisualShaderNodeVec4Parameter::is_show_prop_names() const { return true; } -bool VisualShaderNodeVec4Uniform::is_use_prop_slots() const { +bool VisualShaderNodeVec4Parameter::is_use_prop_slots() const { return true; } -bool VisualShaderNodeVec4Uniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeVec4Parameter::is_qualifier_supported(Qualifier p_qual) const { return true; // All qualifiers are supported. } -bool VisualShaderNodeVec4Uniform::is_convertible_to_constant() const { +bool VisualShaderNodeVec4Parameter::is_convertible_to_constant() const { return true; // Conversion is allowed. } -Vector<StringName> VisualShaderNodeVec4Uniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeVec4Parameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("default_value_enabled"); if (default_value_enabled) { props.push_back("default_value"); @@ -5610,59 +5614,59 @@ Vector<StringName> VisualShaderNodeVec4Uniform::get_editable_properties() const return props; } -VisualShaderNodeVec4Uniform::VisualShaderNodeVec4Uniform() { +VisualShaderNodeVec4Parameter::VisualShaderNodeVec4Parameter() { } -////////////// Transform Uniform +////////////// Transform Parameter -String VisualShaderNodeTransformUniform::get_caption() const { - return "TransformUniform"; +String VisualShaderNodeTransformParameter::get_caption() const { + return "TransformParameter"; } -int VisualShaderNodeTransformUniform::get_input_port_count() const { +int VisualShaderNodeTransformParameter::get_input_port_count() const { return 0; } -VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_input_port_type(int p_port) const { +VisualShaderNodeTransformParameter::PortType VisualShaderNodeTransformParameter::get_input_port_type(int p_port) const { return PORT_TYPE_VECTOR_3D; } -String VisualShaderNodeTransformUniform::get_input_port_name(int p_port) const { +String VisualShaderNodeTransformParameter::get_input_port_name(int p_port) const { return String(); } -int VisualShaderNodeTransformUniform::get_output_port_count() const { +int VisualShaderNodeTransformParameter::get_output_port_count() const { return 1; } -VisualShaderNodeTransformUniform::PortType VisualShaderNodeTransformUniform::get_output_port_type(int p_port) const { +VisualShaderNodeTransformParameter::PortType VisualShaderNodeTransformParameter::get_output_port_type(int p_port) const { return PORT_TYPE_TRANSFORM; } -String VisualShaderNodeTransformUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeTransformParameter::get_output_port_name(int p_port) const { return ""; //no output port means the editor will be used as port } -void VisualShaderNodeTransformUniform::set_default_value_enabled(bool p_enabled) { +void VisualShaderNodeTransformParameter::set_default_value_enabled(bool p_enabled) { default_value_enabled = p_enabled; emit_changed(); } -bool VisualShaderNodeTransformUniform::is_default_value_enabled() const { +bool VisualShaderNodeTransformParameter::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeTransformUniform::set_default_value(const Transform3D &p_value) { +void VisualShaderNodeTransformParameter::set_default_value(const Transform3D &p_value) { default_value = p_value; emit_changed(); } -Transform3D VisualShaderNodeTransformUniform::get_default_value() const { +Transform3D VisualShaderNodeTransformParameter::get_default_value() const { return default_value; } -String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform mat4 " + get_uniform_name(); +String VisualShaderNodeTransformParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform mat4 " + get_parameter_name(); if (default_value_enabled) { Vector3 row0 = default_value.basis.rows[0]; Vector3 row1 = default_value.basis.rows[1]; @@ -5674,42 +5678,42 @@ String VisualShaderNodeTransformUniform::generate_global(Shader::Mode p_mode, Vi return code; } -String VisualShaderNodeTransformUniform::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 { - return " " + p_output_vars[0] + " = " + get_uniform_name() + ";\n"; +String VisualShaderNodeTransformParameter::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 { + return " " + p_output_vars[0] + " = " + get_parameter_name() + ";\n"; } -void VisualShaderNodeTransformUniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformUniform::set_default_value_enabled); - ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformUniform::is_default_value_enabled); +void VisualShaderNodeTransformParameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeTransformParameter::set_default_value_enabled); + ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeTransformParameter::is_default_value_enabled); - ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformUniform::set_default_value); - ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value); + ClassDB::bind_method(D_METHOD("set_default_value", "value"), &VisualShaderNodeTransformParameter::set_default_value); + ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformParameter::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "default_value"), "set_default_value", "get_default_value"); } -bool VisualShaderNodeTransformUniform::is_show_prop_names() const { +bool VisualShaderNodeTransformParameter::is_show_prop_names() const { return true; } -bool VisualShaderNodeTransformUniform::is_use_prop_slots() const { +bool VisualShaderNodeTransformParameter::is_use_prop_slots() const { return true; } -bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeTransformParameter::is_qualifier_supported(Qualifier p_qual) const { if (p_qual == Qualifier::QUAL_INSTANCE) { return false; } return true; } -bool VisualShaderNodeTransformUniform::is_convertible_to_constant() const { +bool VisualShaderNodeTransformParameter::is_convertible_to_constant() const { return true; // conversion is allowed } -Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeTransformParameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("default_value_enabled"); if (default_value_enabled) { props.push_back("default_value"); @@ -5717,12 +5721,12 @@ Vector<StringName> VisualShaderNodeTransformUniform::get_editable_properties() c return props; } -VisualShaderNodeTransformUniform::VisualShaderNodeTransformUniform() { +VisualShaderNodeTransformParameter::VisualShaderNodeTransformParameter() { } ////////////// -String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_type, VisualShaderNodeTextureUniform::ColorDefault p_color_default, VisualShaderNodeTextureUniform::TextureFilter p_texture_filter, VisualShaderNodeTextureUniform::TextureRepeat p_texture_repeat) { +String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat) { String code; bool has_colon = false; @@ -5731,25 +5735,25 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty String type_code; switch (p_texture_type) { - case VisualShaderNodeTextureUniform::TYPE_DATA: - if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) { + case VisualShaderNodeTextureParameter::TYPE_DATA: + if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_BLACK) { type_code = "hint_default_black"; - } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) { + } else if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_TRANSPARENT) { type_code = "hint_default_transparent"; } break; - case VisualShaderNodeTextureUniform::TYPE_COLOR: + case VisualShaderNodeTextureParameter::TYPE_COLOR: type_code = "source_color"; - if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) { + if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_BLACK) { type_code += ", hint_default_black"; - } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) { + } else if (p_color_default == VisualShaderNodeTextureParameter::COLOR_DEFAULT_TRANSPARENT) { type_code += ", hint_default_transparent"; } break; - case VisualShaderNodeTextureUniform::TYPE_NORMAL_MAP: + case VisualShaderNodeTextureParameter::TYPE_NORMAL_MAP: type_code = "hint_normal"; break; - case VisualShaderNodeTextureUniform::TYPE_ANISOTROPY: + case VisualShaderNodeTextureParameter::TYPE_ANISOTROPY: type_code = "hint_anisotropy"; break; default: @@ -5767,22 +5771,22 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty String filter_code; switch (p_texture_filter) { - case VisualShaderNodeTextureUniform::FILTER_NEAREST: + case VisualShaderNodeTextureParameter::FILTER_NEAREST: filter_code = "filter_nearest"; break; - case VisualShaderNodeTextureUniform::FILTER_LINEAR: + case VisualShaderNodeTextureParameter::FILTER_LINEAR: filter_code = "filter_linear"; break; - case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP: + case VisualShaderNodeTextureParameter::FILTER_NEAREST_MIPMAP: filter_code = "filter_nearest_mipmap"; break; - case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP: + case VisualShaderNodeTextureParameter::FILTER_LINEAR_MIPMAP: filter_code = "filter_linear_mipmap"; break; - case VisualShaderNodeTextureUniform::FILTER_NEAREST_MIPMAP_ANISOTROPIC: + case VisualShaderNodeTextureParameter::FILTER_NEAREST_MIPMAP_ANISOTROPIC: filter_code = "filter_nearest_mipmap_anisotropic"; break; - case VisualShaderNodeTextureUniform::FILTER_LINEAR_MIPMAP_ANISOTROPIC: + case VisualShaderNodeTextureParameter::FILTER_LINEAR_MIPMAP_ANISOTROPIC: filter_code = "filter_linear_mipmap_anisotropic"; break; default: @@ -5805,10 +5809,10 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty String repeat_code; switch (p_texture_repeat) { - case VisualShaderNodeTextureUniform::REPEAT_ENABLED: + case VisualShaderNodeTextureParameter::REPEAT_ENABLED: repeat_code = "repeat_enable"; break; - case VisualShaderNodeTextureUniform::REPEAT_DISABLED: + case VisualShaderNodeTextureParameter::REPEAT_DISABLED: repeat_code = "repeat_disable"; break; default: @@ -5828,29 +5832,25 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty return code; } -////////////// Texture Uniform - -String VisualShaderNodeTextureUniform::get_caption() const { - return "TextureUniform"; -} +////////////// Texture Parameter -int VisualShaderNodeTextureUniform::get_input_port_count() const { +int VisualShaderNodeTextureParameter::get_input_port_count() const { return 0; } -VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_input_port_type(int p_port) const { +VisualShaderNodeTextureParameter::PortType VisualShaderNodeTextureParameter::get_input_port_type(int p_port) const { return PORT_TYPE_SCALAR; } -String VisualShaderNodeTextureUniform::get_input_port_name(int p_port) const { +String VisualShaderNodeTextureParameter::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeTextureUniform::get_output_port_count() const { +int VisualShaderNodeTextureParameter::get_output_port_count() const { return 1; } -VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_output_port_type(int p_port) const { +VisualShaderNodeTextureParameter::PortType VisualShaderNodeTextureParameter::get_output_port_type(int p_port) const { switch (p_port) { case 0: return PORT_TYPE_SAMPLER; @@ -5859,27 +5859,11 @@ VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniform::get_out } } -String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const { - switch (p_port) { - case 0: - return "sampler2D"; - default: - return ""; - } -} - -String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform sampler2D " + get_uniform_name(); - code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); - code += ";\n"; - return code; -} - -String VisualShaderNodeTextureUniform::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 VisualShaderNodeTextureParameter::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 { return ""; } -void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_texture_type) { +void VisualShaderNodeTextureParameter::set_texture_type(TextureType p_texture_type) { ERR_FAIL_INDEX(int(p_texture_type), int(TYPE_MAX)); if (texture_type == p_texture_type) { return; @@ -5888,11 +5872,11 @@ void VisualShaderNodeTextureUniform::set_texture_type(TextureType p_texture_type emit_changed(); } -VisualShaderNodeTextureUniform::TextureType VisualShaderNodeTextureUniform::get_texture_type() const { +VisualShaderNodeTextureParameter::TextureType VisualShaderNodeTextureParameter::get_texture_type() const { return texture_type; } -void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_color_default) { +void VisualShaderNodeTextureParameter::set_color_default(ColorDefault p_color_default) { ERR_FAIL_INDEX(int(p_color_default), int(COLOR_DEFAULT_MAX)); if (color_default == p_color_default) { return; @@ -5901,11 +5885,11 @@ void VisualShaderNodeTextureUniform::set_color_default(ColorDefault p_color_defa emit_changed(); } -VisualShaderNodeTextureUniform::ColorDefault VisualShaderNodeTextureUniform::get_color_default() const { +VisualShaderNodeTextureParameter::ColorDefault VisualShaderNodeTextureParameter::get_color_default() const { return color_default; } -void VisualShaderNodeTextureUniform::set_texture_filter(TextureFilter p_filter) { +void VisualShaderNodeTextureParameter::set_texture_filter(TextureFilter p_filter) { ERR_FAIL_INDEX(int(p_filter), int(FILTER_MAX)); if (texture_filter == p_filter) { return; @@ -5914,11 +5898,11 @@ void VisualShaderNodeTextureUniform::set_texture_filter(TextureFilter p_filter) emit_changed(); } -VisualShaderNodeTextureUniform::TextureFilter VisualShaderNodeTextureUniform::get_texture_filter() const { +VisualShaderNodeTextureParameter::TextureFilter VisualShaderNodeTextureParameter::get_texture_filter() const { return texture_filter; } -void VisualShaderNodeTextureUniform::set_texture_repeat(TextureRepeat p_repeat) { +void VisualShaderNodeTextureParameter::set_texture_repeat(TextureRepeat p_repeat) { ERR_FAIL_INDEX(int(p_repeat), int(REPEAT_MAX)); if (texture_repeat == p_repeat) { return; @@ -5927,12 +5911,12 @@ void VisualShaderNodeTextureUniform::set_texture_repeat(TextureRepeat p_repeat) emit_changed(); } -VisualShaderNodeTextureUniform::TextureRepeat VisualShaderNodeTextureUniform::get_texture_repeat() const { +VisualShaderNodeTextureParameter::TextureRepeat VisualShaderNodeTextureParameter::get_texture_repeat() const { return texture_repeat; } -Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() const { - Vector<StringName> props = VisualShaderNodeUniform::get_editable_properties(); +Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() const { + Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties(); props.push_back("texture_type"); if (texture_type == TYPE_DATA || texture_type == TYPE_COLOR) { props.push_back("color_default"); @@ -5942,11 +5926,11 @@ Vector<StringName> VisualShaderNodeTextureUniform::get_editable_properties() con return props; } -bool VisualShaderNodeTextureUniform::is_show_prop_names() const { +bool VisualShaderNodeTextureParameter::is_show_prop_names() const { return true; } -HashMap<StringName, String> VisualShaderNodeTextureUniform::get_editable_properties_names() const { +HashMap<StringName, String> VisualShaderNodeTextureParameter::get_editable_properties_names() const { HashMap<StringName, String> names; names.insert("texture_type", RTR("Type")); names.insert("color_default", RTR("Default Color")); @@ -5955,18 +5939,18 @@ HashMap<StringName, String> VisualShaderNodeTextureUniform::get_editable_propert return names; } -void VisualShaderNodeTextureUniform::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureUniform::set_texture_type); - ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureUniform::get_texture_type); +void VisualShaderNodeTextureParameter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureParameter::set_texture_type); + ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureParameter::get_texture_type); - ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureUniform::set_color_default); - ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureUniform::get_color_default); + ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureParameter::set_color_default); + ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureParameter::get_color_default); - ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureUniform::set_texture_filter); - ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureUniform::get_texture_filter); + ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureParameter::set_texture_filter); + ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureParameter::get_texture_filter); - ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureUniform::set_texture_repeat); - ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureUniform::get_texture_repeat); + ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureParameter::set_texture_repeat); + ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureParameter::get_texture_repeat); ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type"); ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default"); @@ -5999,7 +5983,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() { BIND_ENUM_CONSTANT(REPEAT_MAX); } -bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) const { +bool VisualShaderNodeTextureParameter::is_qualifier_supported(Qualifier p_qual) const { switch (p_qual) { case Qualifier::QUAL_NONE: return true; @@ -6013,31 +5997,56 @@ bool VisualShaderNodeTextureUniform::is_qualifier_supported(Qualifier p_qual) co return false; } -bool VisualShaderNodeTextureUniform::is_convertible_to_constant() const { +bool VisualShaderNodeTextureParameter::is_convertible_to_constant() const { return false; // conversion is not allowed } -VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() { +VisualShaderNodeTextureParameter::VisualShaderNodeTextureParameter() { +} + +////////////// Texture2D Parameter + +String VisualShaderNodeTexture2DParameter::get_caption() const { + return "Texture2DParameter"; +} + +String VisualShaderNodeTexture2DParameter::get_output_port_name(int p_port) const { + switch (p_port) { + case 0: + return "sampler2D"; + default: + return ""; + } +} + +String VisualShaderNodeTexture2DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name(); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += ";\n"; + return code; +} + +VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() { } -////////////// Texture Uniform (Triplanar) +////////////// Texture Parameter (Triplanar) -String VisualShaderNodeTextureUniformTriplanar::get_caption() const { +String VisualShaderNodeTextureParameterTriplanar::get_caption() const { return "TextureUniformTriplanar"; } -int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const { +int VisualShaderNodeTextureParameterTriplanar::get_input_port_count() const { return 2; } -VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const { +VisualShaderNodeTextureParameterTriplanar::PortType VisualShaderNodeTextureParameterTriplanar::get_input_port_type(int p_port) const { if (p_port == 0 || p_port == 1) { return PORT_TYPE_VECTOR_3D; } return PORT_TYPE_SCALAR; } -String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port) const { +String VisualShaderNodeTextureParameterTriplanar::get_input_port_name(int p_port) const { if (p_port == 0) { return "weights"; } else if (p_port == 1) { @@ -6046,11 +6055,11 @@ String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port) return ""; } -int VisualShaderNodeTextureUniformTriplanar::get_output_port_count() const { +int VisualShaderNodeTextureParameterTriplanar::get_output_port_count() const { return 2; } -VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniformTriplanar::get_output_port_type(int p_port) const { +VisualShaderNodeTextureParameterTriplanar::PortType VisualShaderNodeTextureParameterTriplanar::get_output_port_type(int p_port) const { switch (p_port) { case 0: return PORT_TYPE_VECTOR_4D; @@ -6061,7 +6070,7 @@ VisualShaderNodeTextureUniformTriplanar::PortType VisualShaderNodeTextureUniform } } -String VisualShaderNodeTextureUniformTriplanar::get_output_port_name(int p_port) const { +String VisualShaderNodeTextureParameterTriplanar::get_output_port_name(int p_port) const { switch (p_port) { case 0: return "color"; @@ -6072,7 +6081,7 @@ String VisualShaderNodeTextureUniformTriplanar::get_output_port_name(int p_port) } } -String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const { +String VisualShaderNodeTextureParameterTriplanar::generate_global_per_node(Shader::Mode p_mode, int p_id) const { String code; code += "// " + get_caption() + "\n"; @@ -6094,7 +6103,7 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader: return code; } -String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { +String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code; if (p_type == VisualShader::TYPE_VERTEX) { @@ -6110,8 +6119,15 @@ String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader: return code; } -String VisualShaderNodeTextureUniformTriplanar::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 id = get_uniform_name(); +String VisualShaderNodeTextureParameterTriplanar::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name(); + code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); + code += ";\n"; + return code; +} + +String VisualShaderNodeTextureParameterTriplanar::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 id = get_parameter_name(); String code; if (p_input_vars[0].is_empty() && p_input_vars[1].is_empty()) { @@ -6127,7 +6143,7 @@ String VisualShaderNodeTextureUniformTriplanar::generate_code(Shader::Mode p_mod return code; } -bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port, Shader::Mode p_mode) const { +bool VisualShaderNodeTextureParameterTriplanar::is_input_port_default(int p_port, Shader::Mode p_mode) const { if (p_port == 0) { return true; } else if (p_port == 1) { @@ -6136,79 +6152,67 @@ bool VisualShaderNodeTextureUniformTriplanar::is_input_port_default(int p_port, return false; } -VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() { +VisualShaderNodeTextureParameterTriplanar::VisualShaderNodeTextureParameterTriplanar() { } -////////////// Texture2DArray Uniform +////////////// Texture2DArray Parameter -String VisualShaderNodeTexture2DArrayUniform::get_caption() const { - return "Texture2DArrayUniform"; +String VisualShaderNodeTexture2DArrayParameter::get_caption() const { + return "Texture2DArrayParameter"; } -String VisualShaderNodeTexture2DArrayUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeTexture2DArrayParameter::get_output_port_name(int p_port) const { return "sampler2DArray"; } -String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform sampler2DArray " + get_uniform_name(); +String VisualShaderNodeTexture2DArrayParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler2DArray " + get_parameter_name(); code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); code += ";\n"; return code; } -String VisualShaderNodeTexture2DArrayUniform::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 { - return String(); -} - -VisualShaderNodeTexture2DArrayUniform::VisualShaderNodeTexture2DArrayUniform() { +VisualShaderNodeTexture2DArrayParameter::VisualShaderNodeTexture2DArrayParameter() { } -////////////// Texture3D Uniform +////////////// Texture3D Parameter -String VisualShaderNodeTexture3DUniform::get_caption() const { - return "Texture3DUniform"; +String VisualShaderNodeTexture3DParameter::get_caption() const { + return "Texture3DParameter"; } -String VisualShaderNodeTexture3DUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeTexture3DParameter::get_output_port_name(int p_port) const { return "sampler3D"; } -String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform sampler3D " + get_uniform_name(); +String VisualShaderNodeTexture3DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform sampler3D " + get_parameter_name(); code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); code += ";\n"; return code; } -String VisualShaderNodeTexture3DUniform::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 { - return String(); -} - -VisualShaderNodeTexture3DUniform::VisualShaderNodeTexture3DUniform() { +VisualShaderNodeTexture3DParameter::VisualShaderNodeTexture3DParameter() { } -////////////// Cubemap Uniform +////////////// Cubemap Parameter -String VisualShaderNodeCubemapUniform::get_caption() const { - return "CubemapUniform"; +String VisualShaderNodeCubemapParameter::get_caption() const { + return "CubemapParameter"; } -String VisualShaderNodeCubemapUniform::get_output_port_name(int p_port) const { +String VisualShaderNodeCubemapParameter::get_output_port_name(int p_port) const { return "samplerCube"; } -String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { - String code = _get_qual_str() + "uniform samplerCube " + get_uniform_name(); +String VisualShaderNodeCubemapParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code = _get_qual_str() + "uniform samplerCube " + get_parameter_name(); code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat); code += ";\n"; return code; } -String VisualShaderNodeCubemapUniform::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 { - return String(); -} - -VisualShaderNodeCubemapUniform::VisualShaderNodeCubemapUniform() { +VisualShaderNodeCubemapParameter::VisualShaderNodeCubemapParameter() { } ////////////// If @@ -7201,6 +7205,10 @@ String VisualShaderNodeDistanceFade::get_output_port_name(int p_port) const { return "amount"; } +bool VisualShaderNodeDistanceFade::has_output_port_preview(int p_port) const { + return false; +} + String VisualShaderNodeDistanceFade::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; code += vformat(" %s = clamp(smoothstep(%s, %s,-VERTEX.z),0.0,1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]); @@ -7242,12 +7250,20 @@ String VisualShaderNodeProximityFade::get_output_port_name(int p_port) const { return "fade"; } +bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const { + return false; +} + String VisualShaderNodeProximityFade::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; String proximity_fade_distance = vformat("%s", p_input_vars[0]); code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n"; - code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n"; + if (!RenderingServer::get_singleton()->is_low_end()) { + code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n"; + } else { + code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n"; + } code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n"; code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index c603a10eae..4b883c25cc 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -636,6 +636,7 @@ public: 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; @@ -1762,11 +1763,11 @@ public: }; /////////////////////////////////////// -/// UNIFORMS +/// PARAMETERS /////////////////////////////////////// -class VisualShaderNodeFloatUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeFloatUniform, VisualShaderNodeUniform); +class VisualShaderNodeFloatParameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeFloatParameter, VisualShaderNodeParameter); public: enum Hint { @@ -1827,13 +1828,13 @@ public: virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeFloatUniform(); + VisualShaderNodeFloatParameter(); }; -VARIANT_ENUM_CAST(VisualShaderNodeFloatUniform::Hint) +VARIANT_ENUM_CAST(VisualShaderNodeFloatParameter::Hint) -class VisualShaderNodeIntUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeIntUniform, VisualShaderNodeUniform); +class VisualShaderNodeIntParameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeIntParameter, VisualShaderNodeParameter); public: enum Hint { @@ -1894,15 +1895,15 @@ public: virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeIntUniform(); + VisualShaderNodeIntParameter(); }; -VARIANT_ENUM_CAST(VisualShaderNodeIntUniform::Hint) +VARIANT_ENUM_CAST(VisualShaderNodeIntParameter::Hint) /////////////////////////////////////// -class VisualShaderNodeBooleanUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeBooleanUniform, VisualShaderNodeUniform); +class VisualShaderNodeBooleanParameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeBooleanParameter, VisualShaderNodeParameter); private: bool default_value_enabled = false; @@ -1939,13 +1940,13 @@ public: virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeBooleanUniform(); + VisualShaderNodeBooleanParameter(); }; /////////////////////////////////////// -class VisualShaderNodeColorUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeColorUniform, VisualShaderNodeUniform); +class VisualShaderNodeColorParameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeColorParameter, VisualShaderNodeParameter); private: bool default_value_enabled = false; @@ -1983,13 +1984,13 @@ public: virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeColorUniform(); + VisualShaderNodeColorParameter(); }; /////////////////////////////////////// -class VisualShaderNodeVec2Uniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeVec2Uniform, VisualShaderNodeUniform); +class VisualShaderNodeVec2Parameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeVec2Parameter, VisualShaderNodeParameter); private: bool default_value_enabled = false; @@ -2026,13 +2027,13 @@ public: virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeVec2Uniform(); + VisualShaderNodeVec2Parameter(); }; /////////////////////////////////////// -class VisualShaderNodeVec3Uniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeVec3Uniform, VisualShaderNodeUniform); +class VisualShaderNodeVec3Parameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeVec3Parameter, VisualShaderNodeParameter); private: bool default_value_enabled = false; @@ -2069,17 +2070,17 @@ public: virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeVec3Uniform(); + VisualShaderNodeVec3Parameter(); }; /////////////////////////////////////// -class VisualShaderNodeVec4Uniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeVec4Uniform, VisualShaderNodeUniform); +class VisualShaderNodeVec4Parameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeVec4Parameter, VisualShaderNodeParameter); private: bool default_value_enabled = false; - Quaternion default_value; + Vector4 default_value; protected: static void _bind_methods(); @@ -2104,21 +2105,21 @@ public: void set_default_value_enabled(bool p_enabled); bool is_default_value_enabled() const; - void set_default_value(const Quaternion &p_value); - Quaternion get_default_value() const; + void set_default_value(const Vector4 &p_value); + Vector4 get_default_value() const; bool is_qualifier_supported(Qualifier p_qual) const override; bool is_convertible_to_constant() const override; virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeVec4Uniform(); + VisualShaderNodeVec4Parameter(); }; /////////////////////////////////////// -class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeTransformUniform, VisualShaderNodeUniform); +class VisualShaderNodeTransformParameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeTransformParameter, VisualShaderNodeParameter); private: bool default_value_enabled = false; @@ -2155,13 +2156,13 @@ public: virtual Vector<StringName> get_editable_properties() const override; - VisualShaderNodeTransformUniform(); + VisualShaderNodeTransformParameter(); }; /////////////////////////////////////// -class VisualShaderNodeTextureUniform : public VisualShaderNodeUniform { - GDCLASS(VisualShaderNodeTextureUniform, VisualShaderNodeUniform); +class VisualShaderNodeTextureParameter : public VisualShaderNodeParameter { + GDCLASS(VisualShaderNodeTextureParameter, VisualShaderNodeParameter); public: enum TextureType { @@ -2207,17 +2208,13 @@ protected: static void _bind_methods(); 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; virtual HashMap<StringName, String> get_editable_properties_names() const override; @@ -2240,18 +2237,32 @@ public: bool is_qualifier_supported(Qualifier p_qual) const override; bool is_convertible_to_constant() const override; - VisualShaderNodeTextureUniform(); + VisualShaderNodeTextureParameter(); }; -VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureType) -VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault) -VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureFilter) -VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::TextureRepeat) +VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureType) +VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::ColorDefault) +VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureFilter) +VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureRepeat) /////////////////////////////////////// -class VisualShaderNodeTextureUniformTriplanar : public VisualShaderNodeTextureUniform { - GDCLASS(VisualShaderNodeTextureUniformTriplanar, VisualShaderNodeTextureUniform); +class VisualShaderNodeTexture2DParameter : public VisualShaderNodeTextureParameter { + GDCLASS(VisualShaderNodeTexture2DParameter, VisualShaderNodeTextureParameter); + +public: + virtual String get_caption() 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; + + VisualShaderNodeTexture2DParameter(); +}; + +/////////////////////////////////////// + +class VisualShaderNodeTextureParameterTriplanar : public VisualShaderNodeTextureParameter { + GDCLASS(VisualShaderNodeTextureParameterTriplanar, VisualShaderNodeTextureParameter); public: virtual String get_caption() const override; @@ -2268,54 +2279,52 @@ public: 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; + 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; - VisualShaderNodeTextureUniformTriplanar(); + VisualShaderNodeTextureParameterTriplanar(); }; /////////////////////////////////////// -class VisualShaderNodeTexture2DArrayUniform : public VisualShaderNodeTextureUniform { - GDCLASS(VisualShaderNodeTexture2DArrayUniform, VisualShaderNodeTextureUniform); +class VisualShaderNodeTexture2DArrayParameter : public VisualShaderNodeTextureParameter { + GDCLASS(VisualShaderNodeTexture2DArrayParameter, VisualShaderNodeTextureParameter); public: virtual String get_caption() 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; - VisualShaderNodeTexture2DArrayUniform(); + VisualShaderNodeTexture2DArrayParameter(); }; /////////////////////////////////////// -class VisualShaderNodeTexture3DUniform : public VisualShaderNodeTextureUniform { - GDCLASS(VisualShaderNodeTexture3DUniform, VisualShaderNodeTextureUniform); +class VisualShaderNodeTexture3DParameter : public VisualShaderNodeTextureParameter { + GDCLASS(VisualShaderNodeTexture3DParameter, VisualShaderNodeTextureParameter); public: virtual String get_caption() 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; - VisualShaderNodeTexture3DUniform(); + VisualShaderNodeTexture3DParameter(); }; /////////////////////////////////////// -class VisualShaderNodeCubemapUniform : public VisualShaderNodeTextureUniform { - GDCLASS(VisualShaderNodeCubemapUniform, VisualShaderNodeTextureUniform); +class VisualShaderNodeCubemapParameter : public VisualShaderNodeTextureParameter { + GDCLASS(VisualShaderNodeCubemapParameter, VisualShaderNodeTextureParameter); public: virtual String get_caption() 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; - VisualShaderNodeCubemapUniform(); + VisualShaderNodeCubemapParameter(); }; /////////////////////////////////////// @@ -2636,6 +2645,7 @@ public: 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; @@ -2655,6 +2665,7 @@ public: 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; diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 4dfbe5f079..75deb1e60b 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -85,6 +85,7 @@ World2D::World2D() { NavigationServer2D::get_singleton()->map_set_active(navigation_map, true); NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 1)); NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 1)); + NavigationServer2D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/2d/default_link_connection_radius", 4)); } World2D::~World2D() { diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index fb6dcd3d57..ae8c9a182f 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -33,6 +33,8 @@ #include "core/config/project_settings.h" #include "scene/3d/camera_3d.h" #include "scene/3d/visible_on_screen_notifier_3d.h" +#include "scene/resources/camera_attributes.h" +#include "scene/resources/environment.h" #include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" @@ -98,17 +100,17 @@ Ref<Environment> World3D::get_fallback_environment() const { return fallback_environment; } -void World3D::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) { - camera_effects = p_camera_effects; - if (camera_effects.is_valid()) { - RS::get_singleton()->scenario_set_camera_effects(scenario, camera_effects->get_rid()); +void World3D::set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes) { + camera_attributes = p_camera_attributes; + if (camera_attributes.is_valid()) { + RS::get_singleton()->scenario_set_camera_attributes(scenario, camera_attributes->get_rid()); } else { - RS::get_singleton()->scenario_set_camera_effects(scenario, RID()); + RS::get_singleton()->scenario_set_camera_attributes(scenario, RID()); } } -Ref<CameraEffects> World3D::get_camera_effects() const { - return camera_effects; +Ref<CameraAttributes> World3D::get_camera_attributes() const { + return camera_attributes; } PhysicsDirectSpaceState3D *World3D::get_direct_space_state() { @@ -123,12 +125,12 @@ void World3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment); ClassDB::bind_method(D_METHOD("set_fallback_environment", "env"), &World3D::set_fallback_environment); ClassDB::bind_method(D_METHOD("get_fallback_environment"), &World3D::get_fallback_environment); - ClassDB::bind_method(D_METHOD("set_camera_effects", "effects"), &World3D::set_camera_effects); - ClassDB::bind_method(D_METHOD("get_camera_effects"), &World3D::get_camera_effects); + ClassDB::bind_method(D_METHOD("set_camera_attributes", "attributes"), &World3D::set_camera_attributes); + ClassDB::bind_method(D_METHOD("get_camera_attributes"), &World3D::get_camera_attributes); ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World3D::get_direct_space_state); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_attributes", PROPERTY_HINT_RESOURCE_TYPE, "CameraAttributesPractical,CameraAttributesPhysical"), "set_camera_attributes", "get_camera_attributes"); ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_space"); ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map"); ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_scenario"); @@ -151,6 +153,7 @@ World3D::World3D() { NavigationServer3D::get_singleton()->map_set_active(navigation_map, true); NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.25)); NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.25)); + NavigationServer3D::get_singleton()->map_set_link_connection_radius(navigation_map, GLOBAL_DEF("navigation/3d/default_link_connection_radius", 1.0)); } World3D::~World3D() { diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h index 08bc050349..411b9aab37 100644 --- a/scene/resources/world_3d.h +++ b/scene/resources/world_3d.h @@ -32,11 +32,11 @@ #define WORLD_3D_H #include "core/io/resource.h" -#include "scene/resources/camera_effects.h" #include "scene/resources/environment.h" #include "servers/physics_server_3d.h" #include "servers/rendering_server.h" +class CameraAttributes; class Camera3D; class VisibleOnScreenNotifier3D; struct SpatialIndexer; @@ -51,7 +51,7 @@ private: Ref<Environment> environment; Ref<Environment> fallback_environment; - Ref<CameraEffects> camera_effects; + Ref<CameraAttributes> camera_attributes; HashSet<Camera3D *> cameras; @@ -74,8 +74,8 @@ public: void set_fallback_environment(const Ref<Environment> &p_environment); Ref<Environment> get_fallback_environment() const; - void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); - Ref<CameraEffects> get_camera_effects() const; + void set_camera_attributes(const Ref<CameraAttributes> &p_camera_attributes); + Ref<CameraAttributes> get_camera_attributes() const; _FORCE_INLINE_ const HashSet<Camera3D *> &get_cameras() const { return cameras; } diff --git a/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp new file mode 100644 index 0000000000..e89aa1b28d --- /dev/null +++ b/scene/theme/theme_owner.cpp @@ -0,0 +1,410 @@ +/*************************************************************************/ +/* theme_owner.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "theme_owner.h" + +#include "scene/gui/control.h" +#include "scene/main/window.h" +#include "scene/theme/theme_db.h" + +// Theme owner node. + +void ThemeOwner::set_owner_node(Node *p_node) { + owner_control = nullptr; + owner_window = nullptr; + + Control *c = Object::cast_to<Control>(p_node); + if (c) { + owner_control = c; + return; + } + + Window *w = Object::cast_to<Window>(p_node); + if (w) { + owner_window = w; + return; + } +} + +Node *ThemeOwner::get_owner_node() const { + if (owner_control) { + return owner_control; + } else if (owner_window) { + return owner_window; + } + return nullptr; +} + +bool ThemeOwner::has_owner_node() const { + return bool(owner_control || owner_window); +} + +// Theme propagation. + +void ThemeOwner::assign_theme_on_parented(Node *p_for_node) { + // We check if there are any themes affecting the parent. If that's the case + // its children also need to be affected. + // We don't notify here because `NOTIFICATION_THEME_CHANGED` will be handled + // a bit later by `NOTIFICATION_ENTER_TREE`. + + Node *parent = p_for_node->get_parent(); + + Control *parent_c = Object::cast_to<Control>(parent); + if (parent_c && parent_c->has_theme_owner_node()) { + propagate_theme_changed(p_for_node, parent_c->get_theme_owner_node(), false, true); + } else { + Window *parent_w = Object::cast_to<Window>(parent); + if (parent_w && parent_w->has_theme_owner_node()) { + propagate_theme_changed(p_for_node, parent_w->get_theme_owner_node(), false, true); + } + } +} + +void ThemeOwner::clear_theme_on_unparented(Node *p_for_node) { + // We check if there were any themes affecting the parent. If that's the case + // its children need were also affected and need to be updated. + // We don't notify because we're exiting the tree, and it's not important. + + Node *parent = p_for_node->get_parent(); + + Control *parent_c = Object::cast_to<Control>(parent); + if (parent_c && parent_c->has_theme_owner_node()) { + propagate_theme_changed(p_for_node, nullptr, false, true); + } else { + Window *parent_w = Object::cast_to<Window>(parent); + if (parent_w && parent_w->has_theme_owner_node()) { + propagate_theme_changed(p_for_node, nullptr, false, true); + } + } +} + +void ThemeOwner::propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign) { + Control *c = Object::cast_to<Control>(p_to_node); + Window *w = c == nullptr ? Object::cast_to<Window>(p_to_node) : nullptr; + + if (!c && !w) { + // Theme inheritance chains are broken by nodes that aren't Control or Window. + return; + } + + bool assign = p_assign; + if (c) { + if (c != p_owner_node && c->get_theme().is_valid()) { + // Has a theme, so we don't want to change the theme owner, + // but we still want to propagate in case this child has theme items + // it inherits from the theme this node uses. + // See https://github.com/godotengine/godot/issues/62844. + assign = false; + } + + if (assign) { + c->set_theme_owner_node(p_owner_node); + } + + if (p_notify) { + c->notification(Control::NOTIFICATION_THEME_CHANGED); + } + } else if (w) { + if (w != p_owner_node && w->get_theme().is_valid()) { + // Same as above. + assign = false; + } + + if (assign) { + w->set_theme_owner_node(p_owner_node); + } + + if (p_notify) { + w->notification(Window::NOTIFICATION_THEME_CHANGED); + } + } + + for (int i = 0; i < p_to_node->get_child_count(); i++) { + propagate_theme_changed(p_to_node->get_child(i), p_owner_node, p_notify, assign); + } +} + +// Theme lookup. + +void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const { + const Control *for_c = Object::cast_to<Control>(p_for_node); + const Window *for_w = Object::cast_to<Window>(p_for_node); + ERR_FAIL_COND_MSG(!for_c && !for_w, "Only Control and Window nodes and derivatives can be polled for theming."); + + Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme(); + Ref<Theme> project_theme = ThemeDB::get_singleton()->get_project_theme(); + + StringName type_variation; + if (for_c) { + type_variation = for_c->get_theme_type_variation(); + } else if (for_w) { + type_variation = for_w->get_theme_type_variation(); + } + + if (p_theme_type == StringName() || p_theme_type == p_for_node->get_class_name() || p_theme_type == type_variation) { + if (project_theme.is_valid() && project_theme->get_type_variation_base(type_variation) != StringName()) { + project_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list); + } else { + default_theme->get_type_dependencies(p_for_node->get_class_name(), type_variation, r_list); + } + } else { + default_theme->get_type_dependencies(p_theme_type, StringName(), r_list); + } +} + +Node *ThemeOwner::_get_next_owner_node(Node *p_from_node) const { + Node *parent = p_from_node->get_parent(); + + Control *parent_c = Object::cast_to<Control>(parent); + if (parent_c) { + return parent_c->get_theme_owner_node(); + } else { + Window *parent_w = Object::cast_to<Window>(parent); + if (parent_w) { + return parent_w->get_theme_owner_node(); + } + } + + return nullptr; +} + +Variant ThemeOwner::get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) { + ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, Variant(), "At least one theme type must be specified."); + + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + Node *owner_node = get_owner_node(); + + while (owner_node) { + // For each theme resource check the theme types provided and see if p_name exists with any of them. + for (const StringName &E : p_theme_types) { + Ref<Theme> owner_theme; + + Control *owner_c = Object::cast_to<Control>(owner_node); + if (owner_c) { + owner_theme = owner_c->get_theme(); + } + Window *owner_w = Object::cast_to<Window>(owner_node); + if (owner_w) { + owner_theme = owner_w->get_theme(); + } + + if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) { + return owner_theme->get_theme_item(p_data_type, p_name, E); + } + } + + owner_node = _get_next_owner_node(owner_node); + } + + // Secondly, check the project-defined Theme resource. + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + for (const StringName &E : p_theme_types) { + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) { + return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(p_data_type, p_name, E); + } + } + } + + // Lastly, fall back on the items defined in the default Theme, if they exist. + for (const StringName &E : p_theme_types) { + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) { + return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, E); + } + } + + // If they don't exist, use any type to return the default/empty value. + return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]); +} + +bool ThemeOwner::has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) { + ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified."); + + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + Node *owner_node = get_owner_node(); + + while (owner_node) { + // For each theme resource check the theme types provided and see if p_name exists with any of them. + for (const StringName &E : p_theme_types) { + Ref<Theme> owner_theme; + + Control *owner_c = Object::cast_to<Control>(owner_node); + if (owner_c) { + owner_theme = owner_c->get_theme(); + } + Window *owner_w = Object::cast_to<Window>(owner_node); + if (owner_w) { + owner_theme = owner_w->get_theme(); + } + + if (owner_theme.is_valid() && owner_theme->has_theme_item(p_data_type, p_name, E)) { + return true; + } + } + + owner_node = _get_next_owner_node(owner_node); + } + + // Secondly, check the project-defined Theme resource. + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + for (const StringName &E : p_theme_types) { + if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) { + return true; + } + } + } + + // Lastly, fall back on the items defined in the default Theme, if they exist. + for (const StringName &E : p_theme_types) { + if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) { + return true; + } + } + + return false; +} + +float ThemeOwner::get_theme_default_base_scale() { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Node *owner_node = get_owner_node(); + + while (owner_node) { + Ref<Theme> owner_theme; + + Control *owner_c = Object::cast_to<Control>(owner_node); + if (owner_c) { + owner_theme = owner_c->get_theme(); + } + Window *owner_w = Object::cast_to<Window>(owner_node); + if (owner_w) { + owner_theme = owner_w->get_theme(); + } + + if (owner_theme.is_valid() && owner_theme->has_default_base_scale()) { + return owner_theme->get_default_base_scale(); + } + + owner_node = _get_next_owner_node(owner_node); + } + + // Secondly, check the project-defined Theme resource. + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme()->has_default_base_scale()) { + return ThemeDB::get_singleton()->get_project_theme()->get_default_base_scale(); + } + } + + // Lastly, fall back on the default Theme. + if (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) { + return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale(); + } + return ThemeDB::get_singleton()->get_fallback_base_scale(); +} + +Ref<Font> ThemeOwner::get_theme_default_font() { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Node *owner_node = get_owner_node(); + + while (owner_node) { + Ref<Theme> owner_theme; + + Control *owner_c = Object::cast_to<Control>(owner_node); + if (owner_c) { + owner_theme = owner_c->get_theme(); + } + Window *owner_w = Object::cast_to<Window>(owner_node); + if (owner_w) { + owner_theme = owner_w->get_theme(); + } + + if (owner_theme.is_valid() && owner_theme->has_default_font()) { + return owner_theme->get_default_font(); + } + + owner_node = _get_next_owner_node(owner_node); + } + + // Secondly, check the project-defined Theme resource. + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme()->has_default_font()) { + return ThemeDB::get_singleton()->get_project_theme()->get_default_font(); + } + } + + // Lastly, fall back on the default Theme. + if (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) { + return ThemeDB::get_singleton()->get_default_theme()->get_default_font(); + } + return ThemeDB::get_singleton()->get_fallback_font(); +} + +int ThemeOwner::get_theme_default_font_size() { + // First, look through each control or window node in the branch, until no valid parent can be found. + // Only nodes with a theme resource attached are considered. + // For each theme resource see if their assigned theme has the default value defined and valid. + Node *owner_node = get_owner_node(); + + while (owner_node) { + Ref<Theme> owner_theme; + + Control *owner_c = Object::cast_to<Control>(owner_node); + if (owner_c) { + owner_theme = owner_c->get_theme(); + } + Window *owner_w = Object::cast_to<Window>(owner_node); + if (owner_w) { + owner_theme = owner_w->get_theme(); + } + + if (owner_theme.is_valid() && owner_theme->has_default_font_size()) { + return owner_theme->get_default_font_size(); + } + + owner_node = _get_next_owner_node(owner_node); + } + + // Secondly, check the project-defined Theme resource. + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + if (ThemeDB::get_singleton()->get_project_theme()->has_default_font_size()) { + return ThemeDB::get_singleton()->get_project_theme()->get_default_font_size(); + } + } + + // Lastly, fall back on the default Theme. + if (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) { + return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size(); + } + return ThemeDB::get_singleton()->get_fallback_font_size(); +} diff --git a/scene/theme/theme_owner.h b/scene/theme/theme_owner.h new file mode 100644 index 0000000000..59b72c1627 --- /dev/null +++ b/scene/theme/theme_owner.h @@ -0,0 +1,75 @@ +/*************************************************************************/ +/* theme_owner.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef THEME_OWNER_H +#define THEME_OWNER_H + +#include "core/object/object.h" +#include "scene/resources/theme.h" + +class Control; +class Node; +class Window; + +class ThemeOwner : public Object { + Control *owner_control = nullptr; + Window *owner_window = nullptr; + + Node *_get_next_owner_node(Node *p_from_node) const; + +public: + // Theme owner node. + + void set_owner_node(Node *p_node); + Node *get_owner_node() const; + bool has_owner_node() const; + + // Theme propagation. + + void assign_theme_on_parented(Node *p_for_node); + void clear_theme_on_unparented(Node *p_for_node); + void propagate_theme_changed(Node *p_to_node, Node *p_owner_node, bool p_notify, bool p_assign); + + // Theme lookup. + + void get_theme_type_dependencies(const Node *p_for_node, const StringName &p_theme_type, List<StringName> *r_list) const; + + Variant get_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); + bool has_theme_item_in_types(Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); + + float get_theme_default_base_scale(); + Ref<Font> get_theme_default_font(); + int get_theme_default_font_size(); + + ThemeOwner() {} + ~ThemeOwner() {} +}; + +#endif // THEME_OWNER_H |