From 5a275eae38ace4aa6de2faf66fd73748e8891b5e Mon Sep 17 00:00:00 2001 From: kleonc <9283098+kleonc@users.noreply.github.com> Date: Thu, 8 Jan 2026 15:28:17 +0100 Subject: [PATCH] Preserve winding order for transformed tiles' navigation polygons --- .../2d/nav_mesh_generator_2d.cpp | 8 +++--- scene/2d/tile_map_layer.cpp | 22 ++-------------- scene/resources/2d/tile_set.cpp | 25 ++++++++++++++----- scene/resources/2d/tile_set.h | 2 +- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp b/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp index 1d7ee7fb9e9..24d496eeb9c 100644 --- a/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp +++ b/modules/navigation_2d/2d/nav_mesh_generator_2d.cpp @@ -444,10 +444,10 @@ void NavMeshGenerator2D::generator_bake_from_source_geometry_data(Ref 0.0) { Vector2 baking_rect_offset = p_navigation_mesh->get_baking_rect_offset(); - const int rect_begin_x = baking_rect.position[0] + baking_rect_offset.x + border_size; - const int rect_begin_y = baking_rect.position[1] + baking_rect_offset.y + border_size; - const int rect_end_x = baking_rect.position[0] + baking_rect.size[0] + baking_rect_offset.x - border_size; - const int rect_end_y = baking_rect.position[1] + baking_rect.size[1] + baking_rect_offset.y - border_size; + const double rect_begin_x = baking_rect.position[0] + baking_rect_offset.x + border_size; + const double rect_begin_y = baking_rect.position[1] + baking_rect_offset.y + border_size; + const double rect_end_x = baking_rect.position[0] + baking_rect.size[0] + baking_rect_offset.x - border_size; + const double rect_end_y = baking_rect.position[1] + baking_rect.size[1] + baking_rect_offset.y - border_size; RectD clipper_rect = RectD(rect_begin_x, rect_begin_y, rect_end_x, rect_end_y); diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index b409713942f..ba6fcb170f9 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -3565,16 +3565,7 @@ void TileMapLayer::navmesh_parse_source_geometry(const Ref &p continue; } - Vector traversable_outline; - traversable_outline.resize(navigation_polygon_outline.size()); - - const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr(); - Vector2 *traversable_outline_ptrw = traversable_outline.ptrw(); - - for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) { - traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]); - } - + Vector traversable_outline = tile_transform_offset.xform(navigation_polygon_outline); p_source_geometry_data->_add_traversable_outline(traversable_outline); } } @@ -3598,16 +3589,7 @@ void TileMapLayer::navmesh_parse_source_geometry(const Ref &p collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose); } - Vector obstruction_outline; - obstruction_outline.resize(collision_polygon_points.size()); - - const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr(); - Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw(); - - for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) { - obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]); - } - + Vector obstruction_outline = tile_transform_offset.xform(collision_polygon_points); p_source_geometry_data->_add_obstruction_outline(obstruction_outline); } } diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp index ac5ae77bea6..b14ea7ce3d0 100644 --- a/scene/resources/2d/tile_set.cpp +++ b/scene/resources/2d/tile_set.cpp @@ -6594,7 +6594,19 @@ Ref TileData::get_navigation_polygon(int p_layer_id, bool p_f Ref 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); + // Winding order: + // - Preserve for outlines. + // - If there are no polygons provided, preserve for vertices. + // - If there are polygons provided, preserve for polygons, don't preserve for vertices (so the vertex order is unchanged and polygons don't need reindexing). + + Vector> new_polygons = layer_tile_data.navigation_polygon->get_polygons(); + if ((p_flip_h != p_flip_v) != p_transpose) { + for (Vector &polygon : new_polygons) { + polygon.reverse(); + } + } + + PackedVector2Array new_points = get_transformed_vertices(layer_tile_data.navigation_polygon->get_vertices(), p_flip_h, p_flip_v, p_transpose, new_polygons.is_empty()); const Vector> outlines = layer_tile_data.navigation_polygon->get_outlines(); int outline_count = outlines.size(); @@ -6603,10 +6615,10 @@ Ref TileData::get_navigation_polygon(int p_layer_id, bool p_f new_outlines.resize(outline_count); for (int i = 0; i < outline_count; i++) { - new_outlines.write[i] = get_transformed_vertices(outlines[i], p_flip_h, p_flip_v, p_transpose); + new_outlines.write[i] = get_transformed_vertices(outlines[i], p_flip_h, p_flip_v, p_transpose, true); } - transformed_polygon->set_data(new_points, layer_tile_data.navigation_polygon->get_polygons(), new_outlines); + transformed_polygon->set_data(new_points, new_polygons, new_outlines); layer_tile_data.transformed_navigation_polygon[key] = transformed_polygon; return transformed_polygon; @@ -6657,14 +6669,15 @@ 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) { +PackedVector2Array TileData::get_transformed_vertices(const PackedVector2Array &p_vertices, bool p_flip_h, bool p_flip_v, bool p_transpose, bool p_preserve_winding_order) { const Vector2 *r = p_vertices.ptr(); int size = p_vertices.size(); PackedVector2Array new_points; - new_points.resize(size); + new_points.resize_uninitialized(size); Vector2 *w = new_points.ptrw(); + bool reverse_vertex_order = p_preserve_winding_order && ((p_flip_h != p_flip_v) != p_transpose); for (int i = 0; i < size; i++) { Vector2 v; if (p_transpose) { @@ -6679,7 +6692,7 @@ PackedVector2Array TileData::get_transformed_vertices(const PackedVector2Array & if (p_flip_v) { v.y *= -1; } - w[i] = v; + w[reverse_vertex_order ? (size - 1 - i) : i] = v; } return new_points; } diff --git a/scene/resources/2d/tile_set.h b/scene/resources/2d/tile_set.h index ce46c546822..61f8ac47d2b 100644 --- a/scene/resources/2d/tile_set.h +++ b/scene/resources/2d/tile_set.h @@ -1029,7 +1029,7 @@ public: 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); + static PackedVector2Array get_transformed_vertices(const PackedVector2Array &p_vertices, bool p_flip_h, bool p_flip_v, bool p_transpose, bool p_preserve_winding_order = false); }; VARIANT_ENUM_CAST(TileSet::CellNeighbor);