diff options
Diffstat (limited to 'scene')
82 files changed, 992 insertions, 598 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index aeaaaf3aec..aa7df4ea9c 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -155,11 +155,11 @@ Transform2D Camera2D::get_camera_transform() { } } - if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) { - real_t c = smoothing * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); + if (follow_smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) { + real_t c = position_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos; ret_camera_pos = smoothed_camera_pos; - //camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing; + //camera_pos=camera_pos*(1.0-position_smoothing_speed)+new_camera_pos*position_smoothing_speed; } else { ret_camera_pos = smoothed_camera_pos = camera_pos; } @@ -183,7 +183,7 @@ Transform2D Camera2D::get_camera_transform() { Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom_scale); - if (!smoothing_enabled || !limit_smoothing_enabled) { + if (!follow_smoothing_enabled || !limit_smoothing_enabled) { if (screen_rect.position.x < limit[SIDE_LEFT]) { screen_rect.position.x = limit[SIDE_LEFT]; } @@ -428,7 +428,7 @@ void Camera2D::set_current(bool p_current) { void Camera2D::_update_process_internal_for_smoothing() { bool is_not_in_scene_or_editor = !(is_inside_tree() && Engine::get_singleton()->is_editor_hint()); - bool is_any_smoothing_valid = smoothing > 0 || rotation_smoothing_speed > 0; + bool is_any_smoothing_valid = position_smoothing_speed > 0 || rotation_smoothing_speed > 0; bool enabled = is_any_smoothing_valid && is_not_in_scene_or_editor; set_process_internal(enabled); @@ -525,13 +525,13 @@ void Camera2D::align() { _update_scroll(); } -void Camera2D::set_follow_smoothing(real_t p_speed) { - smoothing = p_speed; +void Camera2D::set_position_smoothing_speed(real_t p_speed) { + position_smoothing_speed = p_speed; _update_process_internal_for_smoothing(); } -real_t Camera2D::get_follow_smoothing() const { - return smoothing; +real_t Camera2D::get_position_smoothing_speed() const { + return position_smoothing_speed; } void Camera2D::set_rotation_smoothing_speed(real_t p_speed) { @@ -607,18 +607,18 @@ real_t Camera2D::get_drag_horizontal_offset() const { void Camera2D::_set_old_smoothing(real_t p_enable) { //compatibility if (p_enable > 0) { - smoothing_enabled = true; - set_follow_smoothing(p_enable); + follow_smoothing_enabled = true; + set_position_smoothing_speed(p_enable); } } -void Camera2D::set_enable_follow_smoothing(bool p_enabled) { - smoothing_enabled = p_enabled; +void Camera2D::set_position_smoothing_enabled(bool p_enabled) { + follow_smoothing_enabled = p_enabled; notify_property_list_changed(); } -bool Camera2D::is_follow_smoothing_enabled() const { - return smoothing_enabled; +bool Camera2D::is_position_smoothing_enabled() const { + return follow_smoothing_enabled; } void Camera2D::set_custom_viewport(Node *p_viewport) { @@ -689,7 +689,7 @@ bool Camera2D::is_margin_drawing_enabled() const { } void Camera2D::_validate_property(PropertyInfo &p_property) const { - if (!smoothing_enabled && p_property.name == "smoothing_speed") { + if (!follow_smoothing_enabled && p_property.name == "smoothing_speed") { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } if (!rotation_smoothing_enabled && p_property.name == "rotation_smoothing_speed") { @@ -746,11 +746,11 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &Camera2D::set_custom_viewport); ClassDB::bind_method(D_METHOD("get_custom_viewport"), &Camera2D::get_custom_viewport); - ClassDB::bind_method(D_METHOD("set_follow_smoothing", "follow_smoothing"), &Camera2D::set_follow_smoothing); - ClassDB::bind_method(D_METHOD("get_follow_smoothing"), &Camera2D::get_follow_smoothing); + ClassDB::bind_method(D_METHOD("set_position_smoothing_speed", "position_smoothing_speed"), &Camera2D::set_position_smoothing_speed); + ClassDB::bind_method(D_METHOD("get_position_smoothing_speed"), &Camera2D::get_position_smoothing_speed); - ClassDB::bind_method(D_METHOD("set_enable_follow_smoothing", "follow_smoothing"), &Camera2D::set_enable_follow_smoothing); - ClassDB::bind_method(D_METHOD("is_follow_smoothing_enabled"), &Camera2D::is_follow_smoothing_enabled); + ClassDB::bind_method(D_METHOD("set_position_smoothing_enabled", "position_smoothing_speed"), &Camera2D::set_position_smoothing_enabled); + ClassDB::bind_method(D_METHOD("is_position_smoothing_enabled"), &Camera2D::is_position_smoothing_enabled); ClassDB::bind_method(D_METHOD("set_rotation_smoothing_enabled", "enabled"), &Camera2D::set_rotation_smoothing_enabled); ClassDB::bind_method(D_METHOD("is_rotation_smoothing_enabled"), &Camera2D::is_rotation_smoothing_enabled); @@ -788,9 +788,9 @@ void Camera2D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_bottom", PROPERTY_HINT_NONE, "suffix:px"), "set_limit", "get_limit", SIDE_BOTTOM); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "limit_smoothed"), "set_limit_smoothing_enabled", "is_limit_smoothing_enabled"); - ADD_GROUP("Smoothing", "smoothing_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smoothing_enabled"), "set_enable_follow_smoothing", "is_follow_smoothing_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_follow_smoothing", "get_follow_smoothing"); + ADD_GROUP("Follow Smoothing", "follow_smoothing_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "position_smoothing_enabled"), "set_position_smoothing_enabled", "is_position_smoothing_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "position_smoothing_speed", PROPERTY_HINT_NONE, "suffix:px/s"), "set_position_smoothing_speed", "get_position_smoothing_speed"); ADD_GROUP("Rotation Smoothing", "rotation_smoothing_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotation_smoothing_enabled"), "set_rotation_smoothing_enabled", "is_rotation_smoothing_enabled"); diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 1411175af2..ae172f47b1 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -65,8 +65,8 @@ protected: AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER; bool ignore_rotation = true; bool current = false; - real_t smoothing = 5.0; - bool smoothing_enabled = false; + real_t position_smoothing_speed = 5.0; + bool follow_smoothing_enabled = false; real_t camera_angle = 0.0; real_t rotation_smoothing_speed = 5.0; @@ -140,11 +140,11 @@ public: void set_drag_vertical_offset(real_t p_offset); real_t get_drag_vertical_offset() const; - void set_enable_follow_smoothing(bool p_enabled); - bool is_follow_smoothing_enabled() const; + void set_position_smoothing_enabled(bool p_enabled); + bool is_position_smoothing_enabled() const; - void set_follow_smoothing(real_t p_speed); - real_t get_follow_smoothing() const; + void set_position_smoothing_speed(real_t p_speed); + real_t get_position_smoothing_speed() const; void set_rotation_smoothing_speed(real_t p_speed); real_t get_rotation_smoothing_speed() const; diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 90402260ed..78b5199358 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -172,6 +172,7 @@ void Light2D::set_shadow_filter(ShadowFilter p_filter) { ERR_FAIL_INDEX(p_filter, SHADOW_FILTER_MAX); shadow_filter = p_filter; RS::get_singleton()->canvas_light_set_shadow_filter(canvas_light, RS::CanvasLightShadowFilter(p_filter)); + notify_property_list_changed(); } Light2D::ShadowFilter Light2D::get_shadow_filter() const { @@ -231,6 +232,10 @@ void Light2D::_validate_property(PropertyInfo &p_property) const { if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) { p_property.usage = PROPERTY_USAGE_NO_EDITOR; } + + if (shadow && p_property.name == "shadow_filter_smooth" && shadow_filter == SHADOW_FILTER_NONE) { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } } void Light2D::_bind_methods() { @@ -454,7 +459,7 @@ void DirectionalLight2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &DirectionalLight2D::set_max_distance); ClassDB::bind_method(D_METHOD("get_max_distance"), &DirectionalLight2D::get_max_distance); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01,suffix:px"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384.0,1.0,or_greater,suffix:px"), "set_max_distance", "get_max_distance"); } diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index f077f7f5e6..748fbbe2d1 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -104,7 +104,7 @@ void NavigationAgent2D::_bind_methods() { ADD_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); ADD_SIGNAL(MethodInfo("navigation_finished")); - ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR3, "safe_velocity"))); + ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR2, "safe_velocity"))); } void NavigationAgent2D::_notification(int p_what) { @@ -478,8 +478,8 @@ void NavigationAgent2D::_request_repath() { void NavigationAgent2D::_check_distance_to_target() { if (!target_reached) { if (distance_to_target() < target_desired_distance) { - emit_signal(SNAME("target_reached")); target_reached = true; + emit_signal(SNAME("target_reached")); } } } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index dd016d5e92..f80b2a07c9 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -192,10 +192,8 @@ void Bone2D::_notification(int p_what) { cache_transform = tmp_trans; } break; - // Bone2D Editor gizmo drawing: -#ifndef _MSC_VER -#warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin -#endif + // Bone2D Editor gizmo drawing. + // TODO: Bone2D gizmo drawing needs to be moved to an editor plugin. case NOTIFICATION_DRAW: { // Only draw the gizmo in the editor! if (Engine::get_singleton()->is_editor_hint() == false) { diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index 0ecf8333a0..0784318442 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -309,9 +309,7 @@ bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const { q.y = 1.0f - q.y; } q = q * src_rect.size + src_rect.position; -#ifndef _MSC_VER -#warning this need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that) -#endif + // TODO: This need to be obtained from CanvasItem new repeat mode (but it needs to guess it from hierarchy, need to add a function for that). bool is_repeat = false; bool is_mirrored_repeat = false; if (is_repeat) { @@ -446,7 +444,7 @@ void Sprite2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); ADD_GROUP("Region", "region_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled"); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 26627a4fca..e865806a7f 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1097,8 +1097,8 @@ void TileMap::_rendering_update_layer(int p_layer) { rs->canvas_item_set_sort_children_by_y(ci, layers[p_layer].y_sort_enabled); rs->canvas_item_set_use_parent_material(ci, get_use_parent_material() || get_material().is_valid()); rs->canvas_item_set_z_index(ci, layers[p_layer].z_index); - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat())); + rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree())); + rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree())); rs->canvas_item_set_light_mask(ci, get_light_mask()); } @@ -1208,8 +1208,8 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List rs->canvas_item_set_z_as_relative_to_parent(ci, true); rs->canvas_item_set_z_index(ci, tile_z_index); - rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter())); - rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat())); + rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree())); + rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree())); q.canvas_items.push_back(ci); @@ -2206,11 +2206,10 @@ void TileMap::set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPat } } -TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints) { +TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern) { if (!tile_set.is_valid()) { return TileSet::TerrainsPattern(); } - // Returns all tiles compatible with the given constraints. RBMap<TileSet::TerrainsPattern, int> terrain_pattern_score; RBSet<TileSet::TerrainsPattern> pattern_set = tile_set->get_terrains_pattern_set(p_terrain_set); @@ -2221,28 +2220,41 @@ TileSet::TerrainsPattern TileMap::_get_best_terrain_pattern_for_constraints(int // Check the center bit constraint TerrainConstraint terrain_constraint = TerrainConstraint(this, p_position, terrain_pattern.get_terrain()); RBSet<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_constraint); - if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) { - score += in_set_constraint_element->get().get_priority(); + if (in_set_constraint_element) { + if (in_set_constraint_element->get().get_terrain() != terrain_constraint.get_terrain()) { + score += in_set_constraint_element->get().get_priority(); + } + } else if (p_current_pattern.get_terrain() != terrain_pattern.get_terrain()) { + continue; // Ignore a pattern that cannot keep bits without constraints unmodified. } // Check the surrounding bits + bool invalid_pattern = false; for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { // Check if the bit is compatible with the constraints. TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain_peering_bit(bit)); in_set_constraint_element = p_constraints.find(terrain_bit_constraint); - if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) { - score += in_set_constraint_element->get().get_priority(); + if (in_set_constraint_element) { + if (in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) { + score += in_set_constraint_element->get().get_priority(); + } + } else if (p_current_pattern.get_terrain_peering_bit(bit) != terrain_pattern.get_terrain_peering_bit(bit)) { + invalid_pattern = true; // Ignore a pattern that cannot keep bits without constraints unmodified. + break; } } } + if (invalid_pattern) { + continue; + } terrain_pattern_score[terrain_pattern] = score; } // Compute the minimum score - TileSet::TerrainsPattern min_score_pattern; + TileSet::TerrainsPattern min_score_pattern = p_current_pattern; int min_score = INT32_MAX; for (KeyValue<TileSet::TerrainsPattern, int> E : terrain_pattern_score) { if (E.value < min_score) { @@ -2274,7 +2286,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_added_p return output; } -RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_cell_list, int p_terrain_set, bool p_ignore_empty_terrains) const { +RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const { if (!tile_set.is_valid()) { return RBSet<TerrainConstraint>(); } @@ -2284,8 +2296,8 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l // Build a set of dummy constraints to get the constrained points. RBSet<TerrainConstraint> dummy_constraints; - for (const Vector2i &E : p_cell_list) { - for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over sides. + for (const Vector2i &E : p_painted) { + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { // Iterates over neighbor bits. TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); if (tile_set->is_valid_terrain_peering_bit(p_terrain_set, bit)) { dummy_constraints.insert(TerrainConstraint(this, E, bit, -1)); @@ -2342,7 +2354,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l } // Add the centers as constraints - for (Vector2i E_coords : p_cell_list) { + for (Vector2i E_coords : p_painted) { TileData *tile_data = nullptr; TileMapCell cell = get_cell(p_layer, E_coords); if (cell.source_id != TileSet::INVALID_SOURCE) { @@ -2362,7 +2374,7 @@ RBSet<TileMap::TerrainConstraint> TileMap::_get_terrain_constraints_from_cells_l return constraints; } -HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) { +HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints) { if (!tile_set.is_valid()) { return HashMap<Vector2i, TileSet::TerrainsPattern>(); } @@ -2378,7 +2390,20 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_constraints(co const Vector2i &coords = p_to_replace[i]; // Select the best pattern for the given constraints - TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints); + TileSet::TerrainsPattern current_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); + TileMapCell cell = get_cell(p_layer, coords); + if (cell.source_id != TileSet::INVALID_SOURCE) { + TileSetSource *source = *tile_set->get_source(cell.source_id); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + // Get tile data. + TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + current_pattern = tile_data->get_terrains_pattern(); + } + } + } + TileSet::TerrainsPattern pattern = _get_best_terrain_pattern_for_constraints(p_terrain_set, coords, constraints, current_pattern); // Update the constraint set with the new ones RBSet<TerrainConstraint> new_constraints = _get_terrain_constraints_from_added_pattern(coords, p_terrain_set, pattern); @@ -2492,12 +2517,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_connect(int p_ } // Fills in the constraint list from existing tiles. - for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) { + for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) { constraints.insert(c); } // Fill the terrains. - output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints); return output; } @@ -2527,10 +2552,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay // Build list and set of tiles that can be modified (painted and their surroundings) Vector<Vector2i> can_modify_list; RBSet<Vector2i> can_modify_set; + RBSet<Vector2i> painted_set; for (int i = p_path.size() - 1; i >= 0; i--) { const Vector2i &coords = p_path[i]; can_modify_list.push_back(coords); can_modify_set.insert(coords); + painted_set.insert(coords); } for (Vector2i coords : p_path) { // Find the adequate neighbor @@ -2563,12 +2590,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_path(int p_lay } // Fills in the constraint list from existing tiles. - for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) { + for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) { constraints.insert(c); } // Fill the terrains. - output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints); return output; } @@ -2580,10 +2607,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_ // Build list and set of tiles that can be modified (painted and their surroundings). Vector<Vector2i> can_modify_list; RBSet<Vector2i> can_modify_set; + RBSet<Vector2i> painted_set; for (int i = p_coords_array.size() - 1; i >= 0; i--) { const Vector2i &coords = p_coords_array[i]; can_modify_list.push_back(coords); can_modify_set.insert(coords); + painted_set.insert(coords); } for (Vector2i coords : p_coords_array) { // Find the adequate neighbor @@ -2613,12 +2642,12 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_fill_pattern(int p_ } // Fills in the constraint list from modified tiles border. - for (TerrainConstraint c : _get_terrain_constraints_from_cells_list(p_layer, can_modify_set, p_terrain_set, p_ignore_empty_terrains)) { + for (TerrainConstraint c : _get_terrain_constraints_from_painted_cells_list(p_layer, painted_set, p_terrain_set, p_ignore_empty_terrains)) { constraints.insert(c); } // Fill the terrains. - output = terrain_fill_constraints(can_modify_list, p_terrain_set, constraints); + output = terrain_fill_constraints(p_layer, can_modify_list, p_terrain_set, constraints); return output; } @@ -2627,14 +2656,38 @@ void TileMap::set_cells_terrain_connect(int p_layer, TypedArray<Vector2i> p_cell ERR_FAIL_INDEX(p_layer, (int)layers.size()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); - Vector<Vector2i> vector_cells; + Vector<Vector2i> cells_vector; + HashSet<Vector2i> painted_set; for (int i = 0; i < p_cells.size(); i++) { - vector_cells.push_back(p_cells[i]); - } - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, vector_cells, p_terrain_set, p_terrain, p_ignore_empty_terrains); - for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) { - TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value); - set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + cells_vector.push_back(p_cells[i]); + painted_set.insert(p_cells[i]); + } + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_connect(p_layer, cells_vector, p_terrain_set, p_terrain, p_ignore_empty_terrains); + for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) { + if (painted_set.has(kv.key)) { + // Paint a random tile with the correct terrain for the painted path. + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } else { + // Avoids updating the painted path from the output if the new pattern is the same as before. + TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); + TileMapCell cell = get_cell(p_layer, kv.key); + if (cell.source_id != TileSet::INVALID_SOURCE) { + TileSetSource *source = *tile_set->get_source(cell.source_id); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + // Get tile data. + TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + in_map_terrain_pattern = tile_data->get_terrains_pattern(); + } + } + } + if (in_map_terrain_pattern != kv.value) { + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } + } } } @@ -2644,13 +2697,38 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); Vector<Vector2i> vector_path; + HashSet<Vector2i> painted_set; for (int i = 0; i < p_path.size(); i++) { vector_path.push_back(p_path[i]); + painted_set.insert(p_path[i]); } + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_output = terrain_fill_path(p_layer, vector_path, p_terrain_set, p_terrain, p_ignore_empty_terrains); - for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &E : terrain_fill_output) { - TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, E.value); - set_cell(p_layer, E.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : terrain_fill_output) { + if (painted_set.has(kv.key)) { + // Paint a random tile with the correct terrain for the painted path. + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } else { + // Avoids updating the painted path from the output if the new pattern is the same as before. + TileSet::TerrainsPattern in_map_terrain_pattern = TileSet::TerrainsPattern(*tile_set, p_terrain_set); + TileMapCell cell = get_cell(p_layer, kv.key); + if (cell.source_id != TileSet::INVALID_SOURCE) { + TileSetSource *source = *tile_set->get_source(cell.source_id); + TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); + if (atlas_source) { + // Get tile data. + TileData *tile_data = atlas_source->get_tile_data(cell.get_atlas_coords(), cell.alternative_tile); + if (tile_data && tile_data->get_terrain_set() == p_terrain_set) { + in_map_terrain_pattern = tile_data->get_terrains_pattern(); + } + } + } + if (in_map_terrain_pattern != kv.value) { + TileMapCell c = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value); + set_cell(p_layer, kv.key, c.source_id, c.get_atlas_coords(), c.alternative_tile); + } + } } } @@ -3717,13 +3795,14 @@ void TileMap::set_use_parent_material(bool p_use_parent_material) { } void TileMap::set_texture_filter(TextureFilter p_texture_filter) { - // Set a default texture filter for the whole tilemap + // Set a default texture filter for the whole tilemap. CanvasItem::set_texture_filter(p_texture_filter); + TextureFilter target_filter = get_texture_filter_in_tree(); for (unsigned int layer = 0; layer < layers.size(); layer++) { for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) { TileMapQuadrant &q = F->value; for (const RID &ci : q.canvas_items) { - RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(p_texture_filter)); + RenderingServer::get_singleton()->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(target_filter)); _make_quadrant_dirty(F); } } @@ -3732,13 +3811,14 @@ void TileMap::set_texture_filter(TextureFilter p_texture_filter) { } void TileMap::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) { - // Set a default texture repeat for the whole tilemap + // Set a default texture repeat for the whole tilemap. CanvasItem::set_texture_repeat(p_texture_repeat); + TextureRepeat target_repeat = get_texture_repeat_in_tree(); for (unsigned int layer = 0; layer < layers.size(); layer++) { for (HashMap<Vector2i, TileMapQuadrant>::Iterator F = layers[layer].quadrant_map.begin(); F; ++F) { TileMapQuadrant &q = F->value; for (const RID &ci : q.canvas_items) { - RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(p_texture_repeat)); + RenderingServer::get_singleton()->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(target_repeat)); _make_quadrant_dirty(F); } } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index d468675e91..7f3e241871 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -266,9 +266,9 @@ private: void _scenes_draw_quadrant_debug(TileMapQuadrant *p_quadrant); // Terrains. - TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints); + TileSet::TerrainsPattern _get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, RBSet<TerrainConstraint> p_constraints, TileSet::TerrainsPattern p_current_pattern); RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(Vector2i p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; - RBSet<TerrainConstraint> _get_terrain_constraints_from_cells_list(int p_layer, const RBSet<Vector2i> &p_on_map, int p_terrain_set, bool p_ignore_empty_terrains) const; + RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(int p_layer, const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const; // Set and get tiles from data arrays. void _set_tile_data(int p_layer, const Vector<int> &p_data); @@ -352,7 +352,7 @@ public: void set_pattern(int p_layer, Vector2i p_position, const Ref<TileMapPattern> p_pattern); // Terrains. - HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed. + HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_constraints(int p_layer, const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> p_constraints); // Not exposed. HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_connect(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_path(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); // Not exposed. HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(int p_layer, const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true); // Not exposed. diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index cefa9eceff..c6433e773d 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -578,11 +578,11 @@ bool Area3D::is_using_reverb_bus() const { return use_reverb_bus; } -void Area3D::set_reverb_bus(const StringName &p_audio_bus) { +void Area3D::set_reverb_bus_name(const StringName &p_audio_bus) { reverb_bus = p_audio_bus; } -StringName Area3D::get_reverb_bus() const { +StringName Area3D::get_reverb_bus_name() const { for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) { if (AudioServer::get_singleton()->get_bus_name(i) == reverb_bus) { return reverb_bus; @@ -711,8 +711,8 @@ void Area3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_reverb_bus", "enable"), &Area3D::set_use_reverb_bus); ClassDB::bind_method(D_METHOD("is_using_reverb_bus"), &Area3D::is_using_reverb_bus); - ClassDB::bind_method(D_METHOD("set_reverb_bus", "name"), &Area3D::set_reverb_bus); - ClassDB::bind_method(D_METHOD("get_reverb_bus"), &Area3D::get_reverb_bus); + ClassDB::bind_method(D_METHOD("set_reverb_bus_name", "name"), &Area3D::set_reverb_bus_name); + ClassDB::bind_method(D_METHOD("get_reverb_bus_name"), &Area3D::get_reverb_bus_name); ClassDB::bind_method(D_METHOD("set_reverb_amount", "amount"), &Area3D::set_reverb_amount); ClassDB::bind_method(D_METHOD("get_reverb_amount"), &Area3D::get_reverb_amount); @@ -760,8 +760,8 @@ void Area3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus_name", "get_audio_bus_name"); ADD_GROUP("Reverb Bus", "reverb_bus_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enable"), "set_use_reverb_bus", "is_using_reverb_bus"); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus", "get_reverb_bus"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reverb_bus_enabled"), "set_use_reverb_bus", "is_using_reverb_bus"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "reverb_bus_name", PROPERTY_HINT_ENUM, ""), "set_reverb_bus_name", "get_reverb_bus_name"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_amount", "get_reverb_amount"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "reverb_bus_uniformity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_reverb_uniformity", "get_reverb_uniformity"); diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h index 2125c35f67..195f9f0d9e 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/area_3d.h @@ -215,8 +215,8 @@ public: void set_use_reverb_bus(bool p_enable); bool is_using_reverb_bus() const; - void set_reverb_bus(const StringName &p_audio_bus); - StringName get_reverb_bus() const; + void set_reverb_bus_name(const StringName &p_audio_bus); + StringName get_reverb_bus_name() const; void set_reverb_amount(float p_amount); float get_reverb_amount() const; diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 76cf0d2fd0..40afbdf2ed 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -485,7 +485,7 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() { } if (area->is_using_reverb_bus()) { - StringName reverb_bus_name = area->get_reverb_bus(); + StringName reverb_bus_name = area->get_reverb_bus_name(); Vector<AudioFrame> reverb_vol; _calc_reverb_vol(area, listener_area_pos, output_volume_vector, reverb_vol); bus_volumes[reverb_bus_name] = reverb_vol; diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index b3437c4810..2c5df48b75 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -490,9 +490,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() { params.thickness = th; _compute_sdf(¶ms); - Ref<Image> ret; - ret.instantiate(); - ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data); + Ref<Image> ret = Image::create_from_data(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, cells_data); ret->convert(Image::FORMAT_RH); //convert to half, save space ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function @@ -532,7 +530,7 @@ void GPUParticlesCollisionSDF3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512,suffix:px"), "set_resolution", "get_resolution"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512"), "set_resolution", "get_resolution"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture"); diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 23fd091be6..198dba7811 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -165,6 +165,16 @@ AABB Light3D::get_aabb() const { return AABB(); } +PackedStringArray Light3D::get_configuration_warnings() const { + PackedStringArray warnings = VisualInstance3D::get_configuration_warnings(); + + if (!get_scale().is_equal_approx(Vector3(1, 1, 1))) { + warnings.push_back(RTR("A light's scale does not affect the visual size of the light.")); + } + + return warnings; +} + void Light3D::set_bake_mode(BakeMode p_mode) { bake_mode = p_mode; RS::get_singleton()->light_set_bake_mode(light, RS::LightBakeMode(p_mode)); @@ -579,7 +589,7 @@ OmniLight3D::ShadowMode OmniLight3D::get_shadow_mode() const { } PackedStringArray OmniLight3D::get_configuration_warnings() const { - PackedStringArray warnings = Node::get_configuration_warnings(); + PackedStringArray warnings = Light3D::get_configuration_warnings(); if (!has_shadow() && get_projector().is_valid()) { warnings.push_back(RTR("Projector texture only works with shadows active.")); @@ -609,7 +619,7 @@ OmniLight3D::OmniLight3D() : } PackedStringArray SpotLight3D::get_configuration_warnings() const { - PackedStringArray warnings = Node::get_configuration_warnings(); + PackedStringArray warnings = Light3D::get_configuration_warnings(); if (has_shadow() && get_param(PARAM_SPOT_ANGLE) >= 90.0) { warnings.push_back(RTR("A SpotLight3D with an angle wider than 90 degrees cannot cast shadows.")); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 8da45bee79..84d214030b 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -147,6 +147,7 @@ public: Color get_correlated_color() const; virtual AABB get_aabb() const override; + virtual PackedStringArray get_configuration_warnings() const override; Light3D(); ~Light3D(); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index 3ea1de57cd..1b5427c80d 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -145,10 +145,7 @@ Array LightmapGIData::_get_light_textures_data() const { for (int i = 0; i < texture_count; i++) { int texture_slice_count = (i == texture_count - 1 && last_count != 0) ? last_count : slices_per_texture; - Ref<Image> texture_image; - texture_image.instantiate(); - - texture_image->create(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); + Ref<Image> texture_image = Image::create_empty(slice_width, slice_height * texture_slice_count, false, images[0]->get_format()); for (int j = 0; j < texture_slice_count; j++) { texture_image->blit_rect(images[i * slices_per_texture + j], Rect2i(0, 0, slice_width, slice_height), Point2i(0, slice_height * j)); @@ -818,7 +815,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } md.albedo_on_uv2.instantiate(); - md.albedo_on_uv2->create(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom); + md.albedo_on_uv2->set_data(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom); } md.emission_on_uv2 = images[RS::BAKE_CHANNEL_EMISSION]; @@ -1054,7 +1051,7 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa } break; case ENVIRONMENT_MODE_CUSTOM_COLOR: { environment_image.instantiate(); - environment_image->create(128, 64, false, Image::FORMAT_RGBAF); + environment_image->initialize_data(128, 64, false, Image::FORMAT_RGBAF); Color c = environment_custom_color; c.r *= environment_custom_energy; c.g *= environment_custom_energy; diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index 39068fe83c..f64cabb75c 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -495,8 +495,8 @@ void NavigationAgent3D::_request_repath() { void NavigationAgent3D::_check_distance_to_target() { if (!target_reached) { if (distance_to_target() < target_desired_distance) { - emit_signal(SNAME("target_reached")); target_reached = true; + emit_signal(SNAME("target_reached")); } } } diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 5f515acead..1743fa1838 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -253,9 +253,7 @@ Vector3 Node3D::get_global_rotation() const { void Node3D::set_global_rotation(const Vector3 &p_euler_rad) { Transform3D transform = get_global_transform(); - Basis new_basis = transform.get_basis(); - new_basis.set_euler(p_euler_rad); - transform.set_basis(new_basis); + transform.basis = Basis::from_euler(p_euler_rad); set_global_transform(transform); } diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 90c7bc89ef..457f634c34 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -71,8 +71,8 @@ public: }; private: - // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaterinon/Scale and Euler Rotation/Scale. - // Transform and Quaterinon are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand). + // For the sake of ease of use, Node3D can operate with Transforms (Basis+Origin), Quaternion/Scale and Euler Rotation/Scale. + // Transform and Quaternion are stored in data.local_transform Basis (so quaternion is not really stored, but converted back/forth from 3x3 matrix on demand). // Euler needs to be kept separate because converting to Basis and back may result in a different vector (which is troublesome for users // editing in the inspector, not only because of the numerical precision loss but because they expect these rotations to be consistent, or support // "redundant" rotations for animation interpolation, like going from 0 to 720 degrees). @@ -96,6 +96,7 @@ private: mutable SelfList<Node> xform_change; + // This Data struct is to avoid namespace pollution in derived classes. struct Data { mutable Transform3D global_transform; mutable Transform3D local_transform; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index cc69a1cc51..be6eab2178 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -810,7 +810,7 @@ void Sprite3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "suffix:px", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); ADD_GROUP("Region", "region_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect", PROPERTY_HINT_NONE, "suffix:px"), "set_region_rect", "get_region_rect"); diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp index 2013a93e26..6d4c18a69e 100644 --- a/scene/3d/visible_on_screen_notifier_3d.cpp +++ b/scene/3d/visible_on_screen_notifier_3d.cpp @@ -189,7 +189,7 @@ void VisibleOnScreenEnabler3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibleOnScreenEnabler3D::get_enable_node_path); ADD_GROUP("Enabling", "enable_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,When Paused"), "set_enable_mode", "get_enable_mode"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path"); BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT); diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index e93ad5ecbf..3868d1e42e 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -40,10 +40,6 @@ AABB VisualInstance3D::get_aabb() const { return AABB(); } -AABB VisualInstance3D::get_transformed_aabb() const { - return get_global_transform().xform(get_aabb()); -} - void VisualInstance3D::_update_visibility() { if (!is_inside_tree()) { return; @@ -121,8 +117,6 @@ void VisualInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer_mask_value", "layer_number", "value"), &VisualInstance3D::set_layer_mask_value); ClassDB::bind_method(D_METHOD("get_layer_mask_value", "layer_number"), &VisualInstance3D::get_layer_mask_value); - ClassDB::bind_method(D_METHOD("get_transformed_aabb"), &VisualInstance3D::get_transformed_aabb); - GDVIRTUAL_BIND(_get_aabb); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_RENDER), "set_layer_mask", "get_layer_mask"); } diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 4755545516..06a8c05faa 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -60,8 +60,6 @@ public: RID get_instance() const; virtual AABB get_aabb() const; - virtual AABB get_transformed_aabb() const; // helper - void set_base(const RID &p_base); RID get_base() const; diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index 3dba0221bb..7caf2f4874 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -77,9 +77,7 @@ Dictionary VoxelGIData::_get_data() const { d["octree_cells"] = get_octree_cells(); d["octree_data"] = get_data_cells(); if (otsize != Vector3i()) { - Ref<Image> img; - img.instantiate(); - img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field()); + Ref<Image> img = Image::create_from_data(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field()); Vector<uint8_t> df_png = img->save_png_to_buffer(); ERR_FAIL_COND_V(df_png.size() == 0, Dictionary()); d["octree_df_png"] = df_png; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 4401d22f30..f5d30c584f 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -36,49 +36,37 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// -void XRCamera3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - // need to find our XROrigin3D parent and let it know we're its camera! - XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); - if (origin != nullptr) { - origin->set_tracked_camera(this); - } - } break; +void XRCamera3D::_bind_tracker() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); - case NOTIFICATION_EXIT_TREE: { - // need to find our XROrigin3D parent and let it know we're no longer its camera! - XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); - if (origin != nullptr && origin->get_tracked_camera() == this) { - origin->set_tracked_camera(nullptr); - } - } break; + tracker = xr_server->get_tracker(tracker_name); + if (tracker.is_valid()) { + tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); + + Ref<XRPose> pose = tracker->get_pose(pose_name); + if (pose.is_valid()) { + set_transform(pose->get_adjusted_transform()); + } } } +void XRCamera3D::_unbind_tracker() { + if (tracker.is_valid()) { + tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); + } + tracker.unref(); +} + void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) { if (p_tracker_name == tracker_name) { - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL(xr_server); - - tracker = xr_server->get_tracker(p_tracker_name); - if (tracker.is_valid()) { - tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); - - Ref<XRPose> pose = tracker->get_pose(pose_name); - if (pose.is_valid()) { - set_transform(pose->get_adjusted_transform()); - } - } + _bind_tracker(); } } void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) { if (p_tracker_name == tracker_name) { - if (tracker.is_valid()) { - tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed)); - } - tracker.unref(); + _unbind_tracker(); } } @@ -213,6 +201,9 @@ XRCamera3D::XRCamera3D() { xr_server->connect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker)); xr_server->connect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker)); xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker)); + + // check if our tracker already exists and if so, bind it... + _bind_tracker(); } XRCamera3D::~XRCamera3D() { @@ -372,7 +363,7 @@ void XRNode3D::_unbind_tracker() { } void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) { - if (p_tracker_name == p_tracker_name) { + if (tracker_name == p_tracker_name) { // just in case unref our current tracker _unbind_tracker(); @@ -382,7 +373,7 @@ void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_t } void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) { - if (p_tracker_name == p_tracker_name) { + if (tracker_name == p_tracker_name) { // unref our tracker, it's no longer available _unbind_tracker(); } @@ -582,11 +573,22 @@ Plane XRAnchor3D::get_plane() const { //////////////////////////////////////////////////////////////////////////////////////////////////// +Vector<XROrigin3D *> XROrigin3D::origin_nodes; + PackedStringArray XROrigin3D::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); if (is_visible() && is_inside_tree()) { - if (tracked_camera == nullptr) { + bool has_camera = false; + for (int i = 0; !has_camera && i < get_child_count(); i++) { + XRCamera3D *camera = Object::cast_to<XRCamera3D>(get_child(i)); + if (camera) { + // found it! + has_camera = true; + } + } + + if (!has_camera) { warnings.push_back(RTR("XROrigin3D requires an XRCamera3D child node.")); } } @@ -603,14 +605,10 @@ void XROrigin3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale); ClassDB::bind_method(D_METHOD("get_world_scale"), &XROrigin3D::get_world_scale); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale"); -} -void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) { - tracked_camera = p_tracked_camera; -} - -XRCamera3D *XROrigin3D::get_tracked_camera() const { - return tracked_camera; + ClassDB::bind_method(D_METHOD("set_current", "enabled"), &XROrigin3D::set_current); + ClassDB::bind_method(D_METHOD("is_current"), &XROrigin3D::is_current); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); } real_t XROrigin3D::get_world_scale() const { @@ -629,6 +627,44 @@ void XROrigin3D::set_world_scale(real_t p_world_scale) { xr_server->set_world_scale(p_world_scale); } +void XROrigin3D::set_current(bool p_enabled) { + current = p_enabled; + + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; + } + + // Notify us of any transform changes + set_notify_local_transform(current); + set_notify_transform(current); + + if (current) { + for (int i = 0; i < origin_nodes.size(); i++) { + if (origin_nodes[i] != this) { + origin_nodes[i]->set_current(false); + } + } + } else { + bool found = false; + // We no longer have a current origin so find the first one we can make current + for (int i = 0; !found && i < origin_nodes.size(); i++) { + if (origin_nodes[i] != this) { + origin_nodes[i]->set_current(true); + found = true; + } + } + } +} + +bool XROrigin3D::is_current() const { + if (Engine::get_singleton()->is_editor_hint()) { + // return as is + return current; + } else { + return current && is_inside_tree(); + } +} + void XROrigin3D::_notification(int p_what) { // get our XRServer XRServer *xr_server = XRServer::get_singleton(); @@ -636,34 +672,47 @@ void XROrigin3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - set_process_internal(true); + if (!Engine::get_singleton()->is_editor_hint()) { + if (origin_nodes.is_empty()) { + // first entry always becomes current + current = true; + } + + origin_nodes.push_back(this); + + if (current) { + // set this again so we do whatever setup is needed. + set_current(true); + } + } } break; case NOTIFICATION_EXIT_TREE: { - set_process_internal(false); - } break; - - case NOTIFICATION_INTERNAL_PROCESS: { - // set our world origin to our node transform - xr_server->set_world_origin(get_global_transform()); + if (!Engine::get_singleton()->is_editor_hint()) { + origin_nodes.erase(this); - // check if we have a primary interface - Ref<XRInterface> xr_interface = xr_server->get_primary_interface(); - if (xr_interface.is_valid() && tracked_camera != nullptr) { - // get our positioning transform for our headset - Transform3D t = xr_interface->get_camera_transform(); + if (current) { + // We are no longer current + set_current(false); + } + } + } break; - // now apply this to our camera - tracked_camera->set_transform(t); + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: + case NOTIFICATION_TRANSFORM_CHANGED: { + if (current && !Engine::get_singleton()->is_editor_hint()) { + xr_server->set_world_origin(get_global_transform()); } } break; } - // send our notification to all active XE interfaces, they may need to react to it also - for (int i = 0; i < xr_server->get_interface_count(); i++) { - Ref<XRInterface> interface = xr_server->get_interface(i); - if (interface.is_valid() && interface->is_initialized()) { - interface->notification(p_what); + if (current) { + // send our notification to all active XE interfaces, they may need to react to it also + for (int i = 0; i < xr_server->get_interface_count(); i++) { + Ref<XRInterface> interface = xr_server->get_interface(i); + if (interface.is_valid() && interface->is_initialized()) { + interface->notification(p_what); + } } } } diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index ef846cc3a3..990fb61983 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -48,8 +48,8 @@ protected: StringName pose_name = "default"; Ref<XRPositionalTracker> tracker; - void _notification(int p_what); - + void _bind_tracker(); + void _unbind_tracker(); void _changed_tracker(const StringName p_tracker_name, int p_tracker_type); void _removed_tracker(const StringName p_tracker_name, int p_tracker_type); void _pose_changed(const Ref<XRPose> &p_pose); @@ -180,7 +180,8 @@ class XROrigin3D : public Node3D { GDCLASS(XROrigin3D, Node3D); private: - XRCamera3D *tracked_camera = nullptr; + bool current = false; + static Vector<XROrigin3D *> origin_nodes; // all origin nodes in tree protected: void _notification(int p_what); @@ -189,12 +190,12 @@ protected: public: PackedStringArray get_configuration_warnings() const override; - void set_tracked_camera(XRCamera3D *p_tracked_camera); - XRCamera3D *get_tracked_camera() const; - real_t get_world_scale() const; void set_world_scale(real_t p_world_scale); + void set_current(bool p_enabled); + bool is_current() const; + XROrigin3D() {} ~XROrigin3D() {} }; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index fe67c0886f..e306d00a51 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -109,7 +109,7 @@ bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) { Ref<AnimationLibrary> lib = d[lib_name]; add_animation_library(lib_name, lib); } - + emit_signal("animation_libraries_updated"); } else if (name.begins_with("next/")) { String which = name.get_slicec('/', 1); animation_set_next(which, p_value); @@ -1274,6 +1274,23 @@ void AnimationPlayer::_animation_set_cache_update() { } void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) { + { + int at_pos = -1; + + for (uint32_t i = 0; i < animation_libraries.size(); i++) { + if (animation_libraries[i].name == p_library) { + at_pos = i; + break; + } + } + + ERR_FAIL_COND(at_pos == -1); + + ERR_FAIL_COND(!animation_libraries[at_pos].library->animations.has(p_name)); + + _ref_anim(animation_libraries[at_pos].library->animations[p_name]); + } + _animation_set_cache_update(); } @@ -1283,6 +1300,12 @@ void AnimationPlayer::_animation_removed(const StringName &p_name, const StringN if (!animation_set.has(name)) { return; // No need to update because not the one from the library being used. } + + AnimationData animation_data = animation_set[name]; + if (animation_data.animation_library == p_library) { + _unref_anim(animation_data.animation); + } + _animation_set_cache_update(); // Erase blends if needed @@ -1376,9 +1399,13 @@ Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref animation_libraries.insert(insert_pos, ald); ald.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_name)); - ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_name)); + ald.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_name)); ald.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_name)); + for (const KeyValue<StringName, Ref<Animation>> &K : ald.library->animations) { + _ref_anim(K.value); + } + _animation_set_cache_update(); notify_property_list_changed(); @@ -1399,7 +1426,7 @@ void AnimationPlayer::remove_animation_library(const StringName &p_name) { ERR_FAIL_COND(at_pos == -1); animation_libraries[at_pos].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added)); - animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added)); + animation_libraries[at_pos].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed)); animation_libraries[at_pos].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed)); stop(); @@ -1438,11 +1465,11 @@ void AnimationPlayer::rename_animation_library(const StringName &p_name, const S animation_libraries[i].name = p_new_name; // rename connections animation_libraries[i].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added)); - animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added)); + animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed)); animation_libraries[i].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed)); animation_libraries[i].library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name)); - animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name)); + animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name)); animation_libraries[i].library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name)); for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) { @@ -2151,6 +2178,7 @@ void AnimationPlayer::_bind_methods() { ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name"))); ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name"))); ADD_SIGNAL(MethodInfo("animation_list_changed")); + ADD_SIGNAL(MethodInfo("animation_libraries_updated")); ADD_SIGNAL(MethodInfo("caches_cleared")); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index af6a99ca62..552345e4fe 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -60,7 +60,7 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) { } Ref<InputEventMouseButton> mouse_button = p_event; - bool ui_accept = p_event->is_action("ui_accept") && !p_event->is_echo(); + bool ui_accept = p_event->is_action("ui_accept", true) && !p_event->is_echo(); bool button_masked = mouse_button.is_valid() && (mouse_button_to_mask(mouse_button->get_button_index()) & button_mask) != MouseButton::NONE; if (button_masked || ui_accept) { @@ -349,10 +349,6 @@ Ref<Shortcut> BaseButton::get_shortcut() const { void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shortcut_context()) { - return; - } - if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) { on_action_event(p_event); accept_event(); @@ -389,34 +385,6 @@ Ref<ButtonGroup> BaseButton::get_button_group() const { return button_group; } -void BaseButton::set_shortcut_context(Node *p_node) { - if (p_node != nullptr) { - shortcut_context = p_node->get_instance_id(); - } else { - shortcut_context = ObjectID(); - } -} - -Node *BaseButton::get_shortcut_context() const { - Object *ctx_obj = ObjectDB::get_instance(shortcut_context); - Node *ctx_node = Object::cast_to<Node>(ctx_obj); - - return ctx_node; -} - -bool BaseButton::_is_focus_owner_in_shortcut_context() const { - if (shortcut_context == ObjectID()) { - // No context, therefore global - always "in" context. - return true; - } - - Node *ctx_node = get_shortcut_context(); - Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; - - // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. - return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); -} - bool BaseButton::_was_pressed_by_mouse() const { return was_mouse_pressed; } @@ -446,9 +414,6 @@ void BaseButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group); ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group); - ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &BaseButton::set_shortcut_context); - ClassDB::bind_method(D_METHOD("get_shortcut_context"), &BaseButton::get_shortcut_context); - GDVIRTUAL_BIND(_pressed); GDVIRTUAL_BIND(_toggled, "button_pressed"); @@ -466,7 +431,6 @@ void BaseButton::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_pressed_outside"), "set_keep_pressed_outside", "is_keep_pressed_outside"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "Shortcut"), "set_shortcut", "get_shortcut"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "button_group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); BIND_ENUM_CONSTANT(DRAW_NORMAL); BIND_ENUM_CONSTANT(DRAW_PRESSED); diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index c83b08aadf..7839239800 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -81,7 +81,6 @@ protected: virtual void shortcut_input(const Ref<InputEvent> &p_event) override; void _notification(int p_what); - bool _is_focus_owner_in_shortcut_context() const; bool _was_pressed_by_mouse() const; GDVIRTUAL0(_pressed) @@ -132,9 +131,6 @@ public: void set_button_group(const Ref<ButtonGroup> &p_group); Ref<ButtonGroup> get_button_group() const; - void set_shortcut_context(Node *p_node); - Node *get_shortcut_context() const; - BaseButton(); ~BaseButton(); }; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 70707dba11..8a5d04f49c 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -1248,37 +1248,41 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const { } void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) { - bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT); - if (draw_breakpoints && breakpoint_icon.is_valid()) { - bool hovering = p_region.has_point(get_local_mouse_pos()); bool breakpointed = is_line_breakpointed(p_line); + bool hovering = p_region.has_point(get_local_mouse_pos()); + bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT); if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) { int padding = p_region.size.x / 6; + + Color use_color = breakpoint_color; + if (hovering && !shift_pressed) { + use_color = breakpointed ? use_color.lightened(0.3) : use_color.darkened(0.5); + } Rect2 icon_region = p_region; icon_region.position += Point2(padding, padding); icon_region.size -= Point2(padding, padding) * 2; - - // Darken icon when hovering, shift not pressed & not yet breakpointed. - Color use_color = hovering && !breakpointed && !shift_pressed ? breakpoint_color.darkened(0.4) : breakpoint_color; breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color); } } if (draw_bookmarks && bookmark_icon.is_valid()) { - bool hovering = p_region.has_point(get_local_mouse_pos()); bool bookmarked = is_line_bookmarked(p_line); + bool hovering = p_region.has_point(get_local_mouse_pos()); + bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT); if (bookmarked || (hovering && !is_dragging_cursor() && shift_pressed)) { int horizontal_padding = p_region.size.x / 2; int vertical_padding = p_region.size.y / 4; + + Color use_color = bookmark_color; + if (hovering && shift_pressed) { + use_color = bookmarked ? use_color.lightened(0.3) : use_color.darkened(0.5); + } Rect2 icon_region = p_region; icon_region.position += Point2(horizontal_padding, 0); icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding); - - // Darken icon when hovering, shift pressed & not yet bookmarked. - Color use_color = hovering && !bookmarked && shift_pressed ? bookmark_color.darkened(0.4) : bookmark_color; bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color); } } @@ -1287,10 +1291,10 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 int horizontal_padding = p_region.size.x / 10; int vertical_padding = p_region.size.y / 4; - Rect2 executing_line_region = p_region; - executing_line_region.position += Point2(horizontal_padding, vertical_padding); - executing_line_region.size -= Point2(horizontal_padding, vertical_padding) * 2; - executing_line_icon->draw_rect(get_canvas_item(), executing_line_region, false, executing_line_color); + Rect2 icon_region = p_region; + icon_region.position += Point2(horizontal_padding, vertical_padding); + icon_region.size -= Point2(horizontal_padding, vertical_padding) * 2; + executing_line_icon->draw_rect(get_canvas_item(), icon_region, false, executing_line_color); } } diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index f1e18640e6..929bf27be6 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -1367,7 +1367,7 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) { Ref<Image> img = r->get_texture()->get_image(); if (img.is_valid() && !img->is_empty()) { - Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position(); + Vector2 ofs = mev->get_global_position(); Color c = img->get_pixel(ofs.x, ofs.y); set_pick_color(c); @@ -1403,9 +1403,7 @@ void ColorPicker::_screen_pick_pressed() { screen->show(); } screen->move_to_front(); -#ifndef _MSC_VER -#warning show modal no longer works, needs to be converted to a popup -#endif + // TODO: show modal no longer works, needs to be converted to a popup. //screen->show_modal(); } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 2dcae2553c..2ec0a48278 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1436,13 +1436,6 @@ Rect2 Control::get_screen_rect() const { return r; } -Rect2 Control::get_window_rect() const { - ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); - Rect2 gr = get_global_rect(); - gr.position += get_viewport()->get_visible_rect().position; - return gr; -} - Rect2 Control::get_anchorable_rect() const { return Rect2(Point2(), get_size()); } @@ -1564,7 +1557,7 @@ Size2 Control::get_minimum_size() const { return Vector2(); } -void Control::set_custom_minimum_size(const Size2i &p_custom) { +void Control::set_custom_minimum_size(const Size2 &p_custom) { if (p_custom == data.custom_minimum_size) { return; } @@ -1572,7 +1565,7 @@ void Control::set_custom_minimum_size(const Size2i &p_custom) { update_minimum_size(); } -Size2i Control::get_custom_minimum_size() const { +Size2 Control::get_custom_minimum_size() const { return data.custom_minimum_size; } @@ -1759,6 +1752,34 @@ void Control::warp_mouse(const Point2 &p_position) { get_viewport()->warp_mouse(get_global_transform_with_canvas().xform(p_position)); } +void Control::set_shortcut_context(const Node *p_node) { + if (p_node != nullptr) { + data.shortcut_context = p_node->get_instance_id(); + } else { + data.shortcut_context = ObjectID(); + } +} + +Node *Control::get_shortcut_context() const { + Object *ctx_obj = ObjectDB::get_instance(data.shortcut_context); + Node *ctx_node = Object::cast_to<Node>(ctx_obj); + + return ctx_node; +} + +bool Control::is_focus_owner_in_shortcut_context() const { + if (data.shortcut_context == ObjectID()) { + // No context, therefore global - always "in" context. + return true; + } + + const Node *ctx_node = get_shortcut_context(); + const Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; + + // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. + return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); +} + // Drag and drop handling. void Control::set_drag_forwarding(Object *p_target) { @@ -2885,8 +2906,8 @@ void Control::_notification(int p_notification) { if (data.parent_canvas_item) { data.parent_canvas_item->disconnect("item_rect_changed", callable_mp(this, &Control::_size_changed)); data.parent_canvas_item = nullptr; - } else if (!is_set_as_top_level()) { - //disconnect viewport + } else { + // Disconnect viewport. Viewport *viewport = get_viewport(); ERR_FAIL_COND(!viewport); viewport->disconnect("size_changed", callable_mp(this, &Control::_size_changed)); @@ -3133,6 +3154,9 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("warp_mouse", "position"), &Control::warp_mouse); + ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &Control::set_shortcut_context); + ClassDB::bind_method(D_METHOD("get_shortcut_context"), &Control::get_shortcut_context); + ClassDB::bind_method(D_METHOD("update_minimum_size"), &Control::update_minimum_size); ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Control::set_layout_direction); @@ -3144,7 +3168,7 @@ void Control::_bind_methods() { ADD_GROUP("Layout", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode"); ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION); @@ -3206,6 +3230,9 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mouse_force_pass_scroll_events"), "set_force_pass_scroll_events", "is_force_pass_scroll_events"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,I-Beam,Pointing Hand,Cross,Wait,Busy,Drag,Can Drop,Forbidden,Vertical Resize,Horizontal Resize,Secondary Diagonal Resize,Main Diagonal Resize,Move,Vertical Split,Horizontal Split,Help"), "set_default_cursor_shape", "get_default_cursor_shape"); + ADD_GROUP("Input", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); + 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"); diff --git a/scene/gui/control.h b/scene/gui/control.h index ee6443c81c..72e870930d 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -159,6 +159,7 @@ private: } }; + // This Data struct is to avoid namespace pollution in derived classes. struct Data { // Global relations. @@ -200,7 +201,7 @@ private: int h_size_flags = SIZE_FILL; int v_size_flags = SIZE_FILL; real_t expand = 1.0; - Point2i custom_minimum_size; + Point2 custom_minimum_size; // Input events and rendering. @@ -218,6 +219,8 @@ private: NodePath focus_next; NodePath focus_prev; + ObjectID shortcut_context; + // Theming. ThemeOwner *theme_owner = nullptr; @@ -442,7 +445,6 @@ public: Rect2 get_rect() const; Rect2 get_global_rect() const; Rect2 get_screen_rect() const; - Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the rendering server Rect2 get_anchorable_rect() const override; void set_scale(const Vector2 &p_scale); @@ -460,8 +462,8 @@ public: virtual Size2 get_minimum_size() const; virtual Size2 get_combined_minimum_size() const; - void set_custom_minimum_size(const Size2i &p_custom); - Size2i get_custom_minimum_size() const; + void set_custom_minimum_size(const Size2 &p_custom); + Size2 get_custom_minimum_size() const; // Container sizing. @@ -487,6 +489,10 @@ public: void warp_mouse(const Point2 &p_position); + bool is_focus_owner_in_shortcut_context() const; + void set_shortcut_context(const Node *p_node); + Node *get_shortcut_context() const; + // Drag and drop handling. virtual void set_drag_forwarding(Object *p_target); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 90552c32c2..caf8db4515 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -1385,16 +1385,16 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) { } if (p_ev->is_pressed()) { - if (p_ev->is_action("ui_graph_duplicate")) { + if (p_ev->is_action("ui_graph_duplicate", true)) { emit_signal(SNAME("duplicate_nodes_request")); accept_event(); - } else if (p_ev->is_action("ui_copy")) { + } else if (p_ev->is_action("ui_copy", true)) { emit_signal(SNAME("copy_nodes_request")); accept_event(); - } else if (p_ev->is_action("ui_paste")) { + } else if (p_ev->is_action("ui_paste", true)) { emit_signal(SNAME("paste_nodes_request")); accept_event(); - } else if (p_ev->is_action("ui_graph_delete")) { + } else if (p_ev->is_action("ui_graph_delete", true)) { TypedArray<StringName> nodes; for (int i = 0; i < get_child_count(); i++) { diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 0dc791f71d..223428906a 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -728,7 +728,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } if (p_event->is_pressed() && items.size() > 0) { - if (p_event->is_action("ui_up")) { + if (p_event->is_action("ui_up", true)) { if (!search_string.is_empty()) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; @@ -766,7 +766,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_down")) { + } else if (p_event->is_action("ui_down", true)) { if (!search_string.is_empty()) { uint64_t now = OS::get_singleton()->get_ticks_msec(); uint64_t diff = now - search_time_msec; @@ -803,7 +803,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_page_up")) { + } else if (p_event->is_action("ui_page_up", true)) { search_string = ""; //any mousepress cancels for (int i = 4; i > 0; i--) { @@ -817,7 +817,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { break; } } - } else if (p_event->is_action("ui_page_down")) { + } else if (p_event->is_action("ui_page_down", true)) { search_string = ""; //any mousepress cancels for (int i = 4; i > 0; i--) { @@ -832,7 +832,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { break; } } - } else if (p_event->is_action("ui_left")) { + } else if (p_event->is_action("ui_left", true)) { search_string = ""; //any mousepress cancels if (current % current_columns != 0) { @@ -852,7 +852,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_right")) { + } else if (p_event->is_action("ui_right", true)) { search_string = ""; //any mousepress cancels if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) { @@ -872,9 +872,9 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { } accept_event(); } - } else if (p_event->is_action("ui_cancel")) { + } else if (p_event->is_action("ui_cancel", true)) { search_string = ""; - } else if (p_event->is_action("ui_select") && select_mode == SELECT_MULTI) { + } else if (p_event->is_action("ui_select", true) && select_mode == SELECT_MULTI) { if (current >= 0 && current < items.size()) { if (items[current].selectable && !items[current].disabled && !items[current].selected) { select(current, false); @@ -884,7 +884,7 @@ void ItemList::gui_input(const Ref<InputEvent> &p_event) { emit_signal(SNAME("multi_selected"), current, false); } } - } else if (p_event->is_action("ui_accept")) { + } else if (p_event->is_action("ui_accept", true)) { search_string = ""; //any mousepress cancels if (current >= 0 && current < items.size()) { diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 63401ca195..2203573bbc 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -288,6 +288,36 @@ void Label::_update_theme_item_cache() { theme_cache.font_shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size")); } +PackedStringArray Label::get_configuration_warnings() const { + PackedStringArray warnings = Control::get_configuration_warnings(); + + // Ensure that the font can render all of the required glyphs. + Ref<Font> font; + if (settings.is_valid()) { + font = settings->get_font(); + } + if (font.is_null()) { + font = theme_cache.font; + } + + if (font.is_valid()) { + if (dirty || font_dirty || lines_dirty) { + const_cast<Label *>(this)->_shape(); + } + + const Glyph *glyph = TS->shaped_text_get_glyphs(text_rid); + int64_t glyph_count = TS->shaped_text_get_glyph_count(text_rid); + for (int64_t i = 0; i < glyph_count; i++) { + if (glyph[i].font_rid == RID()) { + warnings.push_back(RTR("The current font does not support rendering one or more characters used in this Label's text.")); + break; + } + } + } + + return warnings; +} + void Label::_notification(int p_what) { switch (p_what) { case NOTIFICATION_TRANSLATION_CHANGED: { @@ -302,6 +332,7 @@ void Label::_notification(int p_what) { dirty = true; queue_redraw(); + update_configuration_warnings(); } break; case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { @@ -674,6 +705,7 @@ void Label::set_text(const String &p_string) { } queue_redraw(); update_minimum_size(); + update_configuration_warnings(); } void Label::_invalidate() { diff --git a/scene/gui/label.h b/scene/gui/label.h index b79c94a5ba..41d7049b22 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -93,6 +93,7 @@ protected: public: virtual Size2 get_minimum_size() const override; + virtual PackedStringArray get_configuration_warnings() const override; void set_horizontal_alignment(HorizontalAlignment p_alignment); HorizontalAlignment get_horizontal_alignment() const; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 36e85b5d02..65670b7786 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -2175,6 +2175,12 @@ void LineEdit::_emit_text_change() { } void LineEdit::_shape() { + const Ref<Font> &font = theme_cache.font; + int font_size = theme_cache.font_size; + if (font.is_null()) { + return; + } + Size2 old_size = TS->shaped_text_get_size(text_rid); TS->shaped_text_clear(text_rid); @@ -2197,9 +2203,6 @@ void LineEdit::_shape() { } TS->shaped_text_set_preserve_control(text_rid, draw_control_chars); - const Ref<Font> &font = theme_cache.font; - int font_size = theme_cache.font_size; - ERR_FAIL_COND(font.is_null()); TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language); for (int i = 0; i < TextServer::SPACING_MAX; i++) { TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i))); diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 742042f65f..82ef53e317 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -41,7 +41,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) { } MutexLock lock(mutex); - if (p_event->is_action("ui_left") && p_event->is_pressed()) { + if (p_event->is_action("ui_left", true) && p_event->is_pressed()) { int new_sel = selected_menu; int old_sel = (selected_menu < 0) ? 0 : selected_menu; do { @@ -63,7 +63,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) { _open_popup(selected_menu, true); } return; - } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) { int new_sel = selected_menu; int old_sel = (selected_menu < 0) ? menu_cache.size() - 1 : selected_menu; do { @@ -149,10 +149,6 @@ void MenuBar::_open_popup(int p_index, bool p_focus_item) { void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shortcut_context()) { - return; - } - if (disable_shortcuts) { return; } @@ -175,34 +171,6 @@ void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) { } } -void MenuBar::set_shortcut_context(Node *p_node) { - if (p_node != nullptr) { - shortcut_context = p_node->get_instance_id(); - } else { - shortcut_context = ObjectID(); - } -} - -Node *MenuBar::get_shortcut_context() const { - Object *ctx_obj = ObjectDB::get_instance(shortcut_context); - Node *ctx_node = Object::cast_to<Node>(ctx_obj); - - return ctx_node; -} - -bool MenuBar::_is_focus_owner_in_shortcut_context() const { - if (shortcut_context == ObjectID()) { - // No context, therefore global - always "in" context. - return true; - } - - Node *ctx_node = get_shortcut_context(); - Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr; - - // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. - return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); -} - void MenuBar::_popup_visibility_changed(bool p_visible) { if (!p_visible) { active_menu = -1; @@ -694,16 +662,12 @@ void MenuBar::_bind_methods() { ClassDB::bind_method(D_METHOD("set_menu_hidden", "menu", "hidden"), &MenuBar::set_menu_hidden); ClassDB::bind_method(D_METHOD("is_menu_hidden", "menu"), &MenuBar::is_menu_hidden); - ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &MenuBar::set_shortcut_context); - ClassDB::bind_method(D_METHOD("get_shortcut_context"), &MenuBar::get_shortcut_context); - ClassDB::bind_method(D_METHOD("get_menu_popup", "menu"), &MenuBar::get_menu_popup); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_NODE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context"); ADD_GROUP("BiDi", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h index f7ef19e98b..c057a7c96f 100644 --- a/scene/gui/menu_bar.h +++ b/scene/gui/menu_bar.h @@ -118,8 +118,6 @@ class MenuBar : public Control { void _clear_menu(); void _update_menu(); - bool _is_focus_owner_in_shortcut_context() const; - protected: virtual void shortcut_input(const Ref<InputEvent> &p_event) override; @@ -170,9 +168,6 @@ public: void set_menu_hidden(int p_menu, bool p_hidden); bool is_menu_hidden(int p_menu) const; - void set_shortcut_context(Node *p_node); - Node *get_shortcut_context() const; - PopupMenu *get_menu_popup(int p_menu) const; virtual void get_translatable_strings(List<String> *p_strings) const override; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 78aeab9457..786f23873e 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -36,10 +36,6 @@ void MenuButton::shortcut_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - if (!_is_focus_owner_in_shortcut_context()) { - return; - } - if (disable_shortcuts) { return; } diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index a6915f9e61..434eb87e7a 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -77,28 +77,36 @@ void Popup::_update_theme_item_cache() { void Popup::_notification(int p_what) { switch (p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { - if (is_visible()) { - _initialize_visible_parents(); - } else { - _deinitialize_visible_parents(); - emit_signal(SNAME("popup_hide")); - popped_up = false; + if (!is_in_edited_scene_root()) { + if (is_visible()) { + _initialize_visible_parents(); + } else { + _deinitialize_visible_parents(); + emit_signal(SNAME("popup_hide")); + popped_up = false; + } } } break; case NOTIFICATION_WM_WINDOW_FOCUS_IN: { - if (has_focus()) { - popped_up = true; + if (!is_in_edited_scene_root()) { + if (has_focus()) { + popped_up = true; + } } } break; case NOTIFICATION_EXIT_TREE: { - _deinitialize_visible_parents(); + if (!is_in_edited_scene_root()) { + _deinitialize_visible_parents(); + } } break; case NOTIFICATION_WM_CLOSE_REQUEST: case NOTIFICATION_APPLICATION_FOCUS_OUT: { - _close_pressed(); + if (!is_in_edited_scene_root()) { + _close_pressed(); + } } break; } } @@ -126,6 +134,16 @@ void Popup::_bind_methods() { ADD_SIGNAL(MethodInfo("popup_hide")); } +void Popup::_validate_property(PropertyInfo &p_property) const { + if ( + p_property.name == "transient" || + p_property.name == "exclusive" || + p_property.name == "popup_window" || + p_property.name == "unfocusable") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } +} + Rect2i Popup::_popup_adjust_rect() const { ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); Rect2i parent_rect = get_usable_parent_rect(); diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 0d6ca25c18..57b811cadb 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -59,6 +59,7 @@ protected: virtual void _update_theme_item_cache() override; void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &p_property) const; virtual void _parent_focused(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 4cdde5902e..9a411ef7ed 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -273,7 +273,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); if (!items.is_empty()) { - if (p_event->is_action("ui_down") && p_event->is_pressed()) { + if (p_event->is_action("ui_down", true) && p_event->is_pressed()) { int search_from = mouse_over + 1; if (search_from >= items.size()) { search_from = 0; @@ -305,7 +305,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { } } } - } else if (p_event->is_action("ui_up") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_up", true) && p_event->is_pressed()) { int search_from = mouse_over - 1; if (search_from < 0) { search_from = items.size() - 1; @@ -337,7 +337,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { } } } - } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) { Node *n = get_parent(); if (n) { if (Object::cast_to<PopupMenu>(n)) { @@ -349,7 +349,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { return; } } - } else if (p_event->is_action("ui_right") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_right", true) && p_event->is_pressed()) { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) { _activate_submenu(mouse_over, true); set_input_as_handled(); @@ -361,7 +361,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) { return; } } - } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) { if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) { _activate_submenu(mouse_over, true); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 5060bacba5..c96d3c763d 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2019,36 +2019,36 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { if (k->is_pressed()) { bool handled = false; - if (k->is_action("ui_page_up") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_page_up", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() - vscroll->get_page()); handled = true; } - if (k->is_action("ui_page_down") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_page_down", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() + vscroll->get_page()); handled = true; } - if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_up", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() - theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } - if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_down", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() + theme_cache.normal_font->get_height(theme_cache.normal_font_size)); handled = true; } - if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_home", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(0); handled = true; } - if (k->is_action("ui_end") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_end", true) && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_max()); handled = true; } if (is_shortcut_keys_enabled()) { - if (k->is_action("ui_text_select_all")) { + if (k->is_action("ui_text_select_all", true)) { select_all(); handled = true; } - if (k->is_action("ui_copy")) { + if (k->is_action("ui_copy", true)) { selection_copy(); handled = true; } @@ -2956,7 +2956,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub memdelete(p_item); } -void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlignment p_alignment) { +void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlignment p_alignment, const Rect2 &p_region) { _stop_thread(); MutexLock data_lock(data_mutex); @@ -2969,7 +2969,15 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, ERR_FAIL_COND(p_image->get_height() == 0); ItemImage *item = memnew(ItemImage); - item->image = p_image; + if (p_region.has_area()) { + Ref<AtlasTexture> atlas_tex = memnew(AtlasTexture); + atlas_tex->set_atlas(p_image); + atlas_tex->set_region(p_region); + item->image = atlas_tex; + } else { + item->image = p_image; + } + item->color = p_color; item->inline_align = p_alignment; @@ -2981,17 +2989,30 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, item->size.height = p_height; } else { // calculate height to keep aspect ratio - item->size.height = p_image->get_height() * p_width / p_image->get_width(); + if (p_region.has_area()) { + item->size.height = p_region.get_size().height * p_width / p_region.get_size().width; + } else { + item->size.height = p_image->get_height() * p_width / p_image->get_width(); + } } } else { if (p_height > 0) { // custom height item->size.height = p_height; // calculate width to keep aspect ratio - item->size.width = p_image->get_width() * p_height / p_image->get_height(); + if (p_region.has_area()) { + item->size.width = p_region.get_size().width * p_height / p_region.get_size().height; + } else { + item->size.width = p_image->get_width() * p_height / p_image->get_height(); + } } else { - // keep original width and height - item->size = p_image->get_size(); + if (p_region.has_area()) { + // if the image has a region, keep the region size + item->size = p_region.get_size(); + } else { + // keep original width and height + item->size = p_image->get_size(); + } } } @@ -4126,6 +4147,18 @@ void RichTextLabel::append_text(const String &p_bbcode) { Ref<Texture2D> texture = ResourceLoader::load(image, "Texture2D"); if (texture.is_valid()) { + Rect2 region; + OptionMap::Iterator region_option = bbcode_options.find("region"); + if (region_option) { + Vector<String> region_values = region_option->value.split(",", false); + if (region_values.size() == 4) { + region.position.x = region_values[0].to_float(); + region.position.y = region_values[1].to_float(); + region.size.x = region_values[2].to_float(); + region.size.y = region_values[3].to_float(); + } + } + Color color = Color(1.0, 1.0, 1.0); OptionMap::Iterator color_option = bbcode_options.find("color"); if (color_option) { @@ -4154,7 +4187,7 @@ void RichTextLabel::append_text(const String &p_bbcode) { } } - add_image(texture, width, height, color, (InlineAlignment)alignment); + add_image(texture, width, height, color, (InlineAlignment)alignment, region); } pos = end; @@ -5209,7 +5242,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_parsed_text"), &RichTextLabel::get_parsed_text); ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text); ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text); - ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER)); + ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align", "region"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGNMENT_CENTER), DEFVAL(Rect2(0, 0, 0, 0))); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line); ClassDB::bind_method(D_METHOD("push_font", "font", "font_size"), &RichTextLabel::push_font); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 73b7676c22..04a682349d 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -569,7 +569,7 @@ private: public: String get_parsed_text() const; void add_text(const String &p_text); - void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER); + void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlignment p_alignment = INLINE_ALIGNMENT_CENTER, const Rect2 &p_region = Rect2(0, 0, 0, 0)); void add_newline(); bool remove_line(const int p_line); void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0)); diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 6c05b171e3..6899178885 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -183,35 +183,35 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) { } if (p_event->is_pressed()) { - if (p_event->is_action("ui_left")) { + if (p_event->is_action("ui_left", true)) { if (orientation != HORIZONTAL) { return; } set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_right")) { + } else if (p_event->is_action("ui_right", true)) { if (orientation != HORIZONTAL) { return; } set_value(get_value() + (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_up")) { + } else if (p_event->is_action("ui_up", true)) { if (orientation != VERTICAL) { return; } set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_down")) { + } else if (p_event->is_action("ui_down", true)) { if (orientation != VERTICAL) { return; } set_value(get_value() + (custom_step >= 0 ? custom_step : get_step())); - } else if (p_event->is_action("ui_home")) { + } else if (p_event->is_action("ui_home", true)) { set_value(get_min()); - } else if (p_event->is_action("ui_end")) { + } else if (p_event->is_action("ui_end", true)) { set_value(get_max()); } } @@ -338,7 +338,7 @@ void ScrollBar::_notification(int p_what) { if (scrolling) { if (get_value() != target_scroll) { double target = target_scroll - get_value(); - double dist = sqrt(target * target); + double dist = abs(target); double vel = ((target / dist) * 500) * get_physics_process_delta_time(); if (Math::abs(vel) >= dist) { diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index a7d44c0f3c..6cbacf0dd3 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -138,10 +138,10 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) { } set_value(get_value() - (custom_step >= 0 ? custom_step : get_step())); accept_event(); - } else if (p_event->is_action("ui_home") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_home", true) && p_event->is_pressed()) { set_value(get_min()); accept_event(); - } else if (p_event->is_action("ui_end") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_end", true) && p_event->is_pressed()) { set_value(get_max()); accept_event(); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index f8501f3570..48853cde9c 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -464,7 +464,7 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (scrolling && get_v_scroll() != target_v_scroll) { double target_y = target_v_scroll - get_v_scroll(); - double dist = sqrt(target_y * target_y); + double dist = abs(target_y); // To ensure minimap is responsive override the speed setting. double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time(); @@ -1692,7 +1692,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { continue; } - if (mpos.x > left_margin && mpos.x <= (left_margin + gutters[i].width) - 3) { + if (mpos.x >= left_margin && mpos.x <= left_margin + gutters[i].width) { emit_signal(SNAME("gutter_clicked"), row, i); return; } @@ -1933,7 +1933,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { continue; } - if (mpos.x > left_margin && mpos.x <= (left_margin + gutters[i].width) - 3) { + if (mpos.x >= left_margin && mpos.x < left_margin + gutters[i].width) { // We are in this gutter i's horizontal area. current_hovered_gutter = Vector2i(i, hovered_row); break; @@ -2051,7 +2051,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } if (is_shortcut_keys_enabled()) { - // SELECT ALL, SELECT WORD UNDER CARET, CUT, COPY, PASTE. + // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, CUT, COPY, PASTE. if (k->is_action("ui_text_select_all", true)) { select_all(); accept_event(); @@ -2062,6 +2062,11 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { accept_event(); return; } + if (k->is_action("ui_text_add_selection_for_next_occurrence", true)) { + add_selection_for_next_occurrence(); + accept_event(); + return; + } if (k->is_action("ui_cut", true)) { cut(); accept_event(); @@ -2192,8 +2197,17 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { return; } - // Handle Unicode (if no modifiers active). Tab has a value of 0x09. - if (allow_unicode_handling && editable && (k->get_unicode() >= 32 || k->get_keycode() == Key::TAB)) { + // Handle tab as it has no set unicode value. + if (k->is_action("ui_text_indent", true)) { + if (editable) { + insert_text_at_caret("\t"); + } + accept_event(); + return; + } + + // Handle Unicode (if no modifiers active). + if (allow_unicode_handling && editable && k->get_unicode() >= 32) { handle_unicode_input(k->get_unicode()); accept_event(); return; @@ -2997,7 +3011,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { continue; } - if (p_pos.x > left_margin && p_pos.x <= (left_margin + gutters[i].width) - 3) { + if (p_pos.x >= left_margin && p_pos.x < left_margin + gutters[i].width) { if (gutters[i].clickable || is_line_gutter_clickable(row, i)) { return CURSOR_POINTING_HAND; } @@ -3854,7 +3868,7 @@ void TextEdit::undo() { } caret_pos_dirty = true; } - queue_redraw(); + adjust_viewport_to_caret(); } void TextEdit::redo() { @@ -3906,7 +3920,7 @@ void TextEdit::redo() { } caret_pos_dirty = true; } - queue_redraw(); + adjust_viewport_to_caret(); } void TextEdit::clear_undo_history() { @@ -4380,7 +4394,7 @@ int TextEdit::add_caret(int p_line, int p_col) { } void TextEdit::remove_caret(int p_caret) { - ERR_FAIL_COND(carets.size() <= 0); + ERR_FAIL_COND_MSG(carets.size() <= 1, "The main caret should not be removed."); ERR_FAIL_INDEX(p_caret, carets.size()); carets.remove_at(p_caret); caret_index_edit_dirty = true; @@ -4816,10 +4830,50 @@ void TextEdit::select_word_under_caret(int p_caret) { continue; } - select(get_caret_line(c), begin, get_caret_column(c), end, c); + select(get_caret_line(c), begin, get_caret_line(c), end, c); // Move the caret to the end of the word for easier editing. set_caret_column(end, false, c); } + merge_overlapping_carets(); +} + +void TextEdit::add_selection_for_next_occurrence() { + if (!selecting_enabled || !is_multiple_carets_enabled()) { + return; + } + + if (text.size() == 1 && text[0].length() == 0) { + return; + } + + // Always use the last caret, to correctly search for + // the next occurrence that comes after this caret. + int caret = get_caret_count() - 1; + + if (!has_selection(caret)) { + select_word_under_caret(caret); + return; + } + + const String &highlighted_text = get_selected_text(caret); + int column = get_selection_from_column(caret) + 1; + int line = get_caret_line(caret); + + const Point2i next_occurrence = search(highlighted_text, SEARCH_MATCH_CASE, line, column); + + if (next_occurrence.x == -1 || next_occurrence.y == -1) { + return; + } + + int to_column = get_selection_to_column(caret) + 1; + int end = next_occurrence.x + (to_column - column); + int new_caret = add_caret(next_occurrence.y, end); + + if (new_caret != -1) { + select(next_occurrence.y, next_occurrence.x, next_occurrence.y, end, new_caret); + adjust_viewport_to_caret(new_caret); + merge_overlapping_carets(); + } } void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret) { @@ -5088,6 +5142,14 @@ bool TextEdit::is_scroll_past_end_of_file_enabled() const { return scroll_past_end_of_file_enabled; } +VScrollBar *TextEdit::get_v_scroll_bar() const { + return v_scroll; +} + +HScrollBar *TextEdit::get_h_scroll_bar() const { + return h_scroll; +} + void TextEdit::set_v_scroll(double p_scroll) { v_scroll->set_value(p_scroll); int max_v_scroll = v_scroll->get_max() - v_scroll->get_page(); @@ -5982,6 +6044,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all); ClassDB::bind_method(D_METHOD("select_word_under_caret", "caret_index"), &TextEdit::select_word_under_caret, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_selection_for_next_occurrence"), &TextEdit::add_selection_for_next_occurrence); ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column", "caret_index"), &TextEdit::select, DEFVAL(0)); ClassDB::bind_method(D_METHOD("has_selection", "caret_index"), &TextEdit::has_selection, DEFVAL(-1)); @@ -6020,6 +6083,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_scroll_enabled", "enable"), &TextEdit::set_smooth_scroll_enabled); ClassDB::bind_method(D_METHOD("is_smooth_scroll_enabled"), &TextEdit::is_smooth_scroll_enabled); + ClassDB::bind_method(D_METHOD("get_v_scroll_bar"), &TextEdit::get_v_scroll_bar); + ClassDB::bind_method(D_METHOD("get_h_scroll_bar"), &TextEdit::get_h_scroll_bar); + ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &TextEdit::set_v_scroll); ClassDB::bind_method(D_METHOD("get_v_scroll"), &TextEdit::get_v_scroll); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index a8e087909e..86b838e387 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -851,6 +851,7 @@ public: void select_all(); void select_word_under_caret(int p_caret = -1); + void add_selection_for_next_occurrence(); void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret = 0); bool has_selection(int p_caret = -1) const; @@ -886,6 +887,9 @@ public: void set_scroll_past_end_of_file_enabled(const bool p_enabled); bool is_scroll_past_end_of_file_enabled() const; + VScrollBar *get_v_scroll_bar() const; + HScrollBar *get_h_scroll_bar() const; + void set_v_scroll(double p_scroll); double get_v_scroll() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index acf398305c..6f9a9a5141 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1504,6 +1504,7 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_button", "column", "button_idx", "button"), &TreeItem::set_button); ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button); ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled); + ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_idx", "color"), &TreeItem::set_button_color); ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled); ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text); @@ -3190,7 +3191,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; bool is_command = k.is_valid() && k->is_command_or_control_pressed(); - if (p_event->is_action("ui_right") && p_event->is_pressed()) { + if (p_event->is_action("ui_right", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3208,7 +3209,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } else { _go_right(); } - } else if (p_event->is_action("ui_left") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_left", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3228,21 +3229,21 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { _go_left(); } - } else if (p_event->is_action("ui_up") && p_event->is_pressed() && !is_command) { + } else if (p_event->is_action("ui_up", true) && p_event->is_pressed() && !is_command) { if (!cursor_can_exit_tree) { accept_event(); } _go_up(); - } else if (p_event->is_action("ui_down") && p_event->is_pressed() && !is_command) { + } else if (p_event->is_action("ui_down", true) && p_event->is_pressed() && !is_command) { if (!cursor_can_exit_tree) { accept_event(); } _go_down(); - } else if (p_event->is_action("ui_page_down") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_page_down", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3280,7 +3281,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } ensure_cursor_is_visible(); - } else if (p_event->is_action("ui_page_up") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_page_up", true) && p_event->is_pressed()) { if (!cursor_can_exit_tree) { accept_event(); } @@ -3317,7 +3318,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { prev->select(selected_col); } ensure_cursor_is_visible(); - } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_accept", true) && p_event->is_pressed()) { if (selected_item) { //bring up editor if possible if (!edit_selected()) { @@ -3326,7 +3327,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } } accept_event(); - } else if (p_event->is_action("ui_select") && p_event->is_pressed()) { + } else if (p_event->is_action("ui_select", true) && p_event->is_pressed()) { if (select_mode == SELECT_MULTI) { if (!selected_item) { return; diff --git a/scene/gui/view_panner.cpp b/scene/gui/view_panner.cpp index 3b7f499a07..e8e3e3e556 100644 --- a/scene/gui/view_panner.cpp +++ b/scene/gui/view_panner.cpp @@ -38,7 +38,9 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect) Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { Vector2 scroll_vec = Vector2((mb->get_button_index() == MouseButton::WHEEL_RIGHT) - (mb->get_button_index() == MouseButton::WHEEL_LEFT), (mb->get_button_index() == MouseButton::WHEEL_DOWN) - (mb->get_button_index() == MouseButton::WHEEL_UP)); - if (scroll_vec != Vector2()) { + // Moving the scroll wheel sends two events: one with pressed as true, + // and one with pressed as false. Make sure we only process one of them. + if (scroll_vec != Vector2() && mb->is_pressed()) { if (control_scheme == SCROLL_PANS) { if (mb->is_ctrl_pressed()) { scroll_vec.y *= mb->get_factor(); diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 05d86f77f2..840913d466 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -986,8 +986,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_repeat", "mode"), &CanvasItem::set_texture_repeat); ClassDB::bind_method(D_METHOD("get_texture_repeat"), &CanvasItem::get_texture_repeat); - ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children); - ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children); + ClassDB::bind_method(D_METHOD("set_clip_children_mode", "mode"), &CanvasItem::set_clip_children_mode); + ClassDB::bind_method(D_METHOD("get_clip_children_mode"), &CanvasItem::get_clip_children_mode); GDVIRTUAL_BIND(_draw); @@ -997,7 +997,7 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "clip_children", PROPERTY_HINT_ENUM, "Disabled,Clip Only,Clip + Draw"), "set_clip_children_mode", "get_clip_children_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); ADD_GROUP("Texture", "texture_"); @@ -1035,6 +1035,11 @@ void CanvasItem::_bind_methods() { BIND_ENUM_CONSTANT(TEXTURE_REPEAT_ENABLED); BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MIRROR); BIND_ENUM_CONSTANT(TEXTURE_REPEAT_MAX); + + BIND_ENUM_CONSTANT(CLIP_CHILDREN_DISABLED); + BIND_ENUM_CONSTANT(CLIP_CHILDREN_ONLY); + BIND_ENUM_CONSTANT(CLIP_CHILDREN_AND_DRAW); + BIND_ENUM_CONSTANT(CLIP_CHILDREN_MAX); } Transform2D CanvasItem::get_canvas_transform() const { @@ -1092,7 +1097,7 @@ int CanvasItem::get_canvas_layer() const { } } -void CanvasItem::_update_texture_filter_changed(bool p_propagate) { +void CanvasItem::_refresh_texture_filter_cache() { if (!is_inside_tree()) { return; } @@ -1107,6 +1112,14 @@ void CanvasItem::_update_texture_filter_changed(bool p_propagate) { } else { texture_filter_cache = RS::CanvasItemTextureFilter(texture_filter); } +} + +void CanvasItem::_update_texture_filter_changed(bool p_propagate) { + if (!is_inside_tree()) { + return; + } + _refresh_texture_filter_cache(); + RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache); queue_redraw(); @@ -1133,7 +1146,7 @@ CanvasItem::TextureFilter CanvasItem::get_texture_filter() const { return texture_filter; } -void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { +void CanvasItem::_refresh_texture_repeat_cache() { if (!is_inside_tree()) { return; } @@ -1148,6 +1161,14 @@ void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { } else { texture_repeat_cache = RS::CanvasItemTextureRepeat(texture_repeat); } +} + +void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { + if (!is_inside_tree()) { + return; + } + _refresh_texture_repeat_cache(); + RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache); queue_redraw(); if (p_propagate) { @@ -1169,26 +1190,39 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) { notify_property_list_changed(); } -void CanvasItem::set_clip_children(bool p_enabled) { - if (clip_children == p_enabled) { +void CanvasItem::set_clip_children_mode(ClipChildrenMode p_clip_mode) { + ERR_FAIL_COND(p_clip_mode >= CLIP_CHILDREN_MAX); + + if (clip_children_mode == p_clip_mode) { return; } - clip_children = p_enabled; + clip_children_mode = p_clip_mode; if (Object::cast_to<CanvasGroup>(this) != nullptr) { //avoid accidental bugs, make this not work on CanvasGroup return; } - RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), clip_children ? RS::CANVAS_GROUP_MODE_OPAQUE : RS::CANVAS_GROUP_MODE_DISABLED); + + RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CanvasGroupMode(clip_children_mode)); } -bool CanvasItem::is_clipping_children() const { - return clip_children; +CanvasItem::ClipChildrenMode CanvasItem::get_clip_children_mode() const { + return clip_children_mode; } CanvasItem::TextureRepeat CanvasItem::get_texture_repeat() const { return texture_repeat; } +CanvasItem::TextureFilter CanvasItem::get_texture_filter_in_tree() { + _refresh_texture_filter_cache(); + return (TextureFilter)texture_filter_cache; +} + +CanvasItem::TextureRepeat CanvasItem::get_texture_repeat_in_tree() { + _refresh_texture_repeat_cache(); + return (TextureRepeat)texture_repeat_cache; +} + CanvasItem::CanvasItem() : xform_change(this) { canvas_item = RenderingServer::get_singleton()->canvas_item_create(); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index b80289fdb4..565ea930ce 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -66,8 +66,16 @@ public: TEXTURE_REPEAT_MAX, }; + enum ClipChildrenMode { + CLIP_CHILDREN_DISABLED, + CLIP_CHILDREN_ONLY, + CLIP_CHILDREN_AND_DRAW, + CLIP_CHILDREN_MAX, + }; + private: - mutable SelfList<Node> xform_change; + mutable SelfList<Node> + xform_change; RID canvas_item; StringName canvas_group; @@ -85,7 +93,6 @@ private: Window *window = nullptr; bool visible = true; bool parent_visible_in_tree = false; - bool clip_children = false; bool pending_update = false; bool top_level = false; bool drawing = false; @@ -95,6 +102,8 @@ private: bool notify_local_transform = false; bool notify_transform = false; + ClipChildrenMode clip_children_mode = CLIP_CHILDREN_DISABLED; + RS::CanvasItemTextureFilter texture_filter_cache = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; RS::CanvasItemTextureRepeat texture_repeat_cache = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; TextureFilter texture_filter = TEXTURE_FILTER_PARENT_NODE; @@ -121,7 +130,9 @@ private: static CanvasItem *current_item_drawn; friend class Viewport; + void _refresh_texture_repeat_cache(); void _update_texture_repeat_changed(bool p_propagate); + void _refresh_texture_filter_cache(); void _update_texture_filter_changed(bool p_propagate); protected: @@ -200,8 +211,8 @@ public: void queue_redraw(); void move_to_front(); - void set_clip_children(bool p_enabled); - bool is_clipping_children() const; + void set_clip_children_mode(ClipChildrenMode p_clip_mode); + ClipChildrenMode get_clip_children_mode() const; virtual void set_light_mask(int p_light_mask); int get_light_mask() const; @@ -310,6 +321,9 @@ public: virtual void set_texture_repeat(TextureRepeat p_texture_repeat); TextureRepeat get_texture_repeat() const; + TextureFilter get_texture_filter_in_tree(); + TextureRepeat get_texture_repeat_in_tree(); + // Used by control nodes to retrieve the parent's anchorable area virtual Rect2 get_anchorable_rect() const { return Rect2(0, 0, 0, 0); }; @@ -321,6 +335,7 @@ public: VARIANT_ENUM_CAST(CanvasItem::TextureFilter) VARIANT_ENUM_CAST(CanvasItem::TextureRepeat) +VARIANT_ENUM_CAST(CanvasItem::ClipChildrenMode) class CanvasTexture : public Texture2D { GDCLASS(CanvasTexture, Texture2D); diff --git a/scene/main/multiplayer_peer.cpp b/scene/main/multiplayer_peer.cpp index 9b63118f7c..462dc1babb 100644 --- a/scene/main/multiplayer_peer.cpp +++ b/scene/main/multiplayer_peer.cpp @@ -78,6 +78,10 @@ bool MultiplayerPeer::is_refusing_new_connections() const { return refuse_connections; } +bool MultiplayerPeer::is_server_relay_supported() const { + return false; +} + void MultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &MultiplayerPeer::set_transfer_channel); ClassDB::bind_method(D_METHOD("get_transfer_channel"), &MultiplayerPeer::get_transfer_channel); @@ -86,6 +90,8 @@ void MultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer); ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer); + ClassDB::bind_method(D_METHOD("get_packet_channel"), &MultiplayerPeer::get_packet_channel); + ClassDB::bind_method(D_METHOD("get_packet_mode"), &MultiplayerPeer::get_packet_mode); ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll); @@ -96,6 +102,8 @@ void MultiplayerPeer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections); ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections); + ClassDB::bind_method(D_METHOD("is_server_relay_supported"), &MultiplayerPeer::is_server_relay_supported); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel", PROPERTY_HINT_RANGE, "0,255,1"), "set_transfer_channel", "get_transfer_channel"); @@ -177,6 +185,14 @@ bool MultiplayerPeerExtension::is_refusing_new_connections() const { return MultiplayerPeer::is_refusing_new_connections(); } +bool MultiplayerPeerExtension::is_server_relay_supported() const { + bool can_relay; + if (GDVIRTUAL_CALL(_is_server_relay_supported, can_relay)) { + return can_relay; + } + return MultiplayerPeer::is_server_relay_supported(); +} + void MultiplayerPeerExtension::_bind_methods() { GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size"); GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size"); diff --git a/scene/main/multiplayer_peer.h b/scene/main/multiplayer_peer.h index ab7483ece5..63ce66871e 100644 --- a/scene/main/multiplayer_peer.h +++ b/scene/main/multiplayer_peer.h @@ -74,10 +74,13 @@ public: virtual TransferMode get_transfer_mode() const; virtual void set_refuse_new_connections(bool p_enable); virtual bool is_refusing_new_connections() const; + virtual bool is_server_relay_supported() const; virtual void set_target_peer(int p_peer_id) = 0; virtual int get_packet_peer() const = 0; + virtual TransferMode get_packet_mode() const = 0; + virtual int get_packet_channel() const = 0; virtual bool is_server() const = 0; @@ -123,12 +126,17 @@ public: virtual bool is_refusing_new_connections() const override; GDVIRTUAL0RC(bool, _is_refusing_new_connections); // Optional. + virtual bool is_server_relay_supported() const override; + GDVIRTUAL0RC(bool, _is_server_relay_supported); // Optional. + EXBIND1(set_transfer_channel, int); EXBIND0RC(int, get_transfer_channel); EXBIND1(set_transfer_mode, TransferMode); EXBIND0RC(TransferMode, get_transfer_mode); EXBIND1(set_target_peer, int); EXBIND0RC(int, get_packet_peer); + EXBIND0RC(TransferMode, get_packet_mode); + EXBIND0RC(int, get_packet_channel); EXBIND0RC(bool, is_server); EXBIND0(poll); EXBIND0RC(int, get_unique_id); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 101a63db1b..2ea45df309 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -322,62 +322,62 @@ void Node::_propagate_exit_tree() { data.depth = -1; } -void Node::move_child(Node *p_child, int p_pos) { +void Node::move_child(Node *p_child, int p_index) { ERR_FAIL_NULL(p_child); ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node."); // We need to check whether node is internal and move it only in the relevant node range. if (p_child->_is_internal_front()) { - if (p_pos < 0) { - p_pos += data.internal_children_front; + if (p_index < 0) { + p_index += data.internal_children_front; } - ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_front, vformat("Invalid new child position: %d. Child is internal.", p_pos)); - _move_child(p_child, p_pos); + ERR_FAIL_INDEX_MSG(p_index, data.internal_children_front, vformat("Invalid new child index: %d. Child is internal.", p_index)); + _move_child(p_child, p_index); } else if (p_child->_is_internal_back()) { - if (p_pos < 0) { - p_pos += data.internal_children_back; + if (p_index < 0) { + p_index += data.internal_children_back; } - ERR_FAIL_INDEX_MSG(p_pos, data.internal_children_back, vformat("Invalid new child position: %d. Child is internal.", p_pos)); - _move_child(p_child, data.children.size() - data.internal_children_back + p_pos); + ERR_FAIL_INDEX_MSG(p_index, data.internal_children_back, vformat("Invalid new child index: %d. Child is internal.", p_index)); + _move_child(p_child, data.children.size() - data.internal_children_back + p_index); } else { - if (p_pos < 0) { - p_pos += get_child_count(false); + if (p_index < 0) { + p_index += get_child_count(false); } - ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child position: %d.", p_pos)); - _move_child(p_child, p_pos + data.internal_children_front); + ERR_FAIL_INDEX_MSG(p_index, data.children.size() + 1 - data.internal_children_front - data.internal_children_back, vformat("Invalid new child index: %d.", p_index)); + _move_child(p_child, p_index + data.internal_children_front); } } -void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) { +void Node::_move_child(Node *p_child, int p_index, bool p_ignore_end) { ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup)."); // Specifying one place beyond the end - // means the same as moving to the last position + // means the same as moving to the last index if (!p_ignore_end) { // p_ignore_end is a little hack to make back internal children work properly. if (p_child->_is_internal_front()) { - if (p_pos == data.internal_children_front) { - p_pos--; + if (p_index == data.internal_children_front) { + p_index--; } } else if (p_child->_is_internal_back()) { - if (p_pos == data.children.size()) { - p_pos--; + if (p_index == data.children.size()) { + p_index--; } } else { - if (p_pos == data.children.size() - data.internal_children_back) { - p_pos--; + if (p_index == data.children.size() - data.internal_children_back) { + p_index--; } } } - if (p_child->data.pos == p_pos) { + if (p_child->data.index == p_index) { return; //do nothing } - int motion_from = MIN(p_pos, p_child->data.pos); - int motion_to = MAX(p_pos, p_child->data.pos); + int motion_from = MIN(p_index, p_child->data.index); + int motion_to = MAX(p_index, p_child->data.index); - data.children.remove_at(p_child->data.pos); - data.children.insert(p_pos, p_child); + data.children.remove_at(p_child->data.index); + data.children.insert(p_index, p_child); if (data.tree) { data.tree->tree_changed(); @@ -386,7 +386,7 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) { data.blocked++; //new pos first for (int i = motion_from; i <= motion_to; i++) { - data.children[i]->data.pos = i; + data.children[i]->data.index = i; } // notification second move_child_notify(p_child); @@ -1024,11 +1024,9 @@ String increase_numeric_string(const String &s) { void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const { if (name == StringName()) { - //no name and a new name is needed, create one. + // No name and a new name is needed, create one. name = p_child->get_class(); - // Adjust casing according to project setting. - name = adjust_name_casing(name); } //quickly test if proposed name exists @@ -1106,7 +1104,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) { //add a child node quickly, without name validation p_child->data.name = p_name; - p_child->data.pos = data.children.size(); + p_child->data.index = data.children.size(); data.children.push_back(p_child); p_child->data.parent = this; @@ -1173,9 +1171,9 @@ void Node::remove_child(Node *p_child) { Node **children = data.children.ptrw(); int idx = -1; - if (p_child->data.pos >= 0 && p_child->data.pos < child_count) { - if (children[p_child->data.pos] == p_child) { - idx = p_child->data.pos; + if (p_child->data.index >= 0 && p_child->data.index < child_count) { + if (children[p_child->data.index] == p_child) { + idx = p_child->data.index; } } @@ -1211,12 +1209,12 @@ void Node::remove_child(Node *p_child) { children = data.children.ptrw(); for (int i = idx; i < child_count; i++) { - children[i]->data.pos = i; + children[i]->data.index = i; children[i]->notification(NOTIFICATION_MOVED_IN_PARENT); } p_child->data.parent = nullptr; - p_child->data.pos = -1; + p_child->data.index = -1; if (data.inside_tree) { p_child->_propagate_after_exit_tree(); @@ -1475,7 +1473,7 @@ bool Node::is_greater_than(const Node *p_node) const { int idx = data.depth - 1; while (n) { ERR_FAIL_INDEX_V(idx, data.depth, false); - this_stack[idx--] = n->data.pos; + this_stack[idx--] = n->data.index; n = n->data.parent; } ERR_FAIL_COND_V(idx != -1, false); @@ -1483,7 +1481,7 @@ bool Node::is_greater_than(const Node *p_node) const { idx = p_node->data.depth - 1; while (n) { ERR_FAIL_INDEX_V(idx, p_node->data.depth, false); - that_stack[idx--] = n->data.pos; + that_stack[idx--] = n->data.index; n = n->data.parent; } @@ -1894,9 +1892,9 @@ int Node::get_index(bool p_include_internal) const { ERR_FAIL_COND_V_MSG(!p_include_internal && (_is_internal_front() || _is_internal_back()), -1, "Node is internal. Can't get index with 'include_internal' being false."); if (data.parent && !p_include_internal) { - return data.pos - data.parent->data.internal_children_front; + return data.index - data.parent->data.internal_children_front; } - return data.pos; + return data.index; } Ref<Tween> Node::create_tween() { @@ -2391,12 +2389,12 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) { } Node *parent = data.parent; - int pos_in_parent = data.pos; + int index_in_parent = data.index; if (data.parent) { parent->remove_child(this); parent->add_child(p_node); - parent->move_child(p_node, pos_in_parent); + parent->move_child(p_node, index_in_parent); } while (get_child_count()) { @@ -2759,7 +2757,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("add_to_group", "group", "persistent"), &Node::add_to_group, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_from_group", "group"), &Node::remove_from_group); ClassDB::bind_method(D_METHOD("is_in_group", "group"), &Node::is_in_group); - ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_position"), &Node::move_child); + ClassDB::bind_method(D_METHOD("move_child", "child_node", "to_index"), &Node::move_child); ClassDB::bind_method(D_METHOD("get_groups"), &Node::_get_groups); ClassDB::bind_method(D_METHOD("set_owner", "owner"), &Node::set_owner); ClassDB::bind_method(D_METHOD("get_owner"), &Node::get_owner); diff --git a/scene/main/node.h b/scene/main/node.h index 4e6530cccd..c8c8c395ce 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -91,6 +91,7 @@ private: SceneTree::Group *group = nullptr; }; + // This Data struct is to avoid namespace pollution in derived classes. struct Data { String scene_file_path; Ref<SceneState> instance_state; @@ -104,7 +105,7 @@ private: int internal_children_front = 0; int internal_children_back = 0; - int pos = -1; + int index = -1; int depth = -1; int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed. StringName name; @@ -186,8 +187,8 @@ private: Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.pos < data.parent->data.internal_children_front; } - _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.pos >= data.parent->data.children.size() - data.parent->data.internal_children_back; } + _FORCE_INLINE_ bool _is_internal_front() const { return data.parent && data.index < data.parent->data.internal_children_front; } + _FORCE_INLINE_ bool _is_internal_back() const { return data.parent && data.index >= data.parent->data.children.size() - data.parent->data.internal_children_back; } friend class SceneTree; @@ -346,8 +347,8 @@ public: void get_groups(List<GroupInfo> *p_groups) const; int get_persistent_group_count() const; - void move_child(Node *p_child, int p_pos); - void _move_child(Node *p_child, int p_pos, bool p_ignore_end = false); + void move_child(Node *p_child, int p_index); + void _move_child(Node *p_child, int p_index, bool p_ignore_end = false); void set_owner(Node *p_owner); Node *get_owner() const; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index af481749d5..5ff9a29792 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -44,6 +44,7 @@ #include "node.h" #include "scene/animation/tween.h" #include "scene/debugger/scene_debugger.h" +#include "scene/gui/control.h" #include "scene/main/multiplayer_api.h" #include "scene/main/viewport.h" #include "scene/resources/environment.h" @@ -895,6 +896,8 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal call_lock++; + Vector<ObjectID> no_context_node_ids; // Nodes may be deleted due to this shortcut input. + for (int i = gr_node_count - 1; i >= 0; i--) { if (p_viewport->is_input_handled()) { break; @@ -913,9 +916,22 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal case CALL_INPUT_TYPE_INPUT: n->_call_input(p_input); break; - case CALL_INPUT_TYPE_SHORTCUT_INPUT: + case CALL_INPUT_TYPE_SHORTCUT_INPUT: { + const Control *c = Object::cast_to<Control>(n); + if (c) { + // If calling shortcut input on a control, ensure it respects the shortcut context. + // Shortcut context (based on focus) only makes sense for controls (UI), so don't need to worry about it for nodes + if (c->get_shortcut_context() == nullptr) { + no_context_node_ids.append(n->get_instance_id()); + continue; + } + if (!c->is_focus_owner_in_shortcut_context()) { + continue; + } + } n->_call_shortcut_input(p_input); break; + } case CALL_INPUT_TYPE_UNHANDLED_INPUT: n->_call_unhandled_input(p_input); break; @@ -925,6 +941,13 @@ void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_cal } } + for (const ObjectID &id : no_context_node_ids) { + Node *n = Object::cast_to<Node>(ObjectDB::get_instance(id)); + if (n) { + n->_call_shortcut_input(p_input); + } + } + call_lock--; if (call_lock == 0) { call_skip.clear(); @@ -1390,6 +1413,9 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa_3d", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa_3d", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Average),4× (Slow),8× (Slowest)"))); root->set_msaa_3d(Viewport::MSAA(msaa_mode_3d)); + const bool transparent_background = GLOBAL_DEF("rendering/transparent_background", false); + root->set_transparent_background(transparent_background); + const int ssaa_mode = GLOBAL_DEF_BASIC("rendering/anti_aliasing/quality/screen_space_aa", 0); ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)")); root->set_screen_space_aa(Viewport::ScreenSpaceAA(ssaa_mode)); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index f7a515dc1d..ad40346c36 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1263,6 +1263,7 @@ void Viewport::_gui_show_tooltip() { Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset"); Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size()); + r.size = r.size.min(panel->get_max_size()); Window *window = gui.tooltip_popup->get_parent_visible_window(); Rect2i vr = window->get_usable_parent_rect(); @@ -1403,10 +1404,6 @@ Control *Viewport::gui_find_control(const Point2 &p_global) { } Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) { - if (Object::cast_to<Viewport>(p_node)) { - return nullptr; - } - if (!p_node->is_visible()) { return nullptr; // Canvas item hidden, discard. } @@ -1490,7 +1487,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.key_event_accepted = false; Point2 mpos = mb->get_position(); - gui.last_mouse_pos = mpos; if (mb->is_pressed()) { Size2 pos = mpos; if (gui.mouse_focus_mask != MouseButton::NONE) { @@ -1644,8 +1640,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.key_event_accepted = false; Point2 mpos = mm->get_position(); - gui.last_mouse_pos = mpos; - // Drag & drop. if (!gui.drag_attempted && gui.mouse_focus && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) { gui.drag_accum += mm->get_relative(); @@ -2759,6 +2753,11 @@ void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) { ev = p_event; } + Ref<InputEventMouse> me = ev; + if (me.is_valid()) { + gui.last_mouse_pos = me->get_position(); + } + if (is_embedding_subwindows() && _sub_windows_forward_input(ev)) { set_input_as_handled(); return; @@ -3727,6 +3726,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_global_canvas_transform", "xform"), &Viewport::set_global_canvas_transform); ClassDB::bind_method(D_METHOD("get_global_canvas_transform"), &Viewport::get_global_canvas_transform); ClassDB::bind_method(D_METHOD("get_final_transform"), &Viewport::get_final_transform); + ClassDB::bind_method(D_METHOD("get_screen_transform"), &Viewport::get_screen_transform); ClassDB::bind_method(D_METHOD("get_visible_rect"), &Viewport::get_visible_rect); ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 7fb3f32d36..ebb11ecee8 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -157,26 +157,18 @@ void Window::set_flag(Flags p_flag, bool p_enabled) { embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { -#ifdef TOOLS_ENABLED - if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) { + if (!is_in_edited_scene_root()) { DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); } -#else - DisplayServer::get_singleton()->window_set_flag(DisplayServer::WindowFlags(p_flag), p_enabled, window_id); -#endif } } bool Window::get_flag(Flags p_flag) const { ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false); if (window_id != DisplayServer::INVALID_WINDOW_ID) { -#ifdef TOOLS_ENABLED - if ((p_flag != FLAG_POPUP) || !(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) { + if (!is_in_edited_scene_root()) { flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id); } -#else - flags[p_flag] = DisplayServer::get_singleton()->window_get_flag(DisplayServer::WindowFlags(p_flag), window_id); -#endif } return flags[p_flag]; } @@ -232,6 +224,14 @@ bool Window::is_embedded() const { return _get_embedder() != nullptr; } +bool Window::is_in_edited_scene_root() const { +#ifdef TOOLS_ENABLED + return (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this)); +#else + return false; +#endif +} + void Window::_make_window() { ERR_FAIL_COND(window_id != DisplayServer::INVALID_WINDOW_ID); @@ -259,15 +259,12 @@ void Window::_make_window() { #endif DisplayServer::get_singleton()->window_set_title(tr_title, window_id); DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); -#ifdef TOOLS_ENABLED - if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) { - DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); - } else { + + if (is_in_edited_scene_root()) { DisplayServer::get_singleton()->window_set_exclusive(window_id, false); + } else { + DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); } -#else - DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); -#endif _update_window_size(); @@ -465,14 +462,10 @@ void Window::set_visible(bool p_visible) { //update transient exclusive if (transient_parent) { if (exclusive && visible) { -#ifdef TOOLS_ENABLED - if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) { + if (!is_in_edited_scene_root()) { ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); transient_parent->exclusive_child = this; } -#else - transient_parent->exclusive_child = this; -#endif } else { if (transient_parent->exclusive_child == this) { transient_parent->exclusive_child = nullptr; @@ -519,13 +512,9 @@ void Window::_make_transient() { window->transient_children.insert(this); if (is_inside_tree() && is_visible() && exclusive) { if (transient_parent->exclusive_child == nullptr) { -#ifdef TOOLS_ENABLED - if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) { + if (!is_in_edited_scene_root()) { transient_parent->exclusive_child = this; } -#else - transient_parent->exclusive_child = this; -#endif } else if (transient_parent->exclusive_child != this) { ERR_PRINT("Making child transient exclusive, but parent has another exclusive child"); } @@ -568,27 +557,19 @@ void Window::set_exclusive(bool p_exclusive) { exclusive = p_exclusive; if (!embedder && window_id != DisplayServer::INVALID_WINDOW_ID) { -#ifdef TOOLS_ENABLED - if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) { - DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); - } else { + if (is_in_edited_scene_root()) { DisplayServer::get_singleton()->window_set_exclusive(window_id, false); + } else { + DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); } -#else - DisplayServer::get_singleton()->window_set_exclusive(window_id, exclusive); -#endif } if (transient_parent) { if (p_exclusive && is_inside_tree() && is_visible()) { ERR_FAIL_COND_MSG(transient_parent->exclusive_child && transient_parent->exclusive_child != this, "Transient parent has another exclusive child."); -#ifdef TOOLS_ENABLED - if (!(Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this))) { + if (!is_in_edited_scene_root()) { transient_parent->exclusive_child = this; } -#else - transient_parent->exclusive_child = this; -#endif } else { if (transient_parent->exclusive_child == this) { transient_parent->exclusive_child = nullptr; @@ -606,6 +587,18 @@ bool Window::is_visible() const { } void Window::_update_window_size() { + // Force window to respect size limitations of rendering server + RenderingServer *rendering_server = RenderingServer::get_singleton(); + if (rendering_server) { + Size2i max_window_size = rendering_server->get_maximum_viewport_size(); + + if (max_window_size != Size2i()) { + size = size.min(max_window_size); + min_size = min_size.min(max_window_size); + max_size = max_size.min(max_window_size); + } + } + Size2i size_limit; if (wrap_controls) { size_limit = get_contents_minimum_size(); @@ -651,9 +644,9 @@ void Window::_update_window_size() { DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id); } - DisplayServer::get_singleton()->window_set_size(size, window_id); DisplayServer::get_singleton()->window_set_max_size(max_size_valid ? max_size : Size2i(), window_id); DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id); + DisplayServer::get_singleton()->window_set_size(size, window_id); } //update the viewport @@ -1847,6 +1840,11 @@ void Window::_bind_methods() { } Window::Window() { + RenderingServer *rendering_server = RenderingServer::get_singleton(); + if (rendering_server) { + max_size = rendering_server->get_maximum_viewport_size(); + } + theme_owner = memnew(ThemeOwner); RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); } diff --git a/scene/main/window.h b/scene/main/window.h index 786f0ada38..03597b309a 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -234,6 +234,8 @@ public: void set_clamp_to_embedder(bool p_enable); bool is_clamped_to_embedder() const; + bool is_in_edited_scene_root() const; + bool can_draw() const; void set_ime_active(bool p_active); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 2bcf569f4e..dfd9c6eb2f 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -5239,9 +5239,7 @@ bool Animation::_fetch_compressed(uint32_t p_compressed_track, double p_time, Ve double page_base_time = compression.pages[page_index].time_offset; const uint8_t *page_data = compression.pages[page_index].data.ptr(); -#ifndef _MSC_VER -#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported -#endif + // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported. const uint32_t *indices = (const uint32_t *)page_data; const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]]; uint32_t time_key_count = indices[p_compressed_track * 3 + 1]; @@ -5384,9 +5382,7 @@ void Animation::_get_compressed_key_indices_in_range(uint32_t p_compressed_track double page_base_time = compression.pages[page_index].time_offset; const uint8_t *page_data = compression.pages[page_index].data.ptr(); -#ifndef _MSC_VER -#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported -#endif + // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported. const uint32_t *indices = (const uint32_t *)page_data; const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]]; uint32_t time_key_count = indices[p_compressed_track * 3 + 1]; @@ -5456,9 +5452,7 @@ int Animation::_get_compressed_key_count(uint32_t p_compressed_track) const { for (uint32_t i = 0; i < compression.pages.size(); i++) { const uint8_t *page_data = compression.pages[i].data.ptr(); -#ifndef _MSC_VER -#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported -#endif + // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported. const uint32_t *indices = (const uint32_t *)page_data; const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]]; uint32_t time_key_count = indices[p_compressed_track * 3 + 1]; @@ -5492,9 +5486,7 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in for (uint32_t i = 0; i < compression.pages.size(); i++) { const uint8_t *page_data = compression.pages[i].data.ptr(); -#ifndef _MSC_VER -#warning Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported -#endif + // Little endian assumed. No major big endian hardware exists any longer, but in case it does it will need to be supported. const uint32_t *indices = (const uint32_t *)page_data; const uint16_t *time_keys = (const uint16_t *)&page_data[indices[p_compressed_track * 3 + 0]]; uint32_t time_key_count = indices[p_compressed_track * 3 + 1]; diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 0505f6b559..1b06e09bb8 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -639,9 +639,7 @@ void BitMap::resize(const Size2i &p_new_size) { } Ref<Image> BitMap::convert_to_image() const { - Ref<Image> image; - image.instantiate(); - image->create(width, height, false, Image::FORMAT_L8); + Ref<Image> image = Image::create_empty(width, height, false, Image::FORMAT_L8); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp index 4eaae111a1..5bcefcd0e4 100644 --- a/scene/resources/convex_polygon_shape_3d.cpp +++ b/scene/resources/convex_polygon_shape_3d.cpp @@ -42,9 +42,9 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const { if (err == OK) { Vector<Vector3> lines; lines.resize(md.edges.size() * 2); - for (int i = 0; i < md.edges.size(); i++) { - lines.write[i * 2 + 0] = md.vertices[md.edges[i].a]; - lines.write[i * 2 + 1] = md.vertices[md.edges[i].b]; + for (uint32_t i = 0; i < md.edges.size(); i++) { + lines.write[i * 2 + 0] = md.vertices[md.edges[i].vertex_a]; + lines.write[i * 2 + 1] = md.vertices[md.edges[i].vertex_b]; } return lines; } diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index ebdaaaa95f..23bd8a4be4 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -78,7 +78,7 @@ float Environment::get_sky_custom_fov() const { void Environment::set_sky_rotation(const Vector3 &p_rotation) { bg_sky_rotation = p_rotation; - RS::get_singleton()->environment_set_sky_orientation(environment, Basis(p_rotation)); + RS::get_singleton()->environment_set_sky_orientation(environment, Basis::from_euler(p_rotation)); } Vector3 Environment::get_sky_rotation() const { diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 838927e34f..8ae217dd1f 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -2348,7 +2348,7 @@ void BaseMaterial3D::set_on_top_of_alpha() { set_flag(FLAG_DISABLE_DEPTH_TEST, true); } -void BaseMaterial3D::set_proximity_fade(bool p_enable) { +void BaseMaterial3D::set_proximity_fade_enabled(bool p_enable) { proximity_fade_enabled = p_enable; _queue_shader_change(); notify_property_list_changed(); @@ -2624,7 +2624,7 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_refraction_texture_channel", "channel"), &BaseMaterial3D::set_refraction_texture_channel); ClassDB::bind_method(D_METHOD("get_refraction_texture_channel"), &BaseMaterial3D::get_refraction_texture_channel); - ClassDB::bind_method(D_METHOD("set_proximity_fade", "enabled"), &BaseMaterial3D::set_proximity_fade); + ClassDB::bind_method(D_METHOD("set_proximity_fade_enabled", "enabled"), &BaseMaterial3D::set_proximity_fade_enabled); ClassDB::bind_method(D_METHOD("is_proximity_fade_enabled"), &BaseMaterial3D::is_proximity_fade_enabled); ClassDB::bind_method(D_METHOD("set_proximity_fade_distance", "distance"), &BaseMaterial3D::set_proximity_fade_distance); @@ -2808,7 +2808,7 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "point_size", PROPERTY_HINT_RANGE, "0.1,128,0.1,suffix:px"), "set_point_size", "get_point_size"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_particle_trails"), "set_flag", "get_flag", FLAG_PARTICLE_TRAILS_MODE); ADD_GROUP("Proximity Fade", "proximity_fade_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enable"), "set_proximity_fade", "is_proximity_fade_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "proximity_fade_enabled"), "set_proximity_fade_enabled", "is_proximity_fade_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "proximity_fade_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,suffix:m"), "set_proximity_fade_distance", "get_proximity_fade_distance"); ADD_GROUP("MSDF", "msdf_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), "set_msdf_pixel_range", "get_msdf_pixel_range"); diff --git a/scene/resources/material.h b/scene/resources/material.h index dd9589c577..b3c2159e70 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -719,7 +719,7 @@ public: void set_on_top_of_alpha(); - void set_proximity_fade(bool p_enable); + void set_proximity_fade_enabled(bool p_enable); bool is_proximity_fade_enabled() const; void set_proximity_fade_distance(float p_distance); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 03ccae5b74..706db3af16 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1576,9 +1576,8 @@ void ArrayMesh::_recompute_aabb() { } } } -#ifndef _MSC_VER -#warning need to add binding to add_surface using future MeshSurfaceData object -#endif + +// TODO: Need to add binding to add_surface using future MeshSurfaceData object. void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) { _create_if_empty(); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 1f71d583b1..1c99fa5554 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1546,7 +1546,7 @@ Array SceneState::get_connection_binds(int p_idx) const { return binds; } -bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method) { +bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance) { // this method cannot be const because of this Ref<SceneState> ss = this; @@ -1578,6 +1578,10 @@ bool SceneState::has_connection(const NodePath &p_node_from, const StringName &p } } + if (p_no_inheritance) { + break; + } + ss = ss->get_base_scene_state(); } while (ss.is_valid()); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 8e1a1d29b6..c6f82ddd5e 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -176,7 +176,7 @@ public: int get_connection_unbinds(int p_idx) const; Array get_connection_binds(int p_idx) const; - bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method); + bool has_connection(const NodePath &p_node_from, const StringName &p_signal, const NodePath &p_node_to, const StringName &p_method, bool p_no_inheritance = false); Vector<NodePath> get_editable_instances() const; diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp index e51c786786..b77430c154 100644 --- a/scene/resources/particle_process_material.cpp +++ b/scene/resources/particle_process_material.cpp @@ -115,6 +115,7 @@ void ParticleProcessMaterial::init_shaders() { shader_names->sub_emitter_frequency = "sub_emitter_frequency"; shader_names->sub_emitter_amount_at_end = "sub_emitter_amount_at_end"; + shader_names->sub_emitter_amount_at_collision = "sub_emitter_amount_at_collision"; shader_names->sub_emitter_keep_velocity = "sub_emitter_keep_velocity"; shader_names->collision_friction = "collision_friction"; @@ -235,6 +236,9 @@ void ParticleProcessMaterial::_update_shader() { if (sub_emitter_mode == SUB_EMITTER_AT_END) { code += "uniform int sub_emitter_amount_at_end;\n"; } + if (sub_emitter_mode == SUB_EMITTER_AT_COLLISION) { + code += "uniform int sub_emitter_amount_at_collision;\n"; + } code += "uniform bool sub_emitter_keep_velocity;\n"; } @@ -830,6 +834,13 @@ void ParticleProcessMaterial::_update_shader() { code += " TRANSFORM[3].z = 0.0;\n"; } + // scale by scale + code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n"; + code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n"; + code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n"; + code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n"; + code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n"; + if (collision_mode == COLLISION_RIGID) { code += " if (COLLIDED) {\n"; code += " if (length(VELOCITY) > 3.0) {\n"; @@ -844,21 +855,6 @@ void ParticleProcessMaterial::_update_shader() { } code += " }\n"; code += " }\n"; - } - - // scale by scale - code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n"; - code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n"; - code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n"; - code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n"; - code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n"; - - if (collision_mode == COLLISION_RIGID) { - code += " if (COLLIDED) {\n"; - code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n"; - code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n"; - code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n"; - code += " }\n"; } else if (collision_mode == COLLISION_HIDE_ON_CONTACT) { code += " if (COLLIDED) {\n"; code += " ACTIVE = false;\n"; @@ -874,7 +870,7 @@ void ParticleProcessMaterial::_update_shader() { code += " if (DELTA >= interval_rem) emit_count = 1;\n"; } break; case SUB_EMITTER_AT_COLLISION: { - code += " if (COLLIDED) emit_count = 1;\n"; + code += " if (COLLIDED) emit_count = sub_emitter_amount_at_collision;\n"; } break; case SUB_EMITTER_AT_END: { code += " float unit_delta = DELTA/LIFETIME;\n"; @@ -1433,6 +1429,10 @@ void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const p_property.usage = PROPERTY_USAGE_NONE; } + if (p_property.name == "sub_emitter_amount_at_collision" && sub_emitter_mode != SUB_EMITTER_AT_COLLISION) { + p_property.usage = PROPERTY_USAGE_NONE; + } + if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { p_property.usage = PROPERTY_USAGE_NONE; } @@ -1488,6 +1488,15 @@ int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const { return sub_emitter_amount_at_end; } +void ParticleProcessMaterial::set_sub_emitter_amount_at_collision(int p_amount) { + sub_emitter_amount_at_collision = p_amount; + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_amount_at_collision, p_amount); +} + +int ParticleProcessMaterial::get_sub_emitter_amount_at_collision() const { + return sub_emitter_amount_at_collision; +} + void ParticleProcessMaterial::set_sub_emitter_keep_velocity(bool p_enable) { sub_emitter_keep_velocity = p_enable; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_keep_velocity, p_enable); @@ -1640,6 +1649,9 @@ void ParticleProcessMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end); ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_end); + ClassDB::bind_method(D_METHOD("get_sub_emitter_amount_at_collision"), &ParticleProcessMaterial::get_sub_emitter_amount_at_collision); + ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_collision", "amount"), &ParticleProcessMaterial::set_sub_emitter_amount_at_collision); + ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity); ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity); @@ -1752,6 +1764,7 @@ void ParticleProcessMaterial::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_mode", PROPERTY_HINT_ENUM, "Disabled,Constant,At End,At Collision"), "set_sub_emitter_mode", "get_sub_emitter_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sub_emitter_frequency", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:Hz"), "set_sub_emitter_frequency", "get_sub_emitter_frequency"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_end", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_end", "get_sub_emitter_amount_at_end"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "sub_emitter_amount_at_collision", PROPERTY_HINT_RANGE, "1,32,1"), "set_sub_emitter_amount_at_collision", "get_sub_emitter_amount_at_collision"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sub_emitter_keep_velocity"), "set_sub_emitter_keep_velocity", "get_sub_emitter_keep_velocity"); ADD_GROUP("Attractor Interaction", "attractor_interaction_"); @@ -1859,6 +1872,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() : set_sub_emitter_mode(SUB_EMITTER_DISABLED); set_sub_emitter_frequency(4); set_sub_emitter_amount_at_end(1); + set_sub_emitter_amount_at_collision(1); set_sub_emitter_keep_velocity(false); set_attractor_interaction_enabled(true); diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h index 8fe9223a47..64d828b3e7 100644 --- a/scene/resources/particle_process_material.h +++ b/scene/resources/particle_process_material.h @@ -246,6 +246,7 @@ private: StringName sub_emitter_frequency; StringName sub_emitter_amount_at_end; + StringName sub_emitter_amount_at_collision; StringName sub_emitter_keep_velocity; StringName collision_friction; @@ -304,6 +305,7 @@ private: SubEmitterMode sub_emitter_mode; double sub_emitter_frequency = 0.0; int sub_emitter_amount_at_end = 0; + int sub_emitter_amount_at_collision = 0; bool sub_emitter_keep_velocity = false; //do not save emission points here @@ -418,6 +420,9 @@ public: void set_sub_emitter_amount_at_end(int p_amount); int get_sub_emitter_amount_at_end() const; + void set_sub_emitter_amount_at_collision(int p_amount); + int get_sub_emitter_amount_at_collision() const; + void set_sub_emitter_keep_velocity(bool p_enable); bool get_sub_emitter_keep_velocity() const; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 7d0336cff3..eb83a37c7b 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -771,6 +771,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto thisrow = 0; prevrow = 0; + const real_t side_normal_y = (bottom_radius - top_radius) / height; for (j = 0; j <= (rings + 1); j++) { v = j; v /= (rings + 1); @@ -789,7 +790,7 @@ void CylinderMesh::create_mesh_array(Array &p_arr, float top_radius, float botto Vector3 p = Vector3(x * radius, y, z * radius); points.push_back(p); - normals.push_back(Vector3(x, 0.0, z)); + normals.push_back(Vector3(x, side_normal_y, z).normalized()); ADD_TANGENT(z, 0.0, -x, 1.0) uvs.push_back(Vector2(u, v * 0.5)); point++; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index c0d65fb445..85b538b1d9 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -445,7 +445,14 @@ Error ResourceLoaderText::load() { // If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path. path = ResourceUID::get_singleton()->get_id_path(uid); } else { +#ifdef TOOLS_ENABLED + // Silence a warning that can happen during the initial filesystem scan due to cache being regenerated. + if (ResourceLoader::get_resource_uid(path) != uid) { + WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data()); + } +#else WARN_PRINT(String(res_path + ":" + itos(lines) + " - ext_resource, invalid UUID: " + uidt + " - using text path instead: " + path).utf8().get_data()); +#endif } } diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index fe43f345d4..61daf801e8 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -105,6 +105,7 @@ void Shape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("collide_and_get_contacts", "local_xform", "with_shape", "shape_xform"), &Shape2D::collide_and_get_contacts); ClassDB::bind_method(D_METHOD("collide_with_motion_and_get_contacts", "local_xform", "local_motion", "with_shape", "shape_xform", "shape_motion"), &Shape2D::collide_with_motion_and_get_contacts); ClassDB::bind_method(D_METHOD("draw", "canvas_item", "color"), &Shape2D::draw); + ClassDB::bind_method(D_METHOD("get_rect"), &Shape2D::get_rect); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias"); } diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 4085aa8ec2..fbcf140925 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -122,7 +122,7 @@ void Texture2D::_bind_methods() { GDVIRTUAL_BIND(_draw, "to_canvas_item", "pos", "modulate", "transpose") GDVIRTUAL_BIND(_draw_rect, "to_canvas_item", "rect", "tile", "modulate", "transpose") - GDVIRTUAL_BIND(_draw_rect_region, "tp_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"); + GDVIRTUAL_BIND(_draw_rect_region, "to_canvas_item", "rect", "src_rect", "modulate", "transpose", "clip_uv"); } Texture2D::Texture2D() { @@ -740,7 +740,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si } } - image->create(w, h, true, mipmap_images[0]->get_format(), img_data); + image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data); return image; } @@ -766,10 +766,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si f->get_buffer(wr, data.size()); } - Ref<Image> image; - image.instantiate(); - - image->create(tw, th, mipmaps - i ? true : false, format, data); + Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data); return image; } @@ -2336,11 +2333,11 @@ void GradientTexture2D::_update() { image.instantiate(); if (gradient->get_points_count() <= 1) { // No need to interpolate. - image->create(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8); + image->initialize_data(width, height, false, (use_hdr) ? Image::FORMAT_RGBAF : Image::FORMAT_RGBA8); image->fill((gradient->get_points_count() == 1) ? gradient->get_color(0) : Color(0, 0, 0, 1)); } else { if (use_hdr) { - image->create(width, height, false, Image::FORMAT_RGBAF); + image->initialize_data(width, height, false, Image::FORMAT_RGBAF); Gradient &g = **gradient; // `create()` isn't available for non-uint8_t data, so fill in the data manually. for (int y = 0; y < height; y++) { @@ -2367,7 +2364,7 @@ void GradientTexture2D::_update() { } } } - image->create(width, height, false, Image::FORMAT_RGBA8, data); + image->set_data(width, height, false, Image::FORMAT_RGBA8, data); } } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 4e529de8ee..9a9f0ad1af 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -238,7 +238,7 @@ private: Error _load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0); String path_to_file; mutable RID texture; - Image::Format format = Image::FORMAT_MAX; + Image::Format format = Image::FORMAT_L8; int w = 0; int h = 0; mutable Ref<BitMap> alpha_cache; @@ -415,7 +415,7 @@ class ImageTextureLayered : public TextureLayered { LayeredType layered_type; mutable RID texture; - Image::Format format = Image::FORMAT_MAX; + Image::Format format = Image::FORMAT_L8; int width = 0; int height = 0; @@ -495,7 +495,7 @@ private: Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0); String path_to_file; mutable RID texture; - Image::Format format = Image::FORMAT_MAX; + Image::Format format = Image::FORMAT_L8; int w = 0; int h = 0; int layers = 0; @@ -587,7 +587,7 @@ class ImageTexture3D : public Texture3D { mutable RID texture; - Image::Format format = Image::FORMAT_MAX; + Image::Format format = Image::FORMAT_L8; int width = 1; int height = 1; int depth = 1; @@ -641,7 +641,7 @@ private: Error _load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps); String path_to_file; mutable RID texture; - Image::Format format = Image::FORMAT_MAX; + Image::Format format = Image::FORMAT_L8; int w = 0; int h = 0; int d = 0; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index d7d7b5fe31..3caf6484d9 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -1801,11 +1801,11 @@ Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) { // Get the best tile. Ref<Texture2D> texture = counts[terrain_set][terrain].texture; Rect2i region = counts[terrain_set][terrain].region; - image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8); + image->initialize_data(region.size.x, region.size.y, false, Image::FORMAT_RGBA8); image->blit_rect(texture->get_image(), region, Point2i()); image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST); } else { - image->create(1, 1, false, Image::FORMAT_RGBA8); + image->initialize_data(1, 1, false, Image::FORMAT_RGBA8); image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain)); } Ref<ImageTexture> icon = ImageTexture::create_from_image(image); @@ -4602,9 +4602,7 @@ void TileSetAtlasSource::_update_padded_texture() { return; } - Ref<Image> image; - image.instantiate(); - image->create(size.x, size.y, false, src->get_format()); + Ref<Image> image = Image::create_empty(size.x, size.y, false, src->get_format()); for (KeyValue<Vector2i, TileAlternativesData> kv : tiles) { for (int frame = 0; frame < (int)kv.value.animation_frames_durations.size(); frame++) { diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index e156679711..8f175e99a6 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -277,6 +277,9 @@ public: bool operator<(const TerrainsPattern &p_terrains_pattern) const; bool operator==(const TerrainsPattern &p_terrains_pattern) const; + bool operator!=(const TerrainsPattern &p_terrains_pattern) const { + return !operator==(p_terrains_pattern); + }; void set_terrain(int p_terrain); int get_terrain() const; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index df9addb6bb..640f6dfcb7 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1509,11 +1509,10 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { } void VisualShader::reset_state() { -#ifndef _MSC_VER -#warning everything needs to be cleared here -#endif + // TODO: Everything needs to be cleared here. emit_changed(); } + void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { //mode p_list->push_back(PropertyInfo(Variant::INT, PNAME("mode"), PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky,Fog")); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index de13912b75..04637983b5 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -1642,17 +1642,20 @@ bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; + code += " {\n"; - code += " float _log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n"; - code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n"; - code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n"; - code += " _depth_view.xyz /= _depth_view.w;"; - code += vformat(" %s = -_depth_view.z;", p_output_vars[0]); + code += " float __log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n"; + code += " vec3 __depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, __log_depth);\n"; + code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(__depth_ndc, 1.0);\n"; + code += " __depth_view.xyz /= __depth_view.w;\n"; + code += vformat(" %s = -__depth_view.z;\n", p_output_vars[0]); + code += " }\n"; return code; } VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() { + simple_decl = false; } ////////////// Float Op @@ -3204,6 +3207,7 @@ String VisualShaderNodeUVPolarCoord::get_output_port_name(int p_port) const { String VisualShaderNodeUVPolarCoord::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"; String uv; if (p_input_vars[0].is_empty()) { @@ -3220,17 +3224,18 @@ String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualSh String repeat = vformat("%s", p_input_vars[3]); if (p_mode == Shader::MODE_CANVAS_ITEM) { - code += vformat(" vec2 __dir = %s - %s;\n", uv, center); - code += " float __radius = length(__dir) * 2.0;\n"; - code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n"; - code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat); + code += vformat(" vec2 __dir = %s - %s;\n", uv, center); + code += " float __radius = length(__dir) * 2.0;\n"; + code += " float __angle = atan(__dir.y, __dir.x) * 1.0 / (PI * 2.0);\n"; + code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat); } else { - code += vformat(" vec2 __dir = %s - %s;\n", uv, center); - code += " float __radius = length(__dir) * 2.0;\n"; - code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n"; - code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat); + code += vformat(" vec2 __dir = %s - %s;\n", uv, center); + code += " float __radius = length(__dir) * 2.0;\n"; + code += " float __angle = atan(__dir.y, __dir.x) * 1.0 / (PI * 2.0);\n"; + code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat); } + code += " }\n"; return code; } @@ -3238,6 +3243,8 @@ VisualShaderNodeUVPolarCoord::VisualShaderNodeUVPolarCoord() { set_input_port_default_value(1, Vector2(0.5, 0.5)); // center set_input_port_default_value(2, 1.0); // zoom set_input_port_default_value(3, 1.0); // repeat + + simple_decl = false; } ////////////// Dot Product @@ -7256,22 +7263,26 @@ bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const { String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; + code += " {\n"; String proximity_fade_distance = vformat("%s", p_input_vars[0]); - code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n"; + code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n"; if (!RenderingServer::get_singleton()->is_low_end()) { - code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n"; + code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n"; } else { - code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n"; + code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(vec3(SCREEN_UV, __depth_tex) * 2.0 - 1.0, 1.0);\n"; } - code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n"; - code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]); + code += " __depth_world_pos.xyz /= __depth_world_pos.w;\n"; + code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]); + code += " }\n"; return code; } VisualShaderNodeProximityFade::VisualShaderNodeProximityFade() { set_input_port_default_value(0, 1.0); + + simple_decl = false; } ////////////// Random Range @@ -7416,11 +7427,11 @@ String VisualShaderNodeRemap::get_output_port_name(int p_port) const { String VisualShaderNodeRemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; - - code += vformat(" float _input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); - code += vformat(" float _output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); - code += vformat(" %s = %s + _output_range * ((%s - %s) / _input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); - + code += " {\n"; + code += vformat(" float __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" float __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + code += " }\n"; return code; } @@ -7429,4 +7440,6 @@ VisualShaderNodeRemap::VisualShaderNodeRemap() { set_input_port_default_value(2, 1.0); set_input_port_default_value(3, 0.0); set_input_port_default_value(4, 1.0); + + simple_decl = false; } diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index ab7354f6e7..f125b05a26 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -460,9 +460,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2> image.instantiate(); if (p_array.size() == 0) { - image->create(1, 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF); } else { - image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); } for (int i = 0; i < p_array.size(); i++) { @@ -481,9 +481,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3> image.instantiate(); if (p_array.size() == 0) { - image->create(1, 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBF); } else { - image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); } for (int i = 0; i < p_array.size(); i++) { @@ -502,9 +502,9 @@ void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p image.instantiate(); if (p_array.size() == 0) { - image->create(1, 1, false, Image::Format::FORMAT_RGBA8); + image->initialize_data(1, 1, false, Image::Format::FORMAT_RGBA8); } else { - image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8); + image->initialize_data(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8); } for (int i = 0; i < p_array.size(); i++) { |