Skip to content

Commit

Permalink
Move tile transforms handling cache to TileData
Browse files Browse the repository at this point in the history
  • Loading branch information
groud committed Dec 13, 2023
1 parent aa5b6ed commit 18fe0bd
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 130 deletions.
8 changes: 8 additions & 0 deletions doc/classes/TileData.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,23 @@
<method name="get_navigation_polygon" qualifiers="const">
<return type="NavigationPolygon" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="flip_h" type="bool" default="false" />
<param index="2" name="flip_v" type="bool" default="false" />
<param index="3" name="transpose" type="bool" default="false" />
<description>
Returns the navigation polygon of the tile for the TileSet navigation layer with index [param layer_id].
[param flip_h], [param flip_v], and [param transpose] allow transforming the returned polygon.
</description>
</method>
<method name="get_occluder" qualifiers="const">
<return type="OccluderPolygon2D" />
<param index="0" name="layer_id" type="int" />
<param index="1" name="flip_h" type="bool" default="false" />
<param index="2" name="flip_v" type="bool" default="false" />
<param index="3" name="transpose" type="bool" default="false" />
<description>
Returns the occluder polygon of the tile for the TileSet occlusion layer with index [param layer_id].
[param flip_h], [param flip_v], and [param transpose] allow transforming the returned polygon.
</description>
</method>
<method name="get_terrain_peering_bit" qualifiers="const">
Expand Down
2 changes: 1 addition & 1 deletion editor/plugins/tiles/tile_data_editors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1421,8 +1421,8 @@ void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Tra

Variant TileDataOcclusionShapeEditor::_get_painted_value() {
Ref<OccluderPolygon2D> occluder_polygon;
occluder_polygon.instantiate();
if (polygon_editor->get_polygon_count() >= 1) {
occluder_polygon.instantiate();
occluder_polygon->set_polygon(polygon_editor->get_polygon(0));
}
return occluder_polygon;
Expand Down
7 changes: 7 additions & 0 deletions misc/extension_api_validation/4.2-stable.expected
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ should instead be used to justify these changes and describe how users should wo
Add new entries at the end of the file.

## Changes between 4.2-stable and 4.3-stable

GH-84660
--------
Validate extension JSON: Error: Field 'classes/TileData/methods/get_navigation_polygon/arguments': size changed value in new API, from 1 to 4.
Validate extension JSON: Error: Field 'classes/TileData/methods/get_occluder/arguments': size changed value in new API, from 1 to 4.

Added optional argument to get_navigation_polygon and get_occluder to specify a polygon transform.
14 changes: 12 additions & 2 deletions modules/navigation/nav_mesh_generator_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,13 +591,19 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
continue;
}

// Transform flags.
const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false);
bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);

Transform2D tile_transform;
tile_transform.set_origin(tilemap->map_to_local(cell));

const Transform2D tile_transform_offset = tilemap_xform * tile_transform;

if (navigation_layers_count > 0) {
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer);
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose);
if (navigation_polygon.is_valid()) {
for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
Expand All @@ -622,11 +628,15 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo

if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
const Vector<Vector2> &collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
if (collision_polygon_points.size() == 0) {
continue;
}

if (flip_h || flip_v || transpose) {
collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
}

Vector<Vector2> obstruction_outline;
obstruction_outline.resize(collision_polygon_points.size());

Expand Down
126 changes: 27 additions & 99 deletions scene/2d/tile_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
Expand All @@ -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 {
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 &region = r_cell_data.navigation_regions[i];
Expand All @@ -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 &region = r_cell_data.navigation_regions[navigation_layer_index];

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -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();

Expand Down
5 changes: 0 additions & 5 deletions scene/2d/tile_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,6 @@ class TileMap : public Node2D {

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;
Expand Down Expand Up @@ -619,7 +615,6 @@ class TileMap : public Node2D {
// 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);
Expand Down
48 changes: 48 additions & 0 deletions scene/resources/tile_set.compat.inc
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit 18fe0bd

Please sign in to comment.