diff options
Diffstat (limited to 'scene')
33 files changed, 493 insertions, 207 deletions
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index bda7b495e1..ee186de5f1 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -101,7 +101,12 @@ void Polygon2D::_skeleton_bone_setup_changed() { } void Polygon2D::_notification(int p_what) { + if (p_what == NOTIFICATION_TRANSFORM_CHANGED && !Engine::get_singleton()->is_editor_hint()) { + return; // Mesh recreation for NOTIFICATION_TRANSFORM_CHANGED is only needed in editor. + } + switch (p_what) { + case NOTIFICATION_TRANSFORM_CHANGED: case NOTIFICATION_DRAW: { if (polygon.size() < 3) { return; @@ -364,7 +369,30 @@ void Polygon2D::_notification(int p_what) { arr[RS::ARRAY_INDEX] = index_array; - RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + RS::SurfaceData sd; + + if (skeleton_node) { + // Compute transform between mesh and skeleton for runtime AABB compute. + const Transform2D mesh_transform = get_global_transform(); + const Transform2D skeleton_transform = skeleton_node->get_global_transform(); + const Transform2D mesh_to_sk2d = mesh_transform * skeleton_transform.affine_inverse(); + + // Convert 2d transform to 3d. + sd.mesh_to_skeleton_xform.basis.rows[0][0] = mesh_to_sk2d.columns[0][0]; + sd.mesh_to_skeleton_xform.basis.rows[0][1] = mesh_to_sk2d.columns[0][1]; + sd.mesh_to_skeleton_xform.origin.x = mesh_to_sk2d.get_origin().x; + + sd.mesh_to_skeleton_xform.basis.rows[1][0] = mesh_to_sk2d.columns[1][0]; + sd.mesh_to_skeleton_xform.basis.rows[1][1] = mesh_to_sk2d.columns[1][1]; + sd.mesh_to_skeleton_xform.origin.y = mesh_to_sk2d.get_origin().y; + } + + Error err = RS::get_singleton()->mesh_create_surface_data_from_arrays(&sd, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); + if (err != OK) { + return; + } + + RS::get_singleton()->mesh_add_surface(mesh, sd); RS::get_singleton()->canvas_item_add_mesh(get_canvas_item(), mesh, Transform2D(), Color(1, 1, 1), texture.is_valid() ? texture->get_rid() : RID()); } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 04e362c426..f2be91cbf3 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -447,11 +447,12 @@ void TileMapLayer::_rendering_update() { for (KeyValue<Vector2i, CellData> &kv : tile_map) { CellData &cell_data = kv.value; for (const RID &occluder : cell_data.occluders) { - if (occluder.is_valid()) { - Transform2D xform(0, tile_map_node->map_to_local(kv.key)); - rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); - rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); + if (occluder.is_null()) { + continue; } + Transform2D xform(0, tile_map_node->map_to_local(kv.key)); + rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); + rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); } } } @@ -591,6 +592,11 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { tile_data = atlas_source->get_tile_data(r_cell_data.cell.get_atlas_coords(), r_cell_data.cell.alternative_tile); } + // Transform flags. + bool flip_h = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (r_cell_data.cell.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + // Create, update or clear occluders. for (uint32_t occlusion_layer_index = 0; occlusion_layer_index < r_cell_data.occluders.size(); occlusion_layer_index++) { Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer_index); @@ -606,7 +612,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { } rs->canvas_light_occluder_set_enabled(occluder, node_visible); rs->canvas_light_occluder_set_transform(occluder, tile_map_node->get_global_transform() * xform); - rs->canvas_light_occluder_set_polygon(occluder, tile_map_node->get_transformed_polygon(Ref<Resource>(tile_data->get_occluder(occlusion_layer_index)), r_cell_data.cell.alternative_tile)->get_rid()); + rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder(occlusion_layer_index, flip_h, flip_v, transpose)->get_rid()); rs->canvas_light_occluder_attach_to_canvas(occluder, tile_map_node->get_canvas()); rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index)); } else { @@ -800,6 +806,11 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } + // Transform flags. + bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + // Free unused bodies then resize the bodies array. for (uint32_t i = tile_set->get_physics_layers_count(); i < r_cell_data.bodies.size(); i++) { RID body = r_cell_data.bodies[i]; @@ -864,8 +875,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { int shapes_count = tile_data->get_collision_polygon_shapes_count(tile_set_physics_layer, polygon_index); for (int shape_index = 0; shape_index < shapes_count; shape_index++) { // Add decomposed convex shapes. - Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(tile_set_physics_layer, polygon_index, shape_index); - shape = tile_map_node->get_transformed_polygon(Ref<Resource>(shape), c.alternative_tile); + Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(tile_set_physics_layer, polygon_index, shape_index, flip_h, flip_v, transpose); ps->body_add_shape(body, shape->get_rid()); ps->body_set_shape_as_one_way_collision(body, body_shape_index, one_way_collision, one_way_collision_margin); @@ -1053,6 +1063,11 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { tile_data = atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile); } + // Transform flags. + bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + // Free unused regions then resize the regions array. for (uint32_t i = tile_set->get_navigation_layers_count(); i < r_cell_data.navigation_regions.size(); i++) { RID ®ion = r_cell_data.navigation_regions[i]; @@ -1066,9 +1081,7 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { // Create, update or clear regions. for (uint32_t navigation_layer_index = 0; navigation_layer_index < r_cell_data.navigation_regions.size(); navigation_layer_index++) { - Ref<NavigationPolygon> navigation_polygon; - navigation_polygon = tile_data->get_navigation_polygon(navigation_layer_index); - navigation_polygon = tile_map_node->get_transformed_polygon(Ref<Resource>(navigation_polygon), c.alternative_tile); + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer_index, flip_h, flip_v, transpose); RID ®ion = r_cell_data.navigation_regions[navigation_layer_index]; @@ -1161,9 +1174,11 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V rs->canvas_item_add_set_transform(p_canvas_item, cell_to_quadrant); for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) { - Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(layer_index); + bool flip_h = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H); + bool flip_v = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V); + bool transpose = (c.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE); + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(layer_index, flip_h, flip_v, transpose); if (navigation_polygon.is_valid()) { - navigation_polygon = tile_map_node->get_transformed_polygon(Ref<Resource>(navigation_polygon), c.alternative_tile); Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices(); if (navigation_polygon_vertices.size() < 3) { continue; @@ -3119,11 +3134,6 @@ void TileMap::_internal_update() { return; } - // FIXME: This should only clear polygons that are no longer going to be used, but since it's difficult to determine, - // the cache is never cleared at runtime to prevent invalidating used polygons. - if (Engine::get_singleton()->is_editor_hint()) { - polygon_cache.clear(); - } // Update dirty quadrants on layers. for (Ref<TileMapLayer> &layer : layers) { layer->internal_update(); @@ -3608,37 +3618,6 @@ Rect2 TileMap::_edit_get_rect() const { } #endif -PackedVector2Array TileMap::_get_transformed_vertices(const PackedVector2Array &p_vertices, int p_alternative_id) { - const Vector2 *r = p_vertices.ptr(); - int size = p_vertices.size(); - - PackedVector2Array new_points; - new_points.resize(size); - Vector2 *w = new_points.ptrw(); - - bool flip_h = (p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H); - bool flip_v = (p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V); - bool transpose = (p_alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE); - - for (int i = 0; i < size; i++) { - Vector2 v; - if (transpose) { - v = Vector2(r[i].y, r[i].x); - } else { - v = r[i]; - } - - if (flip_h) { - v.x *= -1; - } - if (flip_v) { - v.y *= -1; - } - w[i] = v; - } - return new_points; -} - bool TileMap::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); if (p_name == "format") { @@ -4637,57 +4616,6 @@ void TileMap::draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_ce #undef DRAW_SIDE_IF_NEEDED } -Ref<Resource> TileMap::get_transformed_polygon(Ref<Resource> p_polygon, int p_alternative_id) { - if (!bool(p_alternative_id & (TileSetAtlasSource::TRANSFORM_FLIP_H | TileSetAtlasSource::TRANSFORM_FLIP_V | TileSetAtlasSource::TRANSFORM_TRANSPOSE))) { - return p_polygon; - } - - { - HashMap<Pair<Ref<Resource>, int>, Ref<Resource>, PairHash<Ref<Resource>, int>>::Iterator E = polygon_cache.find(Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)); - if (E) { - return E->value; - } - } - - Ref<ConvexPolygonShape2D> col = p_polygon; - if (col.is_valid()) { - Ref<ConvexPolygonShape2D> ret; - ret.instantiate(); - ret->set_points(_get_transformed_vertices(col->get_points(), p_alternative_id)); - polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret; - return ret; - } - - Ref<NavigationPolygon> nav = p_polygon; - if (nav.is_valid()) { - PackedVector2Array new_points = _get_transformed_vertices(nav->get_vertices(), p_alternative_id); - Ref<NavigationPolygon> ret; - ret.instantiate(); - ret->set_vertices(new_points); - - PackedInt32Array indices; - indices.resize(new_points.size()); - int *w = indices.ptrw(); - for (int i = 0; i < new_points.size(); i++) { - w[i] = i; - } - ret->add_polygon(indices); - polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret; - return ret; - } - - Ref<OccluderPolygon2D> ocd = p_polygon; - if (ocd.is_valid()) { - Ref<OccluderPolygon2D> ret; - ret.instantiate(); - ret->set_polygon(_get_transformed_vertices(ocd->get_polygon(), p_alternative_id)); - polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret; - return ret; - } - - return p_polygon; -} - PackedStringArray TileMap::get_configuration_warnings() const { PackedStringArray warnings = Node::get_configuration_warnings(); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 9a847a7ebb..1e4c6d0e66 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -472,10 +472,6 @@ private: void _update_notify_local_transform(); - // Polygons. - HashMap<Pair<Ref<Resource>, int>, Ref<Resource>, PairHash<Ref<Resource>, int>> polygon_cache; - PackedVector2Array _get_transformed_vertices(const PackedVector2Array &p_vertices, int p_alternative_id); - protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -619,7 +615,6 @@ public: // Helpers? TypedArray<Vector2i> get_surrounding_cells(const Vector2i &coords); void draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform = Transform2D()); - Ref<Resource> get_transformed_polygon(Ref<Resource> p_polygon, int p_alternative_id); // Virtual function to modify the TileData at runtime. GDVIRTUAL2R(bool, _use_tile_data_runtime_update, int, Vector2i); diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index c6d69cf622..da00d1dd7b 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -638,6 +638,10 @@ bool AnimationMixer::_update_caches() { switch (track_type) { case Animation::TYPE_VALUE: { + // If a value track without a key is cached first, the initial value cannot be determined. + // It is a corner case, but which may cause problems with blending. + ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, "AnimationMixer: '" + String(E) + "', Value Track: '" + String(path) + "' must have at least one key to cache for blending."); + TrackCacheValue *track_value = memnew(TrackCacheValue); if (resource.is_valid()) { @@ -654,9 +658,6 @@ bool AnimationMixer::_update_caches() { track = track_value; - // If a value track without a key is cached first, the initial value cannot be determined. - // It is a corner case, but which may cause problems with blending. - ERR_CONTINUE_MSG(anim->track_get_key_count(i) == 0, "AnimationMixer: '" + String(E) + "', Value Track: '" + String(path) + "' must have at least one key to cache for blending."); track_value->init_value = anim->track_get_key_value(i, 0); track_value->init_value.zero(); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index dd5ff7912f..f4e1b3615c 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -860,7 +860,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An pi.time = 0; pi.seeked = true; } - fading_from_rem = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + fading_from_rem = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. // Guess playback position. if (fading_from_rem > len_fade_from) { /// Weird but ok. @@ -976,7 +976,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT pi.seeked = true; pi.is_external_seeking = false; pi.weight = 0; - p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true); + p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); } // Just get length to find next recursive. diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index bdadc4ecac..e24816122c 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -100,9 +100,9 @@ void AnimationNode::blend_animation(const StringName &p_animation, AnimationMixe process_state->tree->make_animation_instance(p_animation, p_playback_info); } -double AnimationNode::_pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info) { +double AnimationNode::_pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { process_state = p_process_state; - double t = process(p_playback_info); + double t = process(p_playback_info, p_test_only); process_state = nullptr; return t; } @@ -152,7 +152,7 @@ double AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_pl } double AnimationNode::blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) { - node_state.connections.clear(); + p_node->node_state.connections.clear(); return _blend_node(p_node, p_subpath, this, p_playback_info, p_filter, p_sync, p_test_only, nullptr); } @@ -269,9 +269,9 @@ double AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p p_node->node_state.parent = new_parent; if (!p_playback_info.seeked && !p_sync && !any_valid) { p_playback_info.time = 0.0; - return p_node->_pre_process(process_state, p_playback_info); + return p_node->_pre_process(process_state, p_playback_info, p_test_only); } - return p_node->_pre_process(process_state, p_playback_info); + return p_node->_pre_process(process_state, p_playback_info, p_test_only); } String AnimationNode::get_caption() const { @@ -565,12 +565,12 @@ bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const if (started) { // If started, seek. pi.seeked = true; - root_animation_node->_pre_process(&process_state, pi); + root_animation_node->_pre_process(&process_state, pi, false); started = false; - } else { - pi.time = p_delta; - root_animation_node->_pre_process(&process_state, pi); } + pi.seeked = false; + pi.time = p_delta; + root_animation_node->_pre_process(&process_state, pi, false); } if (!process_state.valid) { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 0be487d3fd..87928e4d20 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -85,7 +85,7 @@ public: void _set_filters(const Array &p_filters); friend class AnimationNodeBlendTree; double _blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false, real_t *r_activity = nullptr); - double _pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info); + double _pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); protected: virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index f250662be0..23b216195a 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -74,7 +74,7 @@ void ColorPicker::_notification(int p_what) { sliders[i]->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers); } alpha_label->set_custom_minimum_size(Size2(theme_cache.label_width, 0)); - alpha_label->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers); + alpha_slider->add_theme_constant_override(SNAME("center_grabber"), theme_cache.center_slider_grabbers); for (int i = 0; i < MODE_BUTTON_COUNT; i++) { mode_btns[i]->begin_bulk_theme_override(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 2fbd29b048..3df0d97160 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -240,10 +240,12 @@ void Label::_shape() { if (i < jst_to_line) { TS->shaped_text_fit_to_width(lines_rid[i], width, line_jst_flags); } else if (i == (visible_lines - 1)) { + TS->shaped_text_set_custom_ellipsis(lines_rid[i], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags); } } } else if (lines_hidden) { + TS->shaped_text_set_custom_ellipsis(lines_rid[visible_lines - 1], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags); } } else { @@ -268,9 +270,11 @@ void Label::_shape() { if (i < jst_to_line && horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) { TS->shaped_text_fit_to_width(lines_rid[i], width, line_jst_flags); overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE); + TS->shaped_text_set_custom_ellipsis(lines_rid[i], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags); TS->shaped_text_fit_to_width(lines_rid[i], width, line_jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS); } else { + TS->shaped_text_set_custom_ellipsis(lines_rid[i], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags); } } @@ -887,6 +891,27 @@ TextServer::OverrunBehavior Label::get_text_overrun_behavior() const { return overrun_behavior; } +void Label::set_ellipsis_char(const String &p_char) { + String c = p_char; + if (c.length() > 1) { + WARN_PRINT("Ellipsis must be exactly one character long (" + itos(c.length()) + " characters given)."); + c = c.left(1); + } + if (el_char == c) { + return; + } + el_char = c; + lines_dirty = true; + queue_redraw(); + if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { + update_minimum_size(); + } +} + +String Label::get_ellipsis_char() const { + return el_char; +} + String Label::get_text() const { return text; } @@ -1007,6 +1032,8 @@ void Label::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tab_stops"), &Label::get_tab_stops); ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &Label::set_text_overrun_behavior); ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &Label::get_text_overrun_behavior); + ClassDB::bind_method(D_METHOD("set_ellipsis_char", "char"), &Label::set_ellipsis_char); + ClassDB::bind_method(D_METHOD("get_ellipsis_char"), &Label::get_ellipsis_char); ClassDB::bind_method(D_METHOD("set_uppercase", "enable"), &Label::set_uppercase); ClassDB::bind_method(D_METHOD("is_uppercase"), &Label::is_uppercase); ClassDB::bind_method(D_METHOD("get_line_height", "line"), &Label::get_line_height, DEFVAL(-1)); @@ -1037,6 +1064,7 @@ void Label::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "ellipsis_char"), "set_ellipsis_char", "get_ellipsis_char"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "tab_stops"), "set_tab_stops", "get_tab_stops"); diff --git a/scene/gui/label.h b/scene/gui/label.h index a5126c6b91..44443e3eb4 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -45,6 +45,7 @@ private: TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF; BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE; bool clip = false; + String el_char = U"…"; TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING; Size2 minsize; bool uppercase = false; @@ -147,6 +148,9 @@ public: void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior); TextServer::OverrunBehavior get_text_overrun_behavior() const; + void set_ellipsis_char(const String &p_char); + String get_ellipsis_char() const; + void set_lines_skipped(int p_lines); int get_lines_skipped() const; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 5ed1a9d5e3..5cca09bcf6 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -1914,12 +1914,15 @@ bool LineEdit::is_secret() const { } void LineEdit::set_secret_character(const String &p_string) { - if (secret_character == p_string) { + String c = p_string; + if (c.length() > 1) { + WARN_PRINT("Secret character must be exactly one character long (" + itos(c.length()) + " characters given)."); + c = c.left(1); + } + if (secret_character == c) { return; } - - secret_character = p_string; - update_configuration_warnings(); + secret_character = c; _shape(); queue_redraw(); } @@ -2285,14 +2288,8 @@ void LineEdit::_shape() { if (text.length() == 0 && ime_text.length() == 0) { t = placeholder_translated; } else if (pass) { - // TODO: Integrate with text server to add support for non-latin scripts. - // Allow secret_character as empty strings, act like if a space was used as a secret character. - String secret = " "; - // Allow values longer than 1 character in the property, but trim characters after the first one. - if (!secret_character.is_empty()) { - secret = secret_character.left(1); - } - t = secret.repeat(text.length() + ime_text.length()); + String s = (secret_character.length() > 0) ? secret_character.left(1) : U"•"; + t = s.repeat(text.length() + ime_text.length()); } else { if (ime_text.length() > 0) { t = text.substr(0, caret_column) + ime_text + text.substr(caret_column, text.length()); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 41f4de5b3b..fbc374e89e 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -6331,11 +6331,9 @@ Ref<RichTextEffect> RichTextLabel::_get_custom_effect_by_code(String p_bbcode_id Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressions) { Dictionary d; for (int i = 0; i < p_expressions.size(); i++) { - String expression = p_expressions[i]; - Array a; - Vector<String> parts = expression.split("=", true); - String key = parts[0]; + Vector<String> parts = p_expressions[i].split("=", true); + const String &key = parts[0]; if (parts.size() != 2) { return d; } diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp index 777ca96cc4..e9fbdbb312 100644 --- a/scene/gui/tab_bar.cpp +++ b/scene/gui/tab_bar.cpp @@ -1664,7 +1664,7 @@ bool TabBar::_set(const StringName &p_name, const Variant &p_value) { } else if (property == "icon") { set_tab_icon(tab_index, p_value); return true; - } else if (components[1] == "disabled") { + } else if (property == "disabled") { set_tab_disabled(tab_index, p_value); return true; } @@ -1683,7 +1683,7 @@ bool TabBar::_get(const StringName &p_name, Variant &r_ret) const { } else if (property == "icon") { r_ret = get_tab_icon(tab_index); return true; - } else if (components[1] == "disabled") { + } else if (property == "disabled") { r_ret = is_tab_disabled(tab_index); return true; } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 5817f70343..308250c592 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -5314,8 +5314,7 @@ int TextEdit::get_line_wrap_index_at_column(int p_line, int p_column) const { Vector<String> lines = get_line_wrapped_text(p_line); for (int i = 0; i < lines.size(); i++) { wrap_index = i; - String s = lines[wrap_index]; - col += s.length(); + col += lines[wrap_index].length(); if (col > p_column) { break; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 1d06ce05ae..8a243fd68f 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -70,19 +70,27 @@ void TreeItem::Cell::draw_icon(const RID &p_where, const Point2 &p_pos, const Si } void TreeItem::_changed_notify(int p_cell) { - tree->item_changed(p_cell, this); + if (tree) { + tree->item_changed(p_cell, this); + } } void TreeItem::_changed_notify() { - tree->item_changed(-1, this); + if (tree) { + tree->item_changed(-1, this); + } } void TreeItem::_cell_selected(int p_cell) { - tree->item_selected(p_cell, this); + if (tree) { + tree->item_selected(p_cell, this); + } } void TreeItem::_cell_deselected(int p_cell) { - tree->item_deselected(p_cell, this); + if (tree) { + tree->item_deselected(p_cell, this); + } } void TreeItem::_change_tree(Tree *p_tree) { diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp index de42b63548..fe0e82370a 100644 --- a/scene/main/resource_preloader.cpp +++ b/scene/main/resource_preloader.cpp @@ -40,12 +40,11 @@ void ResourcePreloader::_set_resources(const Array &p_data) { ERR_FAIL_COND(names.size() != resdata.size()); for (int i = 0; i < resdata.size(); i++) { - String name = names[i]; Ref<Resource> resource = resdata[i]; ERR_CONTINUE(!resource.is_valid()); - resources[name] = resource; + resources[names[i]] = resource; - //add_resource(name,resource); + //add_resource(names[i],resource); } } diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index cf80bd6c6f..4417007b9d 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1302,6 +1302,16 @@ bool SceneTree::has_group(const StringName &p_identifier) const { return group_map.has(p_identifier); } +int SceneTree::get_node_count_in_group(const StringName &p_group) const { + _THREAD_SAFE_METHOD_ + HashMap<StringName, Group>::ConstIterator E = group_map.find(p_group); + if (!E) { + return 0; + } + + return E->value.nodes.size(); +} + Node *SceneTree::get_first_node_in_group(const StringName &p_group) { _THREAD_SAFE_METHOD_ HashMap<StringName, Group>::Iterator E = group_map.find(p_group); @@ -1617,6 +1627,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group); ClassDB::bind_method(D_METHOD("get_first_node_in_group", "group"), &SceneTree::get_first_node_in_group); + ClassDB::bind_method(D_METHOD("get_node_count_in_group", "group"), &SceneTree::get_node_count_in_group); ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene); ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index e1597d3890..618ac275ff 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -385,6 +385,7 @@ public: void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list); Node *get_first_node_in_group(const StringName &p_group); bool has_group(const StringName &p_identifier) const; + int get_node_count_in_group(const StringName &p_group) const; //void change_scene(const String& p_path); //Node *get_loaded_scene(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index b1b3bab937..52850cac4a 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -5485,7 +5485,7 @@ Variant Animation::cast_to_blendwise(const Variant p_value) { switch (p_value.get_type()) { case Variant::BOOL: case Variant::INT: { - return p_value.operator real_t(); + return p_value.operator double(); } break; case Variant::STRING: case Variant::STRING_NAME: { @@ -5521,7 +5521,7 @@ Variant Animation::cast_from_blendwise(const Variant p_value, const Variant::Typ return p_value.operator real_t() >= 0.5; } break; case Variant::INT: { - return (int)Math::round(p_value.operator real_t()); + return (int64_t)Math::round(p_value.operator double()); } break; case Variant::STRING: { return array_to_string(p_value); @@ -5594,8 +5594,12 @@ Variant Animation::array_to_string(const Variant p_value) { } Variant Animation::add_variant(const Variant &a, const Variant &b) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return add_variant(cast_to_blendwise(a), cast_to_blendwise(b)); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5603,7 +5607,7 @@ Variant Animation::add_variant(const Variant &a, const Variant &b) { return Variant(); } break; case Variant::FLOAT: { - return (a.operator real_t()) + (b.operator real_t()); + return (a.operator double()) + (b.operator double()); } break; case Variant::RECT2: { const Rect2 ra = a.operator Rect2(); @@ -5704,8 +5708,12 @@ Variant Animation::add_variant(const Variant &a, const Variant &b) { } Variant Animation::subtract_variant(const Variant &a, const Variant &b) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return subtract_variant(cast_to_blendwise(a), cast_to_blendwise(b)); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5713,7 +5721,7 @@ Variant Animation::subtract_variant(const Variant &a, const Variant &b) { return Variant(); } break; case Variant::FLOAT: { - return (a.operator real_t()) - (b.operator real_t()); + return (a.operator double()) - (b.operator double()); } break; case Variant::RECT2: { const Rect2 ra = a.operator Rect2(); @@ -5814,8 +5822,12 @@ Variant Animation::subtract_variant(const Variant &a, const Variant &b) { } Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return blend_variant(cast_to_blendwise(a), cast_to_blendwise(b), c); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5823,7 +5835,7 @@ Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) { return Variant(); } break; case Variant::FLOAT: { - return (a.operator real_t()) + (b.operator real_t()) * c; + return (a.operator double()) + (b.operator double()) * c; } break; case Variant::VECTOR2: { return (a.operator Vector2()) + (b.operator Vector2()) * c; @@ -5947,8 +5959,12 @@ Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) { } Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element) { - if (a.get_type() != b.get_type() && !a.is_array()) { - return a; + if (a.get_type() != b.get_type()) { + if (a.is_num() && b.is_num()) { + return interpolate_variant(cast_to_blendwise(a), cast_to_blendwise(b), c); + } else if (!a.is_array()) { + return a; + } } switch (a.get_type()) { @@ -5956,8 +5972,8 @@ Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float return Variant(); } break; case Variant::FLOAT: { - const real_t va = a.operator real_t(); - return va + ((b.operator real_t()) - va) * c; + const double va = a.operator double(); + return va + ((b.operator double()) - va) * c; } break; case Variant::VECTOR2: { return (a.operator Vector2()).lerp(b.operator Vector2(), c); diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp index 66d758080e..2ffb8da46c 100644 --- a/scene/resources/importer_mesh.cpp +++ b/scene/resources/importer_mesh.cpp @@ -418,11 +418,10 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli } } - LocalVector<float> normal_weights; - normal_weights.resize(merged_vertex_count); - for (unsigned int j = 0; j < merged_vertex_count; j++) { - normal_weights[j] = 2.0; // Give some weight to normal preservation, may be worth exposing as an import setting - } + const float normal_weights[3] = { + // Give some weight to normal preservation, may be worth exposing as an import setting + 2.0f, 2.0f, 2.0f + }; Vector<float> merged_vertices_f32 = vector3_to_float32_array(merged_vertices_ptr, merged_vertex_count); float scale = SurfaceTool::simplify_scale_func(merged_vertices_f32.ptr(), merged_vertex_count, sizeof(float) * 3); @@ -460,12 +459,13 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli (const uint32_t *)merged_indices_ptr, index_count, merged_vertices_f32.ptr(), merged_vertex_count, sizeof(float) * 3, // Vertex stride + merged_normals_f32.ptr(), + sizeof(float) * 3, // Attribute stride + normal_weights, 3, index_target, max_mesh_error, simplify_options, - &mesh_error, - merged_normals_f32.ptr(), - normal_weights.ptr(), 3); + &mesh_error); if (new_index_count < last_index_count * 1.5f) { index_target = index_target * 1.5f; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 19718f12be..3dc920c4be 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -973,8 +973,7 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String } if (p_map.has(path)) { - String np = p_map[path]; - path = np; + path = p_map[path]; } if (relative) { diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp index d0b5625298..4458cdc0e3 100644 --- a/scene/resources/skeleton_modification_2d_twoboneik.cpp +++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp @@ -468,8 +468,8 @@ void SkeletonModification2DTwoBoneIK::_bind_methods() { ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0,100000000,0.01,suffix:m"), "set_target_minimum_distance", "get_target_minimum_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0,100000000,0.01,suffix:m"), "set_target_maximum_distance", "get_target_maximum_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0,100000000,0.01,suffix:px"), "set_target_minimum_distance", "get_target_minimum_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0,100000000,0.01,suffix:px"), "set_target_maximum_distance", "get_target_maximum_distance"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_bend_direction", PROPERTY_HINT_NONE, ""), "set_flip_bend_direction", "get_flip_bend_direction"); ADD_GROUP("", ""); } diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 670ce152bd..640261d615 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -161,6 +161,15 @@ bool ProceduralSkyMaterial::get_use_debanding() const { return use_debanding; } +void ProceduralSkyMaterial::set_energy_multiplier(float p_multiplier) { + global_energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "exposure", global_energy_multiplier); +} + +float ProceduralSkyMaterial::get_energy_multiplier() const { + return global_energy_multiplier; +} + Shader::Mode ProceduralSkyMaterial::get_shader_mode() const { return Shader::MODE_SKY; } @@ -226,6 +235,9 @@ void ProceduralSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_debanding", "use_debanding"), &ProceduralSkyMaterial::set_use_debanding); ClassDB::bind_method(D_METHOD("get_use_debanding"), &ProceduralSkyMaterial::get_use_debanding); + ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &ProceduralSkyMaterial::set_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &ProceduralSkyMaterial::get_energy_multiplier); + ADD_GROUP("Sky", "sky_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_top_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_top_color", "get_sky_top_color"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "sky_horizon_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_sky_horizon_color", "get_sky_horizon_color"); @@ -246,6 +258,7 @@ void ProceduralSkyMaterial::_bind_methods() { ADD_GROUP("", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "get_use_debanding"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier"); } void ProceduralSkyMaterial::cleanup_shader() { @@ -280,6 +293,7 @@ uniform float ground_curve : hint_range(0, 1) = 0.02; uniform float ground_energy = 1.0; uniform float sun_angle_max = 30.0; uniform float sun_curve : hint_range(0, 1) = 0.15; +uniform float exposure : hint_range(0, 128) = 1.0; void sky() { float v_angle = acos(clamp(EYEDIR.y, -1.0, 1.0)); @@ -334,7 +348,7 @@ void sky() { vec3 ground = mix(ground_horizon_color.rgb, ground_bottom_color.rgb, clamp(1.0 - pow(1.0 - c, 1.0 / ground_curve), 0.0, 1.0)); ground *= ground_energy; - COLOR = mix(ground, sky, step(0.0, EYEDIR.y)); + COLOR = mix(ground, sky, step(0.0, EYEDIR.y)) * exposure; } )", i ? "render_mode use_debanding;" : "")); @@ -358,6 +372,7 @@ ProceduralSkyMaterial::ProceduralSkyMaterial() { set_sun_angle_max(30.0); set_sun_curve(0.15); set_use_debanding(true); + set_energy_multiplier(1.0); } ProceduralSkyMaterial::~ProceduralSkyMaterial() { @@ -393,6 +408,15 @@ bool PanoramaSkyMaterial::is_filtering_enabled() const { return filter; } +void PanoramaSkyMaterial::set_energy_multiplier(float p_multiplier) { + energy_multiplier = p_multiplier; + RS::get_singleton()->material_set_param(_get_material(), "exposure", energy_multiplier); +} + +float PanoramaSkyMaterial::get_energy_multiplier() const { + return energy_multiplier; +} + Shader::Mode PanoramaSkyMaterial::get_shader_mode() const { return Shader::MODE_SKY; } @@ -420,8 +444,12 @@ void PanoramaSkyMaterial::_bind_methods() { ClassDB::bind_method(D_METHOD("set_filtering_enabled", "enabled"), &PanoramaSkyMaterial::set_filtering_enabled); ClassDB::bind_method(D_METHOD("is_filtering_enabled"), &PanoramaSkyMaterial::is_filtering_enabled); + ClassDB::bind_method(D_METHOD("set_energy_multiplier", "multiplier"), &PanoramaSkyMaterial::set_energy_multiplier); + ClassDB::bind_method(D_METHOD("get_energy_multiplier"), &PanoramaSkyMaterial::get_energy_multiplier); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "panorama", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_panorama", "get_panorama"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter"), "set_filtering_enabled", "is_filtering_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "energy_multiplier", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_energy_multiplier", "get_energy_multiplier"); } Mutex PanoramaSkyMaterial::shader_mutex; @@ -447,9 +475,10 @@ void PanoramaSkyMaterial::_update_shader() { shader_type sky; uniform sampler2D source_panorama : %s, source_color, hint_default_black; +uniform float exposure : hint_range(0, 128) = 1.0; void sky() { - COLOR = texture(source_panorama, SKY_COORDS).rgb; + COLOR = texture(source_panorama, SKY_COORDS).rgb * exposure; } )", i ? "filter_linear" : "filter_nearest")); @@ -460,6 +489,7 @@ void sky() { } PanoramaSkyMaterial::PanoramaSkyMaterial() { + set_energy_multiplier(1.0); } PanoramaSkyMaterial::~PanoramaSkyMaterial() { diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index f570dd998d..4ffb18c6b4 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -53,6 +53,7 @@ private: float sun_angle_max = 0.0f; float sun_curve = 0.0f; bool use_debanding = true; + float global_energy_multiplier = 1.0f; static Mutex shader_mutex; static RID shader_cache[2]; @@ -103,6 +104,9 @@ public: void set_use_debanding(bool p_use_debanding); bool get_use_debanding() const; + void set_energy_multiplier(float p_multiplier); + float get_energy_multiplier() const; + virtual Shader::Mode get_shader_mode() const override; virtual RID get_shader_rid() const override; virtual RID get_rid() const override; @@ -121,6 +125,7 @@ class PanoramaSkyMaterial : public Material { private: Ref<Texture2D> panorama; + float energy_multiplier = 1.0f; static Mutex shader_mutex; static RID shader_cache[2]; diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index 2a8ad53525..9dfb298b9e 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -86,7 +86,7 @@ public: static OptimizeVertexCacheFunc optimize_vertex_cache_func; typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, unsigned int options, float *r_error); static SimplifyFunc simplify_func; - typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float *result_error, const float *attributes, const float *attribute_weights, size_t attribute_count); + typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, const float *attributes, size_t attribute_stride, const float *attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float *result_error); static SimplifyWithAttribFunc simplify_with_attrib_func; typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride); static SimplifyScaleFunc simplify_scale_func; diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp index 98527da96b..76c0a28ea4 100644 --- a/scene/resources/text_line.cpp +++ b/scene/resources/text_line.cpp @@ -81,6 +81,10 @@ void TextLine::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior"); + ClassDB::bind_method(D_METHOD("set_ellipsis_char", "char"), &TextLine::set_ellipsis_char); + ClassDB::bind_method(D_METHOD("get_ellipsis_char"), &TextLine::get_ellipsis_char); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "ellipsis_char"), "set_ellipsis_char", "get_ellipsis_char"); + ClassDB::bind_method(D_METHOD("get_objects"), &TextLine::get_objects); ClassDB::bind_method(D_METHOD("get_object_rect", "key"), &TextLine::get_object_rect); @@ -137,8 +141,10 @@ void TextLine::_shape() { if (alignment == HORIZONTAL_ALIGNMENT_FILL) { TS->shaped_text_fit_to_width(rid, width, flags); overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE); + TS->shaped_text_set_custom_ellipsis(rid, (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags); } else { + TS->shaped_text_set_custom_ellipsis(rid, (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(rid, width, overrun_flags); } } else if (alignment == HORIZONTAL_ALIGNMENT_FILL) { @@ -306,6 +312,23 @@ TextServer::OverrunBehavior TextLine::get_text_overrun_behavior() const { return overrun_behavior; } +void TextLine::set_ellipsis_char(const String &p_char) { + String c = p_char; + if (c.length() > 1) { + WARN_PRINT("Ellipsis must be exactly one character long (" + itos(c.length()) + " characters given)."); + c = c.left(1); + } + if (el_char == c) { + return; + } + el_char = c; + dirty = true; +} + +String TextLine::get_ellipsis_char() const { + return el_char; +} + void TextLine::set_width(float p_width) { width = p_width; if (alignment == HORIZONTAL_ALIGNMENT_FILL || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h index cc52d2e6a7..795bdeb15c 100644 --- a/scene/resources/text_line.h +++ b/scene/resources/text_line.h @@ -47,6 +47,7 @@ private: float width = -1.0; BitField<TextServer::JustificationFlag> flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA; HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT; + String el_char = U"…"; TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_TRIM_ELLIPSIS; Vector<float> tab_stops; @@ -90,6 +91,9 @@ public: void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior); TextServer::OverrunBehavior get_text_overrun_behavior() const; + void set_ellipsis_char(const String &p_char); + String get_ellipsis_char() const; + void set_width(float p_width); float get_width() const; diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index 147c9044b8..5da47966dd 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -89,6 +89,10 @@ void TextParagraph::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior"); + ClassDB::bind_method(D_METHOD("set_ellipsis_char", "char"), &TextParagraph::set_ellipsis_char); + ClassDB::bind_method(D_METHOD("get_ellipsis_char"), &TextParagraph::get_ellipsis_char); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "ellipsis_char"), "set_ellipsis_char", "get_ellipsis_char"); + ClassDB::bind_method(D_METHOD("set_width", "width"), &TextParagraph::set_width); ClassDB::bind_method(D_METHOD("get_width"), &TextParagraph::get_width); @@ -252,10 +256,12 @@ void TextParagraph::_shape_lines() { if (i < jst_to_line) { TS->shaped_text_fit_to_width(lines_rid[i], line_w, jst_flags); } else if (i == (visible_lines - 1)) { + TS->shaped_text_set_custom_ellipsis(lines_rid[visible_lines - 1], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], line_w, overrun_flags); } } } else if (lines_hidden) { + TS->shaped_text_set_custom_ellipsis(lines_rid[visible_lines - 1], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], (visible_lines - 1 <= dropcap_lines) ? (width - h_offset) : width, overrun_flags); } } else { @@ -281,9 +287,11 @@ void TextParagraph::_shape_lines() { if (i < jst_to_line && alignment == HORIZONTAL_ALIGNMENT_FILL) { TS->shaped_text_fit_to_width(lines_rid[i], line_w, jst_flags); overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE); + TS->shaped_text_set_custom_ellipsis(lines_rid[i], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[i], line_w, overrun_flags); TS->shaped_text_fit_to_width(lines_rid[i], line_w, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS); } else { + TS->shaped_text_set_custom_ellipsis(lines_rid[i], (el_char.length() > 0) ? el_char[0] : 0x2026); TS->shaped_text_overrun_trim_to_width(lines_rid[i], line_w, overrun_flags); } } @@ -501,6 +509,23 @@ TextServer::OverrunBehavior TextParagraph::get_text_overrun_behavior() const { return overrun_behavior; } +void TextParagraph::set_ellipsis_char(const String &p_char) { + String c = p_char; + if (c.length() > 1) { + WARN_PRINT("Ellipsis must be exactly one character long (" + itos(c.length()) + " characters given)."); + c = c.left(1); + } + if (el_char == c) { + return; + } + el_char = c; + lines_dirty = true; +} + +String TextParagraph::get_ellipsis_char() const { + return el_char; +} + void TextParagraph::set_width(float p_width) { _THREAD_SAFE_METHOD_ diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index 31fc95ac02..28c69967ac 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -56,6 +56,7 @@ private: BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND; BitField<TextServer::JustificationFlag> jst_flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_SKIP_LAST_LINE | TextServer::JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE; + String el_char = U"…"; TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING; HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT; @@ -112,6 +113,9 @@ public: void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior); TextServer::OverrunBehavior get_text_overrun_behavior() const; + void set_ellipsis_char(const String &p_char); + String get_ellipsis_char() const; + void set_width(float p_width); float get_width() const; diff --git a/scene/resources/tile_set.compat.inc b/scene/resources/tile_set.compat.inc new file mode 100644 index 0000000000..873ae3aa93 --- /dev/null +++ b/scene/resources/tile_set.compat.inc @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* tile_set.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +#include "tile_set.h" + +Ref<NavigationPolygon> TileData::_get_navigation_polygon_bind_compat_84660(int p_layer_id) const { + return get_navigation_polygon(p_layer_id, false, false, false); +} + +Ref<OccluderPolygon2D> TileData::_get_occluder_bind_compat_84660(int p_layer_id) const { + return get_occluder(p_layer_id, false, false, false); +} + +void TileData::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("get_navigation_polygon"), &TileData::_get_navigation_polygon_bind_compat_84660); + ClassDB::bind_compatibility_method(D_METHOD("get_occluder"), &TileData::_get_occluder_bind_compat_84660); +} + +#endif diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 422cd4fa2c..2de7cce5c7 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "tile_set.h" +#include "tile_set.compat.inc" #include "core/io/marshalls.h" #include "core/math/geometry_2d.h" @@ -5104,7 +5105,7 @@ void TileData::add_occlusion_layer(int p_to_pos) { p_to_pos = occluders.size(); } ERR_FAIL_INDEX(p_to_pos, occluders.size() + 1); - occluders.insert(p_to_pos, Ref<OccluderPolygon2D>()); + occluders.insert(p_to_pos, OcclusionLayerTileData()); } void TileData::move_occlusion_layer(int p_from_index, int p_to_pos) { @@ -5219,7 +5220,7 @@ void TileData::add_navigation_layer(int p_to_pos) { p_to_pos = navigation.size(); } ERR_FAIL_INDEX(p_to_pos, navigation.size() + 1); - navigation.insert(p_to_pos, Ref<NavigationPolygon>()); + navigation.insert(p_to_pos, NavigationLayerTileData()); } void TileData::move_navigation_layer(int p_from_index, int p_to_pos) { @@ -5365,13 +5366,35 @@ int TileData::get_y_sort_origin() const { void TileData::set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon) { ERR_FAIL_INDEX(p_layer_id, occluders.size()); - occluders.write[p_layer_id] = p_occluder_polygon; + occluders.write[p_layer_id].occluder = p_occluder_polygon; + occluders.write[p_layer_id].transformed_occluders.clear(); emit_signal(SNAME("changed")); } -Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id) const { +Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id, bool p_flip_h, bool p_flip_v, bool p_transpose) const { ERR_FAIL_INDEX_V(p_layer_id, occluders.size(), Ref<OccluderPolygon2D>()); - return occluders[p_layer_id]; + + const OcclusionLayerTileData &layer_tile_data = occluders[p_layer_id]; + + int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2; + if (key == 0) { + return layer_tile_data.occluder; + } + + if (layer_tile_data.occluder.is_null()) { + return Ref<OccluderPolygon2D>(); + } + + HashMap<int, Ref<OccluderPolygon2D>>::Iterator I = layer_tile_data.transformed_occluders.find(key); + if (!I) { + Ref<OccluderPolygon2D> transformed_polygon; + transformed_polygon.instantiate(); + transformed_polygon->set_polygon(get_transformed_vertices(layer_tile_data.occluder->get_polygon(), p_flip_h, p_flip_v, p_transpose)); + layer_tile_data.transformed_occluders[key] = transformed_polygon; + return transformed_polygon; + } else { + return I->value; + } } // Physics @@ -5431,22 +5454,25 @@ void TileData::set_collision_polygon_points(int p_layer_id, int p_polygon_index, ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); ERR_FAIL_COND_MSG(p_polygon.size() != 0 && p_polygon.size() < 3, "Invalid polygon. Needs either 0 or more than 3 points."); + TileData::PhysicsLayerTileData::PolygonShapeTileData &polygon_shape_tile_data = physics.write[p_layer_id].polygons.write[p_polygon_index]; + if (p_polygon.is_empty()) { - physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.clear(); + polygon_shape_tile_data.shapes.clear(); } else { // Decompose into convex shapes. Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(p_polygon); ERR_FAIL_COND_MSG(decomp.is_empty(), "Could not decompose the polygon into convex shapes."); - physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.resize(decomp.size()); + polygon_shape_tile_data.shapes.resize(decomp.size()); for (int i = 0; i < decomp.size(); i++) { Ref<ConvexPolygonShape2D> shape; shape.instantiate(); shape->set_points(decomp[i]); - physics.write[p_layer_id].polygons.write[p_polygon_index].shapes[i] = shape; + polygon_shape_tile_data.shapes[i] = shape; } } - physics.write[p_layer_id].polygons.write[p_polygon_index].polygon = p_polygon; + polygon_shape_tile_data.transformed_shapes.clear(); + polygon_shape_tile_data.polygon = p_polygon; emit_signal(SNAME("changed")); } @@ -5488,11 +5514,36 @@ int TileData::get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_i return physics[p_layer_id].polygons[p_polygon_index].shapes.size(); } -Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const { +Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index, bool p_flip_h, bool p_flip_v, bool p_transpose) const { ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Ref<ConvexPolygonShape2D>()); ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Ref<ConvexPolygonShape2D>()); ERR_FAIL_INDEX_V(shape_index, (int)physics[p_layer_id].polygons[p_polygon_index].shapes.size(), Ref<ConvexPolygonShape2D>()); - return physics[p_layer_id].polygons[p_polygon_index].shapes[shape_index]; + + const PhysicsLayerTileData &layer_tile_data = physics[p_layer_id]; + const PhysicsLayerTileData::PolygonShapeTileData &shapes_data = layer_tile_data.polygons[p_polygon_index]; + + int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2; + if (key == 0) { + return shapes_data.shapes[shape_index]; + } + if (shapes_data.shapes[shape_index].is_null()) { + return Ref<ConvexPolygonShape2D>(); + } + + HashMap<int, LocalVector<Ref<ConvexPolygonShape2D>>>::Iterator I = shapes_data.transformed_shapes.find(key); + if (!I) { + int size = shapes_data.shapes.size(); + shapes_data.transformed_shapes[key].resize(size); + for (int i = 0; i < size; i++) { + Ref<ConvexPolygonShape2D> transformed_polygon; + transformed_polygon.instantiate(); + transformed_polygon->set_points(get_transformed_vertices(shapes_data.shapes[shape_index]->get_points(), p_flip_h, p_flip_v, p_transpose)); + shapes_data.transformed_shapes[key][i] = transformed_polygon; + } + return shapes_data.transformed_shapes[key][shape_index]; + } else { + return I->value[shape_index]; + } } // Terrain @@ -5570,13 +5621,50 @@ TileSet::TerrainsPattern TileData::get_terrains_pattern() const { // Navigation void TileData::set_navigation_polygon(int p_layer_id, Ref<NavigationPolygon> p_navigation_polygon) { ERR_FAIL_INDEX(p_layer_id, navigation.size()); - navigation.write[p_layer_id] = p_navigation_polygon; + navigation.write[p_layer_id].navigation_polygon = p_navigation_polygon; + navigation.write[p_layer_id].transformed_navigation_polygon.clear(); emit_signal(SNAME("changed")); } -Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id) const { +Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id, bool p_flip_h, bool p_flip_v, bool p_transpose) const { ERR_FAIL_INDEX_V(p_layer_id, navigation.size(), Ref<NavigationPolygon>()); - return navigation[p_layer_id]; + + const NavigationLayerTileData &layer_tile_data = navigation[p_layer_id]; + + int key = int(p_flip_h) | int(p_flip_v) << 1 | int(p_transpose) << 2; + if (key == 0) { + return layer_tile_data.navigation_polygon; + } + + if (layer_tile_data.navigation_polygon.is_null()) { + return Ref<NavigationPolygon>(); + } + + HashMap<int, Ref<NavigationPolygon>>::Iterator I = layer_tile_data.transformed_navigation_polygon.find(key); + if (!I) { + Ref<NavigationPolygon> transformed_polygon; + transformed_polygon.instantiate(); + + PackedVector2Array new_points = get_transformed_vertices(layer_tile_data.navigation_polygon->get_vertices(), p_flip_h, p_flip_v, p_transpose); + transformed_polygon->set_vertices(new_points); + + for (int i = 0; i < layer_tile_data.navigation_polygon->get_outline_count(); i++) { + PackedVector2Array new_outline = get_transformed_vertices(layer_tile_data.navigation_polygon->get_outline(i), p_flip_h, p_flip_v, p_transpose); + transformed_polygon->add_outline(new_outline); + } + + PackedInt32Array indices; + indices.resize(new_points.size()); + int *w = indices.ptrw(); + for (int i = 0; i < new_points.size(); i++) { + w[i] = i; + } + transformed_polygon->add_polygon(indices); + layer_tile_data.transformed_navigation_polygon[key] = transformed_polygon; + return transformed_polygon; + } else { + return I->value; + } } // Misc @@ -5615,6 +5703,33 @@ Variant TileData::get_custom_data_by_layer_id(int p_layer_id) const { return custom_data[p_layer_id]; } +PackedVector2Array TileData::get_transformed_vertices(const PackedVector2Array &p_vertices, bool p_flip_h, bool p_flip_v, bool p_transpose) { + const Vector2 *r = p_vertices.ptr(); + int size = p_vertices.size(); + + PackedVector2Array new_points; + new_points.resize(size); + Vector2 *w = new_points.ptrw(); + + for (int i = 0; i < size; i++) { + Vector2 v; + if (p_transpose) { + v = Vector2(r[i].y, r[i].x); + } else { + v = r[i]; + } + + if (p_flip_h) { + v.x *= -1; + } + if (p_flip_v) { + v.y *= -1; + } + w[i] = v; + } + return new_points; +} + bool TileData::_set(const StringName &p_name, const Variant &p_value) { #ifndef DISABLE_DEPRECATED if (p_name == "texture_offset") { @@ -5845,7 +5960,7 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < occluders.size(); i++) { // occlusion_layer_%d/polygon property_info = PropertyInfo(Variant::OBJECT, vformat("occlusion_layer_%d/%s", i, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D", PROPERTY_USAGE_DEFAULT); - if (!occluders[i].is_valid()) { + if (occluders[i].occluder.is_null()) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); @@ -5901,7 +6016,7 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::NIL, GNAME("Navigation", ""), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); for (int i = 0; i < navigation.size(); i++) { property_info = PropertyInfo(Variant::OBJECT, vformat("navigation_layer_%d/%s", i, PNAME("polygon")), PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon", PROPERTY_USAGE_DEFAULT); - if (!navigation[i].is_valid()) { + if (navigation[i].navigation_polygon.is_null()) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); @@ -5942,7 +6057,7 @@ void TileData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_y_sort_origin"), &TileData::get_y_sort_origin); ClassDB::bind_method(D_METHOD("set_occluder", "layer_id", "occluder_polygon"), &TileData::set_occluder); - ClassDB::bind_method(D_METHOD("get_occluder", "layer_id"), &TileData::get_occluder); + ClassDB::bind_method(D_METHOD("get_occluder", "layer_id", "flip_h", "flip_v", "transpose"), &TileData::get_occluder, DEFVAL(false), DEFVAL(false), DEFVAL(false)); // Physics. ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "layer_id", "velocity"), &TileData::set_constant_linear_velocity); @@ -5970,7 +6085,7 @@ void TileData::_bind_methods() { // Navigation ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon); - ClassDB::bind_method(D_METHOD("get_navigation_polygon", "layer_id"), &TileData::get_navigation_polygon); + ClassDB::bind_method(D_METHOD("get_navigation_polygon", "layer_id", "flip_h", "flip_v", "transpose"), &TileData::get_navigation_polygon, DEFVAL(false), DEFVAL(false), DEFVAL(false)); // Misc. ClassDB::bind_method(D_METHOD("set_probability", "probability"), &TileData::set_probability); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 313c4df65d..a71982cd56 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -815,13 +815,18 @@ private: Color modulate = Color(1.0, 1.0, 1.0, 1.0); int z_index = 0; int y_sort_origin = 0; - Vector<Ref<OccluderPolygon2D>> occluders; + struct OcclusionLayerTileData { + Ref<OccluderPolygon2D> occluder; + mutable HashMap<int, Ref<OccluderPolygon2D>> transformed_occluders; + }; + Vector<OcclusionLayerTileData> occluders; // Physics struct PhysicsLayerTileData { struct PolygonShapeTileData { LocalVector<Vector2> polygon; LocalVector<Ref<ConvexPolygonShape2D>> shapes; + mutable HashMap<int, LocalVector<Ref<ConvexPolygonShape2D>>> transformed_shapes; bool one_way = false; float one_way_margin = 1.0; }; @@ -839,7 +844,11 @@ private: int terrain_peering_bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; // Navigation - Vector<Ref<NavigationPolygon>> navigation; + struct NavigationLayerTileData { + Ref<NavigationPolygon> navigation_polygon; + mutable HashMap<int, Ref<NavigationPolygon>> transformed_navigation_polygon; + }; + Vector<NavigationLayerTileData> navigation; // Misc double probability = 1.0; @@ -853,6 +862,13 @@ protected: void _get_property_list(List<PropertyInfo> *p_list) const; static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + Ref<NavigationPolygon> _get_navigation_polygon_bind_compat_84660(int p_layer_id) const; + Ref<OccluderPolygon2D> _get_occluder_bind_compat_84660(int p_layer_id) const; + + static void _bind_compatibility_methods(); +#endif + public: // Not exposed. void set_tile_set(const TileSet *p_tile_set); @@ -901,7 +917,7 @@ public: int get_y_sort_origin() const; void set_occluder(int p_layer_id, Ref<OccluderPolygon2D> p_occluder_polygon); - Ref<OccluderPolygon2D> get_occluder(int p_layer_id) const; + Ref<OccluderPolygon2D> get_occluder(int p_layer_id, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const; // Physics void set_constant_linear_velocity(int p_layer_id, const Vector2 &p_velocity); @@ -919,7 +935,7 @@ public: void set_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index, float p_one_way_margin); float get_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index) const; int get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_index) const; - Ref<ConvexPolygonShape2D> get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const; + Ref<ConvexPolygonShape2D> get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const; // Terrain void set_terrain_set(int p_terrain_id); @@ -934,7 +950,7 @@ public: // Navigation void set_navigation_polygon(int p_layer_id, Ref<NavigationPolygon> p_navigation_polygon); - Ref<NavigationPolygon> get_navigation_polygon(int p_layer_id) const; + Ref<NavigationPolygon> get_navigation_polygon(int p_layer_id, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false) const; // Misc void set_probability(float p_probability); @@ -945,6 +961,9 @@ public: Variant get_custom_data(String p_layer_name) const; void set_custom_data_by_layer_id(int p_layer_id, Variant p_value); Variant get_custom_data_by_layer_id(int p_layer_id) const; + + // Polygons. + static PackedVector2Array get_transformed_vertices(const PackedVector2Array &p_vertices, bool p_flip_h, bool p_flip_v, bool p_transpose); }; VARIANT_ENUM_CAST(TileSet::CellNeighbor); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 423ef3867f..9fb6b364a7 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -962,12 +962,13 @@ void VisualShader::remove_node(Type p_type, int p_id) { for (List<Connection>::Element *E = g->connections.front(); E;) { List<Connection>::Element *N = E->next(); - if (E->get().from_node == p_id || E->get().to_node == p_id) { - if (E->get().from_node == p_id) { - g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id); - g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false); - } else if (E->get().to_node == p_id) { - g->nodes[E->get().from_node].next_connected_nodes.erase(p_id); + const VisualShader::Connection &connection = E->get(); + if (connection.from_node == p_id || connection.to_node == p_id) { + if (connection.from_node == p_id) { + g->nodes[connection.to_node].prev_connected_nodes.erase(p_id); + g->nodes[connection.to_node].node->set_input_port_connected(connection.to_port, false); + } else if (connection.to_node == p_id) { + g->nodes[connection.from_node].next_connected_nodes.erase(p_id); } g->connections.erase(E); } |
