diff options
Diffstat (limited to 'scene')
34 files changed, 861 insertions, 276 deletions
diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp index aa4ae01fd9..9c332123e3 100644 --- a/scene/2d/back_buffer_copy.cpp +++ b/scene/2d/back_buffer_copy.cpp @@ -71,12 +71,19 @@ Rect2 BackBufferCopy::get_rect() const { void BackBufferCopy::set_copy_mode(CopyMode p_mode) { copy_mode = p_mode; _update_copy_mode(); + notify_property_list_changed(); } BackBufferCopy::CopyMode BackBufferCopy::get_copy_mode() const { return copy_mode; } +void BackBufferCopy::_validate_property(PropertyInfo &p_property) const { + if (copy_mode != COPY_MODE_RECT && p_property.name == "rect") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } +} + void BackBufferCopy::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rect", "rect"), &BackBufferCopy::set_rect); ClassDB::bind_method(D_METHOD("get_rect"), &BackBufferCopy::get_rect); diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h index 1f2d5810b0..caacbc83c6 100644 --- a/scene/2d/back_buffer_copy.h +++ b/scene/2d/back_buffer_copy.h @@ -51,6 +51,7 @@ private: protected: static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; public: #ifdef TOOLS_ENABLED diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 4b31bbddac..229625ad6d 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -39,8 +39,11 @@ void Camera2D::_update_scroll() { } if (Engine::get_singleton()->is_editor_hint()) { - queue_redraw(); //will just be drawn - return; + queue_redraw(); + // Only set viewport transform when not bound to the main viewport. + if (get_viewport() == get_tree()->get_edited_scene_root()->get_viewport()) { + return; + } } if (!viewport) { diff --git a/scene/2d/navigation_link_2d.cpp b/scene/2d/navigation_link_2d.cpp index 3f7e10eaea..d639e1cc89 100644 --- a/scene/2d/navigation_link_2d.cpp +++ b/scene/2d/navigation_link_2d.cpp @@ -279,6 +279,8 @@ PackedStringArray NavigationLink2D::get_configuration_warnings() const { NavigationLink2D::NavigationLink2D() { link = NavigationServer2D::get_singleton()->link_create(); + NavigationServer2D::get_singleton()->link_set_owner_id(link, get_instance_id()); + set_notify_transform(true); } diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 13d371042b..7bf3eec79b 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -634,7 +634,9 @@ void NavigationRegion2D::_bind_methods() { NavigationRegion2D::NavigationRegion2D() { set_notify_transform(true); + region = NavigationServer2D::get_singleton()->region_create(); + NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id()); NavigationServer2D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); NavigationServer2D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 3876ab128c..823b8d56e3 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -120,7 +120,7 @@ void Path2D::_notification(int p_what) { Transform2D *w = frames.ptrw(); for (int i = 0; i < sample_count; i++) { - w[i] = curve->sample_baked_with_rotation(i * interval, true); + w[i] = curve->sample_baked_with_rotation(i * interval, false); } } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 0159e9f313..61f45114de 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -755,6 +755,7 @@ void TileMap::set_y_sort_enabled(bool p_enable) { _clear_internals(); _recreate_internals(); emit_signal(SNAME("changed")); + update_configuration_warnings(); } Vector2i TileMap::_coords_to_quadrant_coords(int p_layer, const Vector2i &p_coords) const { @@ -995,9 +996,11 @@ void TileMap::_recompute_rect_cache() { } } + bool changed = rect_cache != r_total; + rect_cache = r_total; - item_rect_changed(); + item_rect_changed(changed); rect_cache_dirty = false; #endif @@ -1733,6 +1736,7 @@ void TileMap::_navigation_update_dirty_quadrants(SelfList<TileMapQuadrant>::List tile_transform.set_origin(map_to_local(E_cell)); RID region = NavigationServer2D::get_singleton()->region_create(); + NavigationServer2D::get_singleton()->region_set_owner_id(region, get_instance_id()); NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); NavigationServer2D::get_singleton()->region_set_transform(region, tilemap_xform * tile_transform); NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); @@ -3838,7 +3842,7 @@ void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) { } } -TypedArray<Vector2i> TileMap::get_surrounding_tiles(Vector2i coords) { +TypedArray<Vector2i> TileMap::get_surrounding_cells(Vector2i coords) { if (!tile_set.is_valid()) { return TypedArray<Vector2i>(); } @@ -3955,6 +3959,22 @@ PackedStringArray TileMap::get_configuration_warnings() const { } } + if (tile_set.is_valid() && tile_set->get_tile_shape() == TileSet::TILE_SHAPE_ISOMETRIC) { + bool warn = !is_y_sort_enabled(); + if (!warn) { + for (int layer = 0; layer < (int)layers.size(); layer++) { + if (!layers[layer].y_sort_enabled) { + warn = true; + break; + } + } + } + + if (warn) { + warnings.push_back(RTR("Isometric TileSet will likely not look as intended without Y-sort enabled for the TileMap and all of its layers.")); + } + } + return warnings; } @@ -4012,7 +4032,7 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("force_update", "layer"), &TileMap::force_update, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("get_surrounding_tiles", "coords"), &TileMap::get_surrounding_tiles); + ClassDB::bind_method(D_METHOD("get_surrounding_cells", "coords"), &TileMap::get_surrounding_cells); 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); @@ -4051,6 +4071,7 @@ void TileMap::_tile_set_changed() { _tile_set_changed_deferred_update_needed = true; instantiated_scenes.clear(); call_deferred(SNAME("_tile_set_changed_deferred_update")); + update_configuration_warnings(); } void TileMap::_tile_set_changed_deferred_update() { @@ -4069,5 +4090,9 @@ TileMap::TileMap() { } TileMap::~TileMap() { + if (tile_set.is_valid()) { + tile_set->disconnect("changed", callable_mp(this, &TileMap::_tile_set_changed)); + } + _clear_internals(); } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 68a5d3c80b..19f0e5a553 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -400,7 +400,7 @@ public: void force_update(int p_layer = -1); // Helpers? - TypedArray<Vector2i> get_surrounding_tiles(Vector2i coords); + TypedArray<Vector2i> get_surrounding_cells(Vector2i coords); void draw_cells_outline(Control *p_control, RBSet<Vector2i> p_cells, Color p_color, Transform2D p_transform = Transform2D()); // Virtual function to modify the TileData at runtime diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index a02f322ef1..11b4718802 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -100,7 +100,7 @@ void TouchScreenButton::_notification(int p_what) { if (!is_inside_tree()) { return; } - 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) { + if (!Engine::get_singleton()->is_editor_hint() && !DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) { return; } @@ -137,7 +137,7 @@ void TouchScreenButton::_notification(int p_what) { } break; case NOTIFICATION_ENTER_TREE: { - if (!Engine::get_singleton()->is_editor_hint() && !!DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())) && visibility == VISIBILITY_TOUCHSCREEN_ONLY) { + if (!Engine::get_singleton()->is_editor_hint() && !DisplayServer::get_singleton()->is_touchscreen_available() && visibility == VISIBILITY_TOUCHSCREEN_ONLY) { return; } queue_redraw(); diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 304e56326d..2a50575749 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -112,6 +112,12 @@ void Camera3D::_notification(int p_what) { if (current || first_camera) { viewport->_camera_3d_set(this); } + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + viewport->connect(SNAME("size_changed"), callable_mp((Node3D *)this, &Camera3D::update_gizmos)); + } +#endif } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -133,6 +139,11 @@ void Camera3D::_notification(int p_what) { } if (viewport) { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + viewport->disconnect(SNAME("size_changed"), callable_mp((Node3D *)this, &Camera3D::update_gizmos)); + } +#endif viewport->_camera_3d_remove(this); viewport = nullptr; } diff --git a/scene/3d/navigation_link_3d.cpp b/scene/3d/navigation_link_3d.cpp index 78fe4754ea..bee7c7f39b 100644 --- a/scene/3d/navigation_link_3d.cpp +++ b/scene/3d/navigation_link_3d.cpp @@ -221,6 +221,8 @@ void NavigationLink3D::_notification(int p_what) { NavigationLink3D::NavigationLink3D() { link = NavigationServer3D::get_singleton()->link_create(); + NavigationServer3D::get_singleton()->link_set_owner_id(link, get_instance_id()); + set_notify_transform(true); } diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 06182d921c..bd96c55512 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -339,7 +339,9 @@ void NavigationRegion3D::_navigation_map_changed(RID p_map) { NavigationRegion3D::NavigationRegion3D() { set_notify_transform(true); + region = NavigationServer3D::get_singleton()->region_create(); + NavigationServer3D::get_singleton()->region_set_owner_id(region, get_instance_id()); NavigationServer3D::get_singleton()->region_set_enter_cost(region, get_enter_cost()); NavigationServer3D::get_singleton()->region_set_travel_cost(region, get_travel_cost()); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 1327bdd6e9..a60ccd2169 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -188,7 +188,7 @@ void Node3D::_notification(int p_what) { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { - get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SNAME("_request_gizmo_for_id"), get_instance_id()); } #endif } break; @@ -482,7 +482,7 @@ void Node3D::update_gizmos() { } if (data.gizmos.is_empty()) { - get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); + get_tree()->call_group_flags(SceneTree::GROUP_CALL_DEFERRED, SceneStringNames::get_singleton()->_spatial_editor_group, SNAME("_request_gizmo_for_id"), get_instance_id()); return; } if (data.gizmos_dirty) { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index f7baa7facc..cc6fadd9b2 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -956,8 +956,8 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double } if (player->is_playing()) { - player->play(anim_name); player->seek(at_anim_pos); + player->play(anim_name); nc->animation_playing = true; playing_caches.insert(nc); } else { @@ -985,8 +985,8 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double nc->animation_playing = false; } } else { + player->seek(0.0); player->play(anim_name); - player->seek(0.0, true); nc->animation_playing = true; playing_caches.insert(nc); } @@ -1001,6 +1001,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started) { double delta = p_delta * speed_scale * cd.speed_scale; double next_pos = cd.pos + delta; + bool backwards = signbit(delta); // Negative zero means playing backwards too. real_t len = cd.from->animation->get_length(); Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE; @@ -1012,23 +1013,7 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta, } else if (next_pos > len) { next_pos = len; } - - bool backwards = signbit(delta); // Negative zero means playing backwards too - delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here) - - if (&cd == &playback.current) { - if (!backwards && cd.pos <= len && next_pos == len) { - //playback finished - end_reached = true; - end_notify = cd.pos < len; // Notify only if not already at the end - } - - if (backwards && cd.pos >= 0 && next_pos == 0) { - //playback finished - end_reached = true; - end_notify = cd.pos > 0; // Notify only if not already at the beginning - } - } + delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here). } break; case Animation::LOOP_LINEAR: { @@ -1057,8 +1042,28 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta, break; } - _animation_process_animation(cd.from, cd.pos, next_pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started, looped_flag); + double prev_pos = cd.pos; // The animation may be changed during process, so it is safer that the state is changed before process. cd.pos = next_pos; + + AnimationData *prev_from = cd.from; + _animation_process_animation(cd.from, prev_pos, cd.pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started, looped_flag); + + // End detection. + if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) { + if (prev_from != playback.current.from) { + return; // Animation has been changed in the process (may be caused by method track), abort process. + } + if (!backwards && prev_pos <= len && next_pos == len) { + // Playback finished. + end_reached = true; + end_notify = prev_pos < len; // Notify only if not already at the end. + } + if (backwards && prev_pos >= 0 && next_pos == 0) { + // Playback finished. + end_reached = true; + end_notify = prev_pos > 0; // Notify only if not already at the beginning. + } + } } void AnimationPlayer::_animation_process2(double p_delta, bool p_started) { @@ -1066,23 +1071,25 @@ void AnimationPlayer::_animation_process2(double p_delta, bool p_started) { accum_pass++; - _animation_process_data(c.current, p_delta, 1.0f, c.seeked, p_started); + bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process. if (p_delta != 0) { c.seeked = false; } + _animation_process_data(c.current, p_delta, 1.0f, seeked, p_started); + List<Blend>::Element *prev = nullptr; for (List<Blend>::Element *E = c.blend.back(); E; E = prev) { Blend &b = E->get(); float blend = b.blend_left / b.blend_time; - _animation_process_data(b.data, p_delta, blend, false, false); - b.blend_left -= Math::absf(speed_scale * p_delta); - prev = E->prev(); if (b.blend_left < 0) { c.blend.erase(E); } + // The effect of animation changes during blending is unknown... + // In that case, we recommends to use method call mode "deferred", not "immediate". + _animation_process_data(b.data, p_delta, blend, false, false); } } @@ -1123,8 +1130,6 @@ void AnimationPlayer::_animation_update_transforms() { } } - cache_update_size = 0; - for (int i = 0; i < cache_update_prop_size; i++) { TrackNodeCache::PropertyAnim *pa = cache_update_prop[i]; @@ -1186,29 +1191,35 @@ void AnimationPlayer::_animation_update_transforms() { } } - cache_update_prop_size = 0; - for (int i = 0; i < cache_update_bezier_size; i++) { TrackNodeCache::BezierAnim *ba = cache_update_bezier[i]; ERR_CONTINUE(ba->accum_pass != accum_pass); ba->object->set_indexed(ba->bezier_property, ba->bezier_accum); } - - cache_update_bezier_size = 0; } void AnimationPlayer::_animation_process(double p_delta) { if (playback.current.from) { end_reached = false; end_notify = false; - _animation_process2(p_delta, playback.started); + bool started = playback.started; // The animation may be changed during process, so it is safer that the state is changed before process. if (playback.started) { playback.started = false; } + cache_update_size = 0; + cache_update_prop_size = 0; + cache_update_bezier_size = 0; + + AnimationData *prev_from = playback.current.from; + _animation_process2(p_delta, started); + if (prev_from != playback.current.from) { + return; // Animation has been changed in the process (may be caused by method track), abort process. + } _animation_update_transforms(); + if (end_reached) { if (queued.size()) { String old = playback.assigned; @@ -2060,7 +2071,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) { old_values->restore(); Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo(); - ur->create_action(TTR("Anim Apply Reset")); + ur->create_action(TTR("Animation Apply Reset")); ur->add_do_method(new_values.ptr(), "restore"); ur->add_undo_method(old_values.ptr(), "restore"); ur->commit_action(); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index bd9b918900..fbc85bd5e1 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -1031,7 +1031,9 @@ void AnimationTree::_process_graph(double p_delta) { } NodePath path = a->track_get_path(i); - ERR_CONTINUE(!track_cache.has(path)); + if (!track_cache.has(path)) { + continue; // No path, but avoid error spamming. + } TrackCache *track = track_cache[path]; ERR_CONTINUE(!state.track_map.has(path)); @@ -1582,8 +1584,8 @@ void AnimationTree::_process_graph(double p_delta) { } if (player2->is_playing() || seeked) { - player2->play(anim_name); player2->seek(at_anim_pos); + player2->play(anim_name); t->playing = true; playing_caches.insert(t); } else { diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index 35ba49563c..28eedcbe13 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -220,8 +220,12 @@ void SceneDebugger::_save_node(ObjectID id, const String &p_path) { Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id)); ERR_FAIL_COND(!node); +#ifdef TOOLS_ENABLED HashMap<const Node *, Node *> duplimap; Node *copy = node->duplicate_from_editor(duplimap); +#else + Node *copy = node->duplicate(); +#endif // Handle Unique Nodes. for (int i = 0; i < copy->get_child_count(false); i++) { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index e90a6a69ab..50ffc0509c 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -257,36 +257,36 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) { if (p_value.get_type() == Variant::NIL || (p_value.get_type() == Variant::OBJECT && (Object *)p_value == nullptr)) { if (name.begins_with("theme_override_icons/")) { String dname = name.get_slicec('/', 1); - if (data.icon_override.has(dname)) { - data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_icon_override.has(dname)) { + data.theme_icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.icon_override.erase(dname); + data.theme_icon_override.erase(dname); _notify_theme_override_changed(); } else if (name.begins_with("theme_override_styles/")) { String dname = name.get_slicec('/', 1); - if (data.style_override.has(dname)) { - data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_style_override.has(dname)) { + data.theme_style_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.style_override.erase(dname); + data.theme_style_override.erase(dname); _notify_theme_override_changed(); } else if (name.begins_with("theme_override_fonts/")) { String dname = name.get_slicec('/', 1); - if (data.font_override.has(dname)) { - data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_font_override.has(dname)) { + data.theme_font_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.font_override.erase(dname); + data.theme_font_override.erase(dname); _notify_theme_override_changed(); } else if (name.begins_with("theme_override_font_sizes/")) { String dname = name.get_slicec('/', 1); - data.font_size_override.erase(dname); + data.theme_font_size_override.erase(dname); _notify_theme_override_changed(); } else if (name.begins_with("theme_override_colors/")) { String dname = name.get_slicec('/', 1); - data.color_override.erase(dname); + data.theme_color_override.erase(dname); _notify_theme_override_changed(); } else if (name.begins_with("theme_override_constants/")) { String dname = name.get_slicec('/', 1); - data.constant_override.erase(dname); + data.theme_constant_override.erase(dname); _notify_theme_override_changed(); } else { return false; @@ -326,22 +326,22 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const { if (sname.begins_with("theme_override_icons/")) { String name = sname.get_slicec('/', 1); - r_ret = data.icon_override.has(name) ? Variant(data.icon_override[name]) : Variant(); + r_ret = data.theme_icon_override.has(name) ? Variant(data.theme_icon_override[name]) : Variant(); } else if (sname.begins_with("theme_override_styles/")) { String name = sname.get_slicec('/', 1); - r_ret = data.style_override.has(name) ? Variant(data.style_override[name]) : Variant(); + r_ret = data.theme_style_override.has(name) ? Variant(data.theme_style_override[name]) : Variant(); } else if (sname.begins_with("theme_override_fonts/")) { String name = sname.get_slicec('/', 1); - r_ret = data.font_override.has(name) ? Variant(data.font_override[name]) : Variant(); + r_ret = data.theme_font_override.has(name) ? Variant(data.theme_font_override[name]) : Variant(); } else if (sname.begins_with("theme_override_font_sizes/")) { String name = sname.get_slicec('/', 1); - r_ret = data.font_size_override.has(name) ? Variant(data.font_size_override[name]) : Variant(); + r_ret = data.theme_font_size_override.has(name) ? Variant(data.theme_font_size_override[name]) : Variant(); } else if (sname.begins_with("theme_override_colors/")) { String name = sname.get_slicec('/', 1); - r_ret = data.color_override.has(name) ? Variant(data.color_override[name]) : Variant(); + r_ret = data.theme_color_override.has(name) ? Variant(data.theme_color_override[name]) : Variant(); } else if (sname.begins_with("theme_override_constants/")) { String name = sname.get_slicec('/', 1); - r_ret = data.constant_override.has(name) ? Variant(data.constant_override[name]) : Variant(); + r_ret = data.theme_constant_override.has(name) ? Variant(data.theme_constant_override[name]) : Variant(); } else { return false; } @@ -350,16 +350,16 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const { } void Control::_get_property_list(List<PropertyInfo> *p_list) const { - Ref<Theme> theme = ThemeDB::get_singleton()->get_default_theme(); + Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme(); p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP)); { List<StringName> names; - theme->get_color_list(get_class_name(), &names); + default_theme->get_color_list(get_class_name(), &names); for (const StringName &E : names) { uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - if (data.color_override.has(E)) { + if (data.theme_color_override.has(E)) { usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; } @@ -368,10 +368,10 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const { } { List<StringName> names; - theme->get_constant_list(get_class_name(), &names); + default_theme->get_constant_list(get_class_name(), &names); for (const StringName &E : names) { uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - if (data.constant_override.has(E)) { + if (data.theme_constant_override.has(E)) { usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; } @@ -380,10 +380,10 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const { } { List<StringName> names; - theme->get_font_list(get_class_name(), &names); + default_theme->get_font_list(get_class_name(), &names); for (const StringName &E : names) { uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - if (data.font_override.has(E)) { + if (data.theme_font_override.has(E)) { usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; } @@ -392,10 +392,10 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const { } { List<StringName> names; - theme->get_font_size_list(get_class_name(), &names); + default_theme->get_font_size_list(get_class_name(), &names); for (const StringName &E : names) { uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - if (data.font_size_override.has(E)) { + if (data.theme_font_size_override.has(E)) { usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; } @@ -404,10 +404,10 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const { } { List<StringName> names; - theme->get_icon_list(get_class_name(), &names); + default_theme->get_icon_list(get_class_name(), &names); for (const StringName &E : names) { uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - if (data.icon_override.has(E)) { + if (data.theme_icon_override.has(E)) { usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; } @@ -416,10 +416,10 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const { } { List<StringName> names; - theme->get_stylebox_list(get_class_name(), &names); + default_theme->get_stylebox_list(get_class_name(), &names); for (const StringName &E : names) { uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; - if (data.style_override.has(E)) { + if (data.theme_style_override.has(E)) { usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; } @@ -2381,7 +2381,7 @@ StringName Control::get_theme_type_variation() const { 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); + const Ref<Texture2D> *tex = data.theme_icon_override.getptr(p_name); if (tex) { return *tex; } @@ -2400,7 +2400,7 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam Ref<StyleBox> Control::get_theme_stylebox(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<StyleBox> *style = data.style_override.getptr(p_name); + const Ref<StyleBox> *style = data.theme_style_override.getptr(p_name); if (style) { return *style; } @@ -2419,7 +2419,7 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String Ref<Font> Control::get_theme_font(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<Font> *font = data.font_override.getptr(p_name); + const Ref<Font> *font = data.theme_font_override.getptr(p_name); if (font) { return *font; } @@ -2438,7 +2438,7 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_ int Control::get_theme_font_size(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 int *font_size = data.font_size_override.getptr(p_name); + const int *font_size = data.theme_font_size_override.getptr(p_name); if (font_size && (*font_size) > 0) { return *font_size; } @@ -2457,7 +2457,7 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t Color Control::get_theme_color(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 Color *color = data.color_override.getptr(p_name); + const Color *color = data.theme_color_override.getptr(p_name); if (color) { return *color; } @@ -2476,7 +2476,7 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the int Control::get_theme_constant(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 int *constant = data.constant_override.getptr(p_name); + const int *constant = data.theme_constant_override.getptr(p_name); if (constant) { return *constant; } @@ -2570,123 +2570,123 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t void Control::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) { ERR_FAIL_COND(!p_icon.is_valid()); - if (data.icon_override.has(p_name)) { - data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_icon_override.has(p_name)) { + data.theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.icon_override[p_name] = p_icon; - data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + data.theme_icon_override[p_name] = p_icon; + data.theme_icon_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); _notify_theme_override_changed(); } void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { ERR_FAIL_COND(!p_style.is_valid()); - if (data.style_override.has(p_name)) { - data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_style_override.has(p_name)) { + data.theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.style_override[p_name] = p_style; - data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + data.theme_style_override[p_name] = p_style; + data.theme_style_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); _notify_theme_override_changed(); } void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) { ERR_FAIL_COND(!p_font.is_valid()); - if (data.font_override.has(p_name)) { - data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_font_override.has(p_name)) { + data.theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.font_override[p_name] = p_font; - data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + data.theme_font_override[p_name] = p_font; + data.theme_font_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); _notify_theme_override_changed(); } void Control::add_theme_font_size_override(const StringName &p_name, int p_font_size) { - data.font_size_override[p_name] = p_font_size; + data.theme_font_size_override[p_name] = p_font_size; _notify_theme_override_changed(); } void Control::add_theme_color_override(const StringName &p_name, const Color &p_color) { - data.color_override[p_name] = p_color; + data.theme_color_override[p_name] = p_color; _notify_theme_override_changed(); } void Control::add_theme_constant_override(const StringName &p_name, int p_constant) { - data.constant_override[p_name] = p_constant; + data.theme_constant_override[p_name] = p_constant; _notify_theme_override_changed(); } void Control::remove_theme_icon_override(const StringName &p_name) { - if (data.icon_override.has(p_name)) { - data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_icon_override.has(p_name)) { + data.theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.icon_override.erase(p_name); + data.theme_icon_override.erase(p_name); _notify_theme_override_changed(); } void Control::remove_theme_style_override(const StringName &p_name) { - if (data.style_override.has(p_name)) { - data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_style_override.has(p_name)) { + data.theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.style_override.erase(p_name); + data.theme_style_override.erase(p_name); _notify_theme_override_changed(); } void Control::remove_theme_font_override(const StringName &p_name) { - if (data.font_override.has(p_name)) { - data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); + if (data.theme_font_override.has(p_name)) { + data.theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - data.font_override.erase(p_name); + data.theme_font_override.erase(p_name); _notify_theme_override_changed(); } void Control::remove_theme_font_size_override(const StringName &p_name) { - data.font_size_override.erase(p_name); + data.theme_font_size_override.erase(p_name); _notify_theme_override_changed(); } void Control::remove_theme_color_override(const StringName &p_name) { - data.color_override.erase(p_name); + data.theme_color_override.erase(p_name); _notify_theme_override_changed(); } void Control::remove_theme_constant_override(const StringName &p_name) { - data.constant_override.erase(p_name); + data.theme_constant_override.erase(p_name); _notify_theme_override_changed(); } bool Control::has_theme_icon_override(const StringName &p_name) const { - const Ref<Texture2D> *tex = data.icon_override.getptr(p_name); + const Ref<Texture2D> *tex = data.theme_icon_override.getptr(p_name); return tex != nullptr; } bool Control::has_theme_stylebox_override(const StringName &p_name) const { - const Ref<StyleBox> *style = data.style_override.getptr(p_name); + const Ref<StyleBox> *style = data.theme_style_override.getptr(p_name); return style != nullptr; } bool Control::has_theme_font_override(const StringName &p_name) const { - const Ref<Font> *font = data.font_override.getptr(p_name); + const Ref<Font> *font = data.theme_font_override.getptr(p_name); return font != nullptr; } bool Control::has_theme_font_size_override(const StringName &p_name) const { - const int *font_size = data.font_size_override.getptr(p_name); + const int *font_size = data.theme_font_size_override.getptr(p_name); return font_size != nullptr; } bool Control::has_theme_color_override(const StringName &p_name) const { - const Color *color = data.color_override.getptr(p_name); + const Color *color = data.theme_color_override.getptr(p_name); return color != nullptr; } bool Control::has_theme_constant_override(const StringName &p_name) const { - const int *constant = data.constant_override.getptr(p_name); + const int *constant = data.theme_constant_override.getptr(p_name); return constant != nullptr; } @@ -3359,21 +3359,21 @@ Control::~Control() { memdelete(data.theme_owner); // Resources need to be disconnected. - for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) { + for (KeyValue<StringName, Ref<Texture2D>> &E : data.theme_icon_override) { E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - for (KeyValue<StringName, Ref<StyleBox>> &E : data.style_override) { + for (KeyValue<StringName, Ref<StyleBox>> &E : data.theme_style_override) { E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } - for (KeyValue<StringName, Ref<Font>> &E : data.font_override) { + for (KeyValue<StringName, Ref<Font>> &E : data.theme_font_override) { E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed)); } // Then override maps can be simply cleared. - data.icon_override.clear(); - data.style_override.clear(); - data.font_override.clear(); - data.font_size_override.clear(); - data.color_override.clear(); - data.constant_override.clear(); + data.theme_icon_override.clear(); + data.theme_style_override.clear(); + data.theme_font_override.clear(); + data.theme_font_size_override.clear(); + data.theme_color_override.clear(); + data.theme_constant_override.clear(); } diff --git a/scene/gui/control.h b/scene/gui/control.h index 3e9bb48a4a..12710f3a93 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -228,12 +228,12 @@ private: StringName theme_type_variation; bool bulk_theme_override = false; - Theme::ThemeIconMap icon_override; - Theme::ThemeStyleMap style_override; - Theme::ThemeFontMap font_override; - Theme::ThemeFontSizeMap font_size_override; - Theme::ThemeColorMap color_override; - Theme::ThemeConstantMap constant_override; + Theme::ThemeIconMap theme_icon_override; + Theme::ThemeStyleMap theme_style_override; + Theme::ThemeFontMap theme_font_override; + Theme::ThemeFontSizeMap theme_font_size_override; + Theme::ThemeColorMap theme_color_override; + Theme::ThemeConstantMap theme_constant_override; mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache; mutable HashMap<StringName, Theme::ThemeStyleMap> theme_style_cache; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index ab74979777..5d8e106e26 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -221,7 +221,7 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) { Rect2 safe_area = this_rect; 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; + safe_area.size.y = items[p_over]._height_cache + theme_cache.v_separation; DisplayServer::get_singleton()->window_set_popup_safe_rect(submenu_popup->get_window_id(), safe_area); // Make the position of the parent popup relative to submenu popup. diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index 66b8a21760..886442bc80 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -79,7 +79,7 @@ public: uint32_t get_glyph_index() const { return glyph_index; }; void set_glyph_index(uint32_t p_glyph_index) { glyph_index = p_glyph_index; }; - uint16_t get_glyph_flags() const { return glyph_index; }; + uint16_t get_glyph_flags() const { return glyph_flags; }; void set_glyph_flags(uint16_t p_glyph_flags) { glyph_flags = p_glyph_flags; }; uint8_t get_glyph_count() const { return glyph_count; }; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 60d107cce6..f26e05518e 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1854,10 +1854,6 @@ void RichTextLabel::_notification(int p_what) { } Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const { - if (!underline_meta) { - return get_default_cursor_shape(); - } - if (selection.click_item) { return CURSOR_IBEAM; } diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 6899178885..a44ddff507 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -550,7 +550,7 @@ void ScrollBar::_drag_node_input(const Ref<InputEvent> &p_input) { drag_node_accum = Vector2(); last_drag_node_accum = Vector2(); drag_node_from = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0); - drag_node_touching = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); + drag_node_touching = DisplayServer::get_singleton()->is_touchscreen_available(); drag_node_touching_deaccel = false; time_since_motion = 0; diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 531226f938..73d30b7568 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -164,8 +164,8 @@ void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) { } } - bool screen_is_touchscreen = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); - if (!screen_is_touchscreen) { + bool is_touchscreen_available = DisplayServer::get_singleton()->is_touchscreen_available(); + if (!is_touchscreen_available) { return; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index c0990211aa..35cc29d080 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2471,6 +2471,8 @@ bool Tree::_is_sibling_branch_selected(TreeItem *p_from) const { } void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev, bool *r_in_range, bool p_force_deselect) { + popup_editor->hide(); + TreeItem::Cell &selected_cell = p_selected->cells.write[p_col]; bool switched = false; @@ -3671,7 +3673,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { drag_accum = 0; //last_drag_accum=0; drag_from = v_scroll->get_value(); - drag_touching = DisplayServer::get_singleton()->screen_is_touchscreen(DisplayServer::get_singleton()->window_get_current_screen(get_viewport()->get_window_id())); + drag_touching = DisplayServer::get_singleton()->is_touchscreen_available(); drag_touching_deaccel = false; if (drag_touching) { set_physics_process_internal(true); @@ -4216,7 +4218,9 @@ Tree::SelectMode Tree::get_select_mode() const { void Tree::deselect_all() { TreeItem *item = get_next_selected(get_root()); while (item) { - item->deselect(selected_col); + for (int i = 0; i < columns.size(); i++) { + item->deselect(i); + } TreeItem *prev_item = item; item = get_next_selected(get_root()); ERR_FAIL_COND(item == prev_item); diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h index 4b5909538e..fa6b11e5db 100644 --- a/scene/main/multiplayer_peer.h +++ b/scene/main/multiplayer_peer.h @@ -112,11 +112,11 @@ protected: public: /* PacketPeer extension */ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet - GDVIRTUAL2R(Error, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>); + GDVIRTUAL2R(Error, _get_packet, GDExtensionConstPtr<const uint8_t *>, GDExtensionPtr<int>); GDVIRTUAL0R(PackedByteArray, _get_packet_script); // For GDScript. virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override; - GDVIRTUAL2R(Error, _put_packet, GDNativeConstPtr<const uint8_t>, int); + GDVIRTUAL2R(Error, _put_packet, GDExtensionConstPtr<const uint8_t>, int); GDVIRTUAL1R(Error, _put_packet_script, PackedByteArray); // For GDScript. EXBIND0RC(int, get_available_packet_count); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index aff2c594d9..c71c3e195b 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -40,6 +40,218 @@ #include "scene/theme/theme_db.h" #include "scene/theme/theme_owner.h" +// Dynamic properties. + +bool Window::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + if (!name.begins_with("theme_override")) { + return false; + } + + if (p_value.get_type() == Variant::NIL || (p_value.get_type() == Variant::OBJECT && (Object *)p_value == nullptr)) { + if (name.begins_with("theme_override_icons/")) { + String dname = name.get_slicec('/', 1); + if (theme_icon_override.has(dname)) { + theme_icon_override[dname]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + theme_icon_override.erase(dname); + _notify_theme_override_changed(); + } else if (name.begins_with("theme_override_styles/")) { + String dname = name.get_slicec('/', 1); + if (theme_style_override.has(dname)) { + theme_style_override[dname]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + theme_style_override.erase(dname); + _notify_theme_override_changed(); + } else if (name.begins_with("theme_override_fonts/")) { + String dname = name.get_slicec('/', 1); + if (theme_font_override.has(dname)) { + theme_font_override[dname]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + theme_font_override.erase(dname); + _notify_theme_override_changed(); + } else if (name.begins_with("theme_override_font_sizes/")) { + String dname = name.get_slicec('/', 1); + theme_font_size_override.erase(dname); + _notify_theme_override_changed(); + } else if (name.begins_with("theme_override_colors/")) { + String dname = name.get_slicec('/', 1); + theme_color_override.erase(dname); + _notify_theme_override_changed(); + } else if (name.begins_with("theme_override_constants/")) { + String dname = name.get_slicec('/', 1); + theme_constant_override.erase(dname); + _notify_theme_override_changed(); + } else { + return false; + } + + } else { + if (name.begins_with("theme_override_icons/")) { + String dname = name.get_slicec('/', 1); + add_theme_icon_override(dname, p_value); + } else if (name.begins_with("theme_override_styles/")) { + String dname = name.get_slicec('/', 1); + add_theme_style_override(dname, p_value); + } else if (name.begins_with("theme_override_fonts/")) { + String dname = name.get_slicec('/', 1); + add_theme_font_override(dname, p_value); + } else if (name.begins_with("theme_override_font_sizes/")) { + String dname = name.get_slicec('/', 1); + add_theme_font_size_override(dname, p_value); + } else if (name.begins_with("theme_override_colors/")) { + String dname = name.get_slicec('/', 1); + add_theme_color_override(dname, p_value); + } else if (name.begins_with("theme_override_constants/")) { + String dname = name.get_slicec('/', 1); + add_theme_constant_override(dname, p_value); + } else { + return false; + } + } + return true; +} + +bool Window::_get(const StringName &p_name, Variant &r_ret) const { + String sname = p_name; + if (!sname.begins_with("theme_override")) { + return false; + } + + if (sname.begins_with("theme_override_icons/")) { + String name = sname.get_slicec('/', 1); + r_ret = theme_icon_override.has(name) ? Variant(theme_icon_override[name]) : Variant(); + } else if (sname.begins_with("theme_override_styles/")) { + String name = sname.get_slicec('/', 1); + r_ret = theme_style_override.has(name) ? Variant(theme_style_override[name]) : Variant(); + } else if (sname.begins_with("theme_override_fonts/")) { + String name = sname.get_slicec('/', 1); + r_ret = theme_font_override.has(name) ? Variant(theme_font_override[name]) : Variant(); + } else if (sname.begins_with("theme_override_font_sizes/")) { + String name = sname.get_slicec('/', 1); + r_ret = theme_font_size_override.has(name) ? Variant(theme_font_size_override[name]) : Variant(); + } else if (sname.begins_with("theme_override_colors/")) { + String name = sname.get_slicec('/', 1); + r_ret = theme_color_override.has(name) ? Variant(theme_color_override[name]) : Variant(); + } else if (sname.begins_with("theme_override_constants/")) { + String name = sname.get_slicec('/', 1); + r_ret = theme_constant_override.has(name) ? Variant(theme_constant_override[name]) : Variant(); + } else { + return false; + } + + return true; +} + +void Window::_get_property_list(List<PropertyInfo> *p_list) const { + Ref<Theme> default_theme = ThemeDB::get_singleton()->get_default_theme(); + + p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP)); + + { + List<StringName> names; + default_theme->get_color_list(get_class_name(), &names); + for (const StringName &E : names) { + uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; + if (theme_color_override.has(E)) { + usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; + } + + p_list->push_back(PropertyInfo(Variant::COLOR, "theme_override_colors/" + E, PROPERTY_HINT_NONE, "", usage)); + } + } + { + List<StringName> names; + default_theme->get_constant_list(get_class_name(), &names); + for (const StringName &E : names) { + uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; + if (theme_constant_override.has(E)) { + usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; + } + + p_list->push_back(PropertyInfo(Variant::INT, "theme_override_constants/" + E, PROPERTY_HINT_RANGE, "-16384,16384", usage)); + } + } + { + List<StringName> names; + default_theme->get_font_list(get_class_name(), &names); + for (const StringName &E : names) { + uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; + if (theme_font_override.has(E)) { + usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; + } + + p_list->push_back(PropertyInfo(Variant::OBJECT, "theme_override_fonts/" + E, PROPERTY_HINT_RESOURCE_TYPE, "Font", usage)); + } + } + { + List<StringName> names; + default_theme->get_font_size_list(get_class_name(), &names); + for (const StringName &E : names) { + uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; + if (theme_font_size_override.has(E)) { + usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; + } + + p_list->push_back(PropertyInfo(Variant::INT, "theme_override_font_sizes/" + E, PROPERTY_HINT_RANGE, "1,256,1,or_greater,suffix:px", usage)); + } + } + { + List<StringName> names; + default_theme->get_icon_list(get_class_name(), &names); + for (const StringName &E : names) { + uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; + if (theme_icon_override.has(E)) { + usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; + } + + p_list->push_back(PropertyInfo(Variant::OBJECT, "theme_override_icons/" + E, PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", usage)); + } + } + { + List<StringName> names; + default_theme->get_stylebox_list(get_class_name(), &names); + for (const StringName &E : names) { + uint32_t usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CHECKABLE; + if (theme_style_override.has(E)) { + usage |= PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_CHECKED; + } + + p_list->push_back(PropertyInfo(Variant::OBJECT, "theme_override_styles/" + E, PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", usage)); + } + } +} + +void Window::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "theme_type_variation") { + List<StringName> names; + + // Only the default theme and the project theme are used for the list of options. + // This is an imposed limitation to simplify the logic needed to leverage those options. + ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names); + if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { + ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names); + } + names.sort_custom<StringName::AlphCompare>(); + + Vector<StringName> unique_names; + String hint_string; + for (const StringName &E : names) { + // Skip duplicate values. + if (unique_names.has(E)) { + continue; + } + + hint_string += String(E) + ","; + unique_names.append(E); + } + + p_property.hint_string = hint_string; + } +} + +// + void Window::set_title(const String &p_title) { title = p_title; @@ -106,9 +318,16 @@ void Window::reset_size() { set_size(Size2i()); } -Size2i Window::get_real_size() const { +Point2i Window::get_position_with_decorations() const { + if (window_id != DisplayServer::INVALID_WINDOW_ID) { + return DisplayServer::get_singleton()->window_get_position_with_decorations(window_id); + } + return position; +} + +Size2i Window::get_size_with_decorations() const { if (window_id != DisplayServer::INVALID_WINDOW_ID) { - return DisplayServer::get_singleton()->window_get_real_size(window_id); + return DisplayServer::get_singleton()->window_get_size_with_decorations(window_id); } return size; } @@ -1316,6 +1535,8 @@ void Window::remove_child_notify(Node *p_child) { } } +// Theming. + void Window::set_theme_owner_node(Node *p_node) { theme_owner->set_owner_node(p_node); } @@ -1369,6 +1590,12 @@ void Window::_theme_changed() { } } +void Window::_notify_theme_override_changed() { + if (!bulk_theme_override && is_inside_tree()) { + notification(NOTIFICATION_THEME_CHANGED); + } +} + void Window::_invalidate_theme_cache() { theme_icon_cache.clear(); theme_style_cache.clear(); @@ -1379,6 +1606,9 @@ void Window::_invalidate_theme_cache() { } void Window::_update_theme_item_cache() { + // Request an update on the next frame to reflect theme changes. + // Updating without a delay can cause a lot of lag. + child_controls_changed(); } void Window::set_theme_type_variation(const StringName &p_theme_type) { @@ -1392,7 +1622,16 @@ StringName Window::get_theme_type_variation() const { return theme_type_variation; } +/// Theme property lookup. + Ref<Texture2D> Window::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 == theme_type_variation) { + const Ref<Texture2D> *tex = theme_icon_override.getptr(p_name); + if (tex) { + return *tex; + } + } + 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]; } @@ -1405,6 +1644,13 @@ Ref<Texture2D> Window::get_theme_icon(const StringName &p_name, const StringName } Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + const Ref<StyleBox> *style = theme_style_override.getptr(p_name); + if (style) { + return *style; + } + } + 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]; } @@ -1417,6 +1663,13 @@ Ref<StyleBox> Window::get_theme_stylebox(const StringName &p_name, const StringN } Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + const Ref<Font> *font = theme_font_override.getptr(p_name); + if (font) { + return *font; + } + } + 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]; } @@ -1429,6 +1682,13 @@ Ref<Font> Window::get_theme_font(const StringName &p_name, const StringName &p_t } int Window::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + const int *font_size = theme_font_size_override.getptr(p_name); + if (font_size && (*font_size) > 0) { + return *font_size; + } + } + 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]; } @@ -1441,6 +1701,13 @@ int Window::get_theme_font_size(const StringName &p_name, const StringName &p_th } Color Window::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + const Color *color = theme_color_override.getptr(p_name); + if (color) { + return *color; + } + } + 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]; } @@ -1453,6 +1720,13 @@ Color Window::get_theme_color(const StringName &p_name, const StringName &p_them } int Window::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + const int *constant = theme_constant_override.getptr(p_name); + if (constant) { + return *constant; + } + } + 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]; } @@ -1465,41 +1739,204 @@ int Window::get_theme_constant(const StringName &p_name, const StringName &p_the } bool Window::has_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 == theme_type_variation) { + if (has_theme_icon_override(p_name)) { + return true; + } + } + List<StringName> 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 { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + if (has_theme_stylebox_override(p_name)) { + return true; + } + } + List<StringName> 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 { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + if (has_theme_font_override(p_name)) { + return true; + } + } + List<StringName> 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 { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + if (has_theme_font_size_override(p_name)) { + return true; + } + } + List<StringName> 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 { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + if (has_theme_color_override(p_name)) { + return true; + } + } + List<StringName> 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 { + if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) { + if (has_theme_constant_override(p_name)) { + return true; + } + } + List<StringName> 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); } +/// Local property overrides. + +void Window::add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon) { + ERR_FAIL_COND(!p_icon.is_valid()); + + if (theme_icon_override.has(p_name)) { + theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + + theme_icon_override[p_name] = p_icon; + theme_icon_override[p_name]->connect("changed", callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + _notify_theme_override_changed(); +} + +void Window::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) { + ERR_FAIL_COND(!p_style.is_valid()); + + if (theme_style_override.has(p_name)) { + theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + + theme_style_override[p_name] = p_style; + theme_style_override[p_name]->connect("changed", callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + _notify_theme_override_changed(); +} + +void Window::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) { + ERR_FAIL_COND(!p_font.is_valid()); + + if (theme_font_override.has(p_name)) { + theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + + theme_font_override[p_name] = p_font; + theme_font_override[p_name]->connect("changed", callable_mp(this, &Window::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED); + _notify_theme_override_changed(); +} + +void Window::add_theme_font_size_override(const StringName &p_name, int p_font_size) { + theme_font_size_override[p_name] = p_font_size; + _notify_theme_override_changed(); +} + +void Window::add_theme_color_override(const StringName &p_name, const Color &p_color) { + theme_color_override[p_name] = p_color; + _notify_theme_override_changed(); +} + +void Window::add_theme_constant_override(const StringName &p_name, int p_constant) { + theme_constant_override[p_name] = p_constant; + _notify_theme_override_changed(); +} + +void Window::remove_theme_icon_override(const StringName &p_name) { + if (theme_icon_override.has(p_name)) { + theme_icon_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + + theme_icon_override.erase(p_name); + _notify_theme_override_changed(); +} + +void Window::remove_theme_style_override(const StringName &p_name) { + if (theme_style_override.has(p_name)) { + theme_style_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + + theme_style_override.erase(p_name); + _notify_theme_override_changed(); +} + +void Window::remove_theme_font_override(const StringName &p_name) { + if (theme_font_override.has(p_name)) { + theme_font_override[p_name]->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + + theme_font_override.erase(p_name); + _notify_theme_override_changed(); +} + +void Window::remove_theme_font_size_override(const StringName &p_name) { + theme_font_size_override.erase(p_name); + _notify_theme_override_changed(); +} + +void Window::remove_theme_color_override(const StringName &p_name) { + theme_color_override.erase(p_name); + _notify_theme_override_changed(); +} + +void Window::remove_theme_constant_override(const StringName &p_name) { + theme_constant_override.erase(p_name); + _notify_theme_override_changed(); +} + +bool Window::has_theme_icon_override(const StringName &p_name) const { + const Ref<Texture2D> *tex = theme_icon_override.getptr(p_name); + return tex != nullptr; +} + +bool Window::has_theme_stylebox_override(const StringName &p_name) const { + const Ref<StyleBox> *style = theme_style_override.getptr(p_name); + return style != nullptr; +} + +bool Window::has_theme_font_override(const StringName &p_name) const { + const Ref<Font> *font = theme_font_override.getptr(p_name); + return font != nullptr; +} + +bool Window::has_theme_font_size_override(const StringName &p_name) const { + const int *font_size = theme_font_size_override.getptr(p_name); + return font_size != nullptr; +} + +bool Window::has_theme_color_override(const StringName &p_name) const { + const Color *color = theme_color_override.getptr(p_name); + return color != nullptr; +} + +bool Window::has_theme_constant_override(const StringName &p_name) const { + const int *constant = theme_constant_override.getptr(p_name); + return constant != nullptr; +} + +/// Default theme properties. + float Window::get_theme_default_base_scale() const { return theme_owner->get_theme_default_base_scale(); } @@ -1512,6 +1949,21 @@ int Window::get_theme_default_font_size() const { return theme_owner->get_theme_default_font_size(); } +/// Bulk actions. + +void Window::begin_bulk_theme_override() { + bulk_theme_override = true; +} + +void Window::end_bulk_theme_override() { + ERR_FAIL_COND(!bulk_theme_override); + + bulk_theme_override = false; + _notify_theme_override_changed(); +} + +// + Rect2i Window::get_parent_rect() const { ERR_FAIL_COND_V(!is_inside_tree(), Rect2i()); if (is_embedded()) { @@ -1604,34 +2056,6 @@ bool Window::is_auto_translating() const { return auto_translate; } -void Window::_validate_property(PropertyInfo &p_property) const { - if (p_property.name == "theme_type_variation") { - List<StringName> names; - - // Only the default theme and the project theme are used for the list of options. - // This is an imposed limitation to simplify the logic needed to leverage those options. - ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names); - if (ThemeDB::get_singleton()->get_project_theme().is_valid()) { - ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names); - } - names.sort_custom<StringName::AlphCompare>(); - - Vector<StringName> unique_names; - String hint_string; - for (const StringName &E : names) { - // Skip duplicate values. - if (unique_names.has(E)) { - continue; - } - - hint_string += String(E) + ","; - unique_names.append(E); - } - - p_property.hint_string = hint_string; - } -} - Transform2D Window::get_screen_transform() const { Transform2D embedder_transform; if (_get_embedder()) { @@ -1655,7 +2079,8 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size); ClassDB::bind_method(D_METHOD("reset_size"), &Window::reset_size); - ClassDB::bind_method(D_METHOD("get_real_size"), &Window::get_real_size); + ClassDB::bind_method(D_METHOD("get_position_with_decorations"), &Window::get_position_with_decorations); + ClassDB::bind_method(D_METHOD("get_size_with_decorations"), &Window::get_size_with_decorations); ClassDB::bind_method(D_METHOD("set_max_size", "max_size"), &Window::set_max_size); ClassDB::bind_method(D_METHOD("get_max_size"), &Window::get_max_size); @@ -1725,6 +2150,23 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("set_theme_type_variation", "theme_type"), &Window::set_theme_type_variation); ClassDB::bind_method(D_METHOD("get_theme_type_variation"), &Window::get_theme_type_variation); + ClassDB::bind_method(D_METHOD("begin_bulk_theme_override"), &Window::begin_bulk_theme_override); + ClassDB::bind_method(D_METHOD("end_bulk_theme_override"), &Window::end_bulk_theme_override); + + ClassDB::bind_method(D_METHOD("add_theme_icon_override", "name", "texture"), &Window::add_theme_icon_override); + ClassDB::bind_method(D_METHOD("add_theme_stylebox_override", "name", "stylebox"), &Window::add_theme_style_override); + ClassDB::bind_method(D_METHOD("add_theme_font_override", "name", "font"), &Window::add_theme_font_override); + ClassDB::bind_method(D_METHOD("add_theme_font_size_override", "name", "font_size"), &Window::add_theme_font_size_override); + ClassDB::bind_method(D_METHOD("add_theme_color_override", "name", "color"), &Window::add_theme_color_override); + ClassDB::bind_method(D_METHOD("add_theme_constant_override", "name", "constant"), &Window::add_theme_constant_override); + + ClassDB::bind_method(D_METHOD("remove_theme_icon_override", "name"), &Window::remove_theme_icon_override); + ClassDB::bind_method(D_METHOD("remove_theme_stylebox_override", "name"), &Window::remove_theme_style_override); + ClassDB::bind_method(D_METHOD("remove_theme_font_override", "name"), &Window::remove_theme_font_override); + ClassDB::bind_method(D_METHOD("remove_theme_font_size_override", "name"), &Window::remove_theme_font_size_override); + ClassDB::bind_method(D_METHOD("remove_theme_color_override", "name"), &Window::remove_theme_color_override); + ClassDB::bind_method(D_METHOD("remove_theme_constant_override", "name"), &Window::remove_theme_constant_override); + ClassDB::bind_method(D_METHOD("get_theme_icon", "name", "theme_type"), &Window::get_theme_icon, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_theme_stylebox", "name", "theme_type"), &Window::get_theme_stylebox, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_theme_font", "name", "theme_type"), &Window::get_theme_font, DEFVAL("")); @@ -1732,6 +2174,13 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("get_theme_color", "name", "theme_type"), &Window::get_theme_color, DEFVAL("")); ClassDB::bind_method(D_METHOD("get_theme_constant", "name", "theme_type"), &Window::get_theme_constant, DEFVAL("")); + ClassDB::bind_method(D_METHOD("has_theme_icon_override", "name"), &Window::has_theme_icon_override); + ClassDB::bind_method(D_METHOD("has_theme_stylebox_override", "name"), &Window::has_theme_stylebox_override); + ClassDB::bind_method(D_METHOD("has_theme_font_override", "name"), &Window::has_theme_font_override); + ClassDB::bind_method(D_METHOD("has_theme_font_size_override", "name"), &Window::has_theme_font_size_override); + ClassDB::bind_method(D_METHOD("has_theme_color_override", "name"), &Window::has_theme_color_override); + ClassDB::bind_method(D_METHOD("has_theme_constant_override", "name"), &Window::has_theme_constant_override); + ClassDB::bind_method(D_METHOD("has_theme_icon", "name", "theme_type"), &Window::has_theme_icon, DEFVAL("")); ClassDB::bind_method(D_METHOD("has_theme_stylebox", "name", "theme_type"), &Window::has_theme_stylebox, DEFVAL("")); ClassDB::bind_method(D_METHOD("has_theme_font", "name", "theme_type"), &Window::has_theme_font, DEFVAL("")); @@ -1785,13 +2234,13 @@ void Window::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "content_scale_aspect", PROPERTY_HINT_ENUM, "Ignore,Keep,Keep Width,Keep Height,Expand"), "set_content_scale_aspect", "get_content_scale_aspect"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "content_scale_factor"), "set_content_scale_factor", "get_content_scale_factor"); + ADD_GROUP("Localization", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating"); + ADD_GROUP("Theme", "theme_"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), "set_theme", "get_theme"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "theme_type_variation", PROPERTY_HINT_ENUM_SUGGESTION), "set_theme_type_variation", "get_theme_type_variation"); - ADD_GROUP("Auto Translate", ""); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating"); - ADD_SIGNAL(MethodInfo("window_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"))); ADD_SIGNAL(MethodInfo("mouse_entered")); @@ -1851,4 +2300,23 @@ Window::Window() { Window::~Window() { memdelete(theme_owner); + + // Resources need to be disconnected. + for (KeyValue<StringName, Ref<Texture2D>> &E : theme_icon_override) { + E.value->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + for (KeyValue<StringName, Ref<StyleBox>> &E : theme_style_override) { + E.value->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + for (KeyValue<StringName, Ref<Font>> &E : theme_font_override) { + E.value->disconnect("changed", callable_mp(this, &Window::_notify_theme_override_changed)); + } + + // Then override maps can be simply cleared. + theme_icon_override.clear(); + theme_style_override.clear(); + theme_font_override.clear(); + theme_font_size_override.clear(); + theme_color_override.clear(); + theme_constant_override.clear(); } diff --git a/scene/main/window.h b/scene/main/window.h index 03597b309a..5024b42587 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -140,6 +140,14 @@ private: Ref<Theme> theme; StringName theme_type_variation; + bool bulk_theme_override = false; + Theme::ThemeIconMap theme_icon_override; + Theme::ThemeStyleMap theme_style_override; + Theme::ThemeFontMap theme_font_override; + Theme::ThemeFontSizeMap theme_font_size_override; + Theme::ThemeColorMap theme_color_override; + Theme::ThemeConstantMap theme_constant_override; + mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache; mutable HashMap<StringName, Theme::ThemeStyleMap> theme_style_cache; mutable HashMap<StringName, Theme::ThemeFontMap> theme_font_cache; @@ -148,6 +156,7 @@ private: mutable HashMap<StringName, Theme::ThemeConstantMap> theme_constant_cache; void _theme_changed(); + void _notify_theme_override_changed(); void _invalidate_theme_cache(); Viewport *embedder = nullptr; @@ -173,6 +182,10 @@ protected: virtual Size2 _get_contents_minimum_size() const; static void _bind_methods(); 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; + void _get_property_list(List<PropertyInfo> *p_list) const; void _validate_property(PropertyInfo &p_property) const; virtual void add_child_notify(Node *p_child) override; @@ -198,7 +211,8 @@ public: Size2i get_size() const; void reset_size(); - Size2i get_real_size() const; + Point2i get_position_with_decorations() const; + Size2i get_size_with_decorations() const; void set_max_size(const Size2i &p_max_size); Size2i get_max_size() const; @@ -270,16 +284,6 @@ 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 set_theme_type_variation(const StringName &p_theme_type); - StringName get_theme_type_variation() const; - Size2 get_contents_minimum_size() const; void grab_focus(); @@ -295,6 +299,35 @@ public: Rect2i get_usable_parent_rect() const; + // 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; + + void set_theme_type_variation(const StringName &p_theme_type); + StringName get_theme_type_variation() const; + + void begin_bulk_theme_override(); + void end_bulk_theme_override(); + + void add_theme_icon_override(const StringName &p_name, const Ref<Texture2D> &p_icon); + void add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style); + void add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font); + void add_theme_font_size_override(const StringName &p_name, int p_font_size); + void add_theme_color_override(const StringName &p_name, const Color &p_color); + void add_theme_constant_override(const StringName &p_name, int p_constant); + + void remove_theme_icon_override(const StringName &p_name); + void remove_theme_style_override(const StringName &p_name); + void remove_theme_font_override(const StringName &p_name); + void remove_theme_font_size_override(const StringName &p_name); + void remove_theme_color_override(const StringName &p_name); + void remove_theme_constant_override(const StringName &p_name); + Ref<Texture2D> get_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const; Ref<StyleBox> get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const; Ref<Font> get_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const; @@ -302,6 +335,13 @@ public: Color get_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const; int get_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const; + bool has_theme_icon_override(const StringName &p_name) const; + bool has_theme_stylebox_override(const StringName &p_name) const; + bool has_theme_font_override(const StringName &p_name) const; + bool has_theme_font_size_override(const StringName &p_name) const; + bool has_theme_color_override(const StringName &p_name) const; + bool has_theme_constant_override(const StringName &p_name) const; + bool has_theme_icon(const StringName &p_name, const StringName &p_theme_type = StringName()) const; bool has_theme_stylebox(const StringName &p_name, const StringName &p_theme_type = StringName()) const; bool has_theme_font(const StringName &p_name, const StringName &p_theme_type = StringName()) const; @@ -313,6 +353,8 @@ public: Ref<Font> get_theme_default_font() const; int get_theme_default_font_size() const; + // + virtual Transform2D get_screen_transform() const override; Rect2i get_parent_rect() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index ee45a8ea6f..043895b591 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -31,7 +31,7 @@ #include "register_scene_types.h" #include "core/config/project_settings.h" -#include "core/extension/native_extension_manager.h" +#include "core/extension/gdextension_manager.h" #include "core/object/class_db.h" #include "core/os/os.h" #include "scene/2d/animated_sprite_2d.h" @@ -827,14 +827,14 @@ void register_scene_types() { GDREGISTER_CLASS(ConvexPolygonShape3D); GDREGISTER_CLASS(ConcavePolygonShape3D); - ClassDB::register_class<SkeletonModificationStack3D>(); - ClassDB::register_class<SkeletonModification3D>(); - ClassDB::register_class<SkeletonModification3DLookAt>(); - ClassDB::register_class<SkeletonModification3DCCDIK>(); - ClassDB::register_class<SkeletonModification3DFABRIK>(); - ClassDB::register_class<SkeletonModification3DJiggle>(); - ClassDB::register_class<SkeletonModification3DTwoBoneIK>(); - ClassDB::register_class<SkeletonModification3DStackHolder>(); + GDREGISTER_CLASS(SkeletonModificationStack3D); + GDREGISTER_CLASS(SkeletonModification3D); + GDREGISTER_CLASS(SkeletonModification3DLookAt); + GDREGISTER_CLASS(SkeletonModification3DCCDIK); + GDREGISTER_CLASS(SkeletonModification3DFABRIK); + GDREGISTER_CLASS(SkeletonModification3DJiggle); + GDREGISTER_CLASS(SkeletonModification3DTwoBoneIK); + GDREGISTER_CLASS(SkeletonModification3DStackHolder); OS::get_singleton()->yield(); // may take time to init #endif // _3D_DISABLED diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index fa7a1f3dbf..bc2149a8c6 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -941,7 +941,7 @@ Transform2D Curve2D::_sample_posture(Interval p_interval) const { const Vector2 forward = forward_begin.slerp(forward_end, frac).normalized(); const Vector2 side = Vector2(-forward.y, forward.x); - return Transform2D(forward, side, Vector2(0.0, 0.0)); + return Transform2D(side, forward, Vector2(0.0, 0.0)); } Vector2 Curve2D::sample_baked(real_t p_offset, bool p_cubic) const { diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index f4b7f3d0b2..5316b524ba 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -450,7 +450,7 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const { callable = callable.bindp(argptrs, binds.size()); } - cfrom->connect(snames[c.signal], callable, CONNECT_PERSIST | c.flags); + cfrom->connect(snames[c.signal], callable, CONNECT_PERSIST | c.flags | (p_edit_state == GEN_EDIT_STATE_MAIN ? 0 : CONNECT_INHERITED)); } //Node *s = ret_nodes[0]; diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index 413670d23e..87c6c36ee9 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -124,7 +124,6 @@ Shape2D::Shape2D(const RID &p_rid) { } Shape2D::~Shape2D() { - if (PhysicsServer2D::get_singleton() != nullptr) { - PhysicsServer2D::get_singleton()->free(shape); - } + ERR_FAIL_NULL(PhysicsServer2D::get_singleton()); + PhysicsServer2D::get_singleton()->free(shape); } diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp index 44f21d2a48..7992ba9fd4 100644 --- a/scene/resources/shape_3d.cpp +++ b/scene/resources/shape_3d.cpp @@ -128,7 +128,6 @@ Shape3D::Shape3D(RID p_shape) : shape(p_shape) {} Shape3D::~Shape3D() { - if (PhysicsServer3D::get_singleton() != nullptr) { - PhysicsServer3D::get_singleton()->free(shape); - } + ERR_FAIL_NULL(PhysicsServer3D::get_singleton()); + PhysicsServer3D::get_singleton()->free(shape); } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 461dccfbdd..6b8f8097a8 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -2066,10 +2066,9 @@ Error VisualShader::_write_node(Type type, StringBuilder *p_global_code, StringB } if (!node_code.is_empty()) { - r_code += "\n"; + r_code += "\n\n"; } - r_code += "\n"; // r_processed.insert(p_node); return OK; @@ -2366,71 +2365,62 @@ void VisualShader::_update_shader() const { String global_compute_code; if (shader_mode == Shader::MODE_PARTICLES) { - bool has_start = !code_map[TYPE_START].is_empty(); bool has_start_custom = !code_map[TYPE_START_CUSTOM].is_empty(); bool has_process = !code_map[TYPE_PROCESS].is_empty(); bool has_process_custom = !code_map[TYPE_PROCESS_CUSTOM].is_empty(); bool has_collide = !code_map[TYPE_COLLIDE].is_empty(); shader_code += "void start() {\n"; - if (has_start || has_start_custom) { - shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; - shader_code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; - shader_code += " float __radians;\n"; - shader_code += " vec3 __vec3_buff1;\n"; - shader_code += " vec3 __vec3_buff2;\n"; - shader_code += " float __scalar_buff1;\n"; - shader_code += " float __scalar_buff2;\n"; - shader_code += " int __scalar_ibuff;\n"; - shader_code += " vec4 __vec4_buff;\n"; - shader_code += " vec3 __ndiff = normalize(__diff);\n\n"; - } - if (has_start) { - shader_code += " {\n"; - shader_code += code_map[TYPE_START].replace("\n ", "\n "); - shader_code += " }\n"; - if (has_start_custom) { - shader_code += " \n"; - } - } + shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; + shader_code += "\n"; + shader_code += " {\n"; + shader_code += code_map[TYPE_START].replace("\n ", "\n "); + shader_code += " }\n"; if (has_start_custom) { + shader_code += " \n"; shader_code += " {\n"; shader_code += code_map[TYPE_START_CUSTOM].replace("\n ", "\n "); shader_code += " }\n"; } shader_code += "}\n\n"; - shader_code += "void process() {\n"; + if (has_process || has_process_custom || has_collide) { + shader_code += "void process() {\n"; shader_code += " uint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; - shader_code += " vec3 __vec3_buff1;\n"; - shader_code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; - shader_code += " vec3 __ndiff = normalize(__diff);\n\n"; - } - shader_code += " {\n"; - String tab = " "; - if (has_collide) { - shader_code += " if (COLLIDED) {\n\n"; - shader_code += code_map[TYPE_COLLIDE].replace("\n ", "\n "); + shader_code += "\n"; + if (has_process || has_collide) { + shader_code += " {\n"; + } + String tab = " "; + if (has_collide) { + shader_code += " if (COLLIDED) {\n\n"; + shader_code += code_map[TYPE_COLLIDE].replace("\n ", "\n "); + if (has_process) { + shader_code += " } else {\n\n"; + tab += " "; + } + } if (has_process) { - shader_code += " } else {\n\n"; - tab += " "; + shader_code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab); + } + if (has_collide) { + shader_code += " }\n"; + } + if (has_process || has_collide) { + shader_code += " }\n"; } - } - if (has_process) { - shader_code += code_map[TYPE_PROCESS].replace("\n ", "\n " + tab); - } - if (has_collide) { - shader_code += " }\n"; - } - shader_code += " }\n"; - if (has_process_custom) { - shader_code += " {\n\n"; - shader_code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n "); - shader_code += " }\n"; - } + if (has_process_custom) { + if (has_process || has_collide) { + shader_code += " \n"; + } + shader_code += " {\n"; + shader_code += code_map[TYPE_PROCESS_CUSTOM].replace("\n ", "\n "); + shader_code += " }\n"; + } - shader_code += "}\n\n"; + shader_code += "}\n\n"; + } global_compute_code += "float __rand_from_seed(inout uint seed) {\n"; global_compute_code += " int k;\n"; diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index f125b05a26..d61a343688 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -374,13 +374,13 @@ String VisualShaderNodeParticleMeshEmitter::_generate_code(VisualShader::Type p_ if (is_output_port_connected(p_index)) { switch (p_port_type) { case PORT_TYPE_VECTOR_2D: { - code += vformat(" %s = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0).xy;\n", p_output_vars[p_index], make_unique_id(p_type, p_id, p_texture_name)); + code += vformat(" %s = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0).xy;\n", p_output_vars[p_index], make_unique_id(p_type, p_id, p_texture_name)); } break; case PORT_TYPE_VECTOR_3D: { if (mode_2d) { - code += vformat(" %s = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0).xy;\n", p_output_vars[p_index], make_unique_id(p_type, p_id, p_texture_name)); + code += vformat(" %s = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0).xy;\n", p_output_vars[p_index], make_unique_id(p_type, p_id, p_texture_name)); } else { - code += vformat(" %s = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0).xyz;\n", p_output_vars[p_index], make_unique_id(p_type, p_id, p_texture_name)); + code += vformat(" %s = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0).xyz;\n", p_output_vars[p_index], make_unique_id(p_type, p_id, p_texture_name)); } } break; default: @@ -392,25 +392,27 @@ String VisualShaderNodeParticleMeshEmitter::_generate_code(VisualShader::Type p_ String VisualShaderNodeParticleMeshEmitter::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 += " __scalar_ibuff = int(__rand_from_seed(__seed) * 65535.0) % " + itos(position_texture->get_width()) + ";\n"; + code += " {\n"; + code += " int __scalar_ibuff = int(__rand_from_seed(__seed) * 65535.0) % " + itos(position_texture->get_width()) + ";\n"; code += _generate_code(p_type, p_id, p_output_vars, 0, "mesh_vx", VisualShaderNode::PORT_TYPE_VECTOR_3D); code += _generate_code(p_type, p_id, p_output_vars, 1, "mesh_nm", VisualShaderNode::PORT_TYPE_VECTOR_3D); if (is_output_port_connected(2) || is_output_port_connected(3)) { - code += vformat(" __vec4_buff = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0);\n", make_unique_id(p_type, p_id, "mesh_col")); + code += vformat(" vec4 __vec4_buff = texelFetch(%s, ivec2(__scalar_ibuff, 0), 0);\n", make_unique_id(p_type, p_id, "mesh_col")); if (is_output_port_connected(2)) { - code += " " + p_output_vars[2] + " = __vec4_buff.rgb;\n"; + code += " " + p_output_vars[2] + " = __vec4_buff.rgb;\n"; } if (is_output_port_connected(3)) { - code += " " + p_output_vars[3] + " = __vec4_buff.a;\n"; + code += " " + p_output_vars[3] + " = __vec4_buff.a;\n"; } } code += _generate_code(p_type, p_id, p_output_vars, 4, "mesh_uv", VisualShaderNode::PORT_TYPE_VECTOR_2D); code += _generate_code(p_type, p_id, p_output_vars, 5, "mesh_uv2", VisualShaderNode::PORT_TYPE_VECTOR_2D); + code += " }\n"; return code; } @@ -737,6 +739,8 @@ VisualShaderNodeParticleMeshEmitter::VisualShaderNodeParticleMeshEmitter() { color_texture.instantiate(); uv_texture.instantiate(); uv2_texture.instantiate(); + + simple_decl = false; } // VisualShaderNodeParticleMultiplyByAxisAngle @@ -879,22 +883,26 @@ bool VisualShaderNodeParticleConeVelocity::has_output_port_preview(int p_port) c String VisualShaderNodeParticleConeVelocity::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 += " __radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; - code += " __scalar_buff1 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; - code += " __scalar_buff2 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; - code += " __vec3_buff1 = " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + ";\n"; - code += " __scalar_buff1 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.x, __vec3_buff1.z) : sign(__vec3_buff1.x) * (PI / 2.0);\n"; - code += " __scalar_buff2 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.z)) : (__vec3_buff1.x != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.x)) : sign(__vec3_buff1.y) * (PI / 2.0));\n"; - code += " __vec3_buff1 = vec3(sin(__scalar_buff1), 0.0, cos(__scalar_buff1));\n"; - code += " __vec3_buff2 = vec3(0.0, sin(__scalar_buff2), cos(__scalar_buff2));\n"; - code += " __vec3_buff2.z = __vec3_buff2.z / max(0.0001, sqrt(abs(__vec3_buff2.z)));\n"; - code += " " + p_output_vars[0] + " = normalize(vec3(__vec3_buff1.x * __vec3_buff2.z, __vec3_buff2.y, __vec3_buff1.z * __vec3_buff2.z));\n"; + code += " {\n"; + code += " float __radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; + code += " float __scalar_buff1 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; + code += " float __scalar_buff2 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; + code += " vec3 __vec3_buff1 = " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + ";\n"; + code += " __scalar_buff1 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.x, __vec3_buff1.z) : sign(__vec3_buff1.x) * (PI / 2.0);\n"; + code += " __scalar_buff2 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.z)) : (__vec3_buff1.x != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.x)) : sign(__vec3_buff1.y) * (PI / 2.0));\n"; + code += " __vec3_buff1 = vec3(sin(__scalar_buff1), 0.0, cos(__scalar_buff1));\n"; + code += " vec3 __vec3_buff2 = vec3(0.0, sin(__scalar_buff2), cos(__scalar_buff2));\n"; + code += " __vec3_buff2.z = __vec3_buff2.z / max(0.0001, sqrt(abs(__vec3_buff2.z)));\n"; + code += " " + p_output_vars[0] + " = normalize(vec3(__vec3_buff1.x * __vec3_buff2.z, __vec3_buff2.y, __vec3_buff1.z * __vec3_buff2.z));\n"; + code += " }\n"; return code; } VisualShaderNodeParticleConeVelocity::VisualShaderNodeParticleConeVelocity() { set_input_port_default_value(0, Vector3(1, 0, 0)); set_input_port_default_value(1, 45.0); + + simple_decl = false; } // VisualShaderNodeParticleRandomness @@ -1086,21 +1094,26 @@ String VisualShaderNodeParticleAccelerator::get_input_port_name(int p_port) cons String VisualShaderNodeParticleAccelerator::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 += " {\n"; switch (mode) { case MODE_LINEAR: - code += " " + p_output_vars[0] + " = length(VELOCITY) > 0.0 ? " + "normalize(VELOCITY) * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; + code += " " + p_output_vars[0] + " = length(VELOCITY) > 0.0 ? " + "normalize(VELOCITY) * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; break; case MODE_RADIAL: - code += " " + p_output_vars[0] + " = length(__diff) > 0.0 ? __ndiff * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; + code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; + code += " vec3 __ndiff = normalize(__diff);\n\n"; + code += " " + p_output_vars[0] + " = length(__diff) > 0.0 ? __ndiff * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; break; case MODE_TANGENTIAL: - code += " __vec3_buff1 = cross(__ndiff, normalize(" + (p_input_vars[2].is_empty() ? "vec3" + (String)get_input_port_default_value(2) : p_input_vars[2]) + "));\n"; - code += " " + p_output_vars[0] + " = length(__vec3_buff1) > 0.0 ? normalize(__vec3_buff1) * (" + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ")) : vec3(0.0);\n"; + code += " vec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; + code += " vec3 __ndiff = normalize(__diff);\n\n"; + code += " vec3 __vec3_buff1 = cross(__ndiff, normalize(" + (p_input_vars[2].is_empty() ? "vec3" + (String)get_input_port_default_value(2) : p_input_vars[2]) + "));\n"; + code += " " + p_output_vars[0] + " = length(__vec3_buff1) > 0.0 ? normalize(__vec3_buff1) * (" + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ")) : vec3(0.0);\n"; break; default: break; } - + code += " }\n"; return code; } @@ -1125,6 +1138,8 @@ VisualShaderNodeParticleAccelerator::VisualShaderNodeParticleAccelerator() { set_input_port_default_value(0, Vector3(1, 1, 1)); set_input_port_default_value(1, 0.0); set_input_port_default_value(2, Vector3(0, -9.8, 0)); + + simple_decl = false; } // VisualShaderNodeParticleOutput |