Add per-tile flipping and transposing

This commit is contained in:
kobewi
2023-07-31 21:35:17 +02:00
parent fc99492d30
commit a9f3154da3
7 changed files with 330 additions and 48 deletions
+90 -4
View File
@@ -548,7 +548,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
RID occluder_id = rs->canvas_light_occluder_create();
rs->canvas_light_occluder_set_enabled(occluder_id, node_visible);
rs->canvas_light_occluder_set_transform(occluder_id, tile_map_node->get_global_transform() * xform);
rs->canvas_light_occluder_set_polygon(occluder_id, tile_data->get_occluder(i)->get_rid());
rs->canvas_light_occluder_set_polygon(occluder_id, tile_map_node->get_transformed_polygon(Ref<Resource>(tile_data->get_occluder(i)), r_cell_data.cell.alternative_tile)->get_rid());
rs->canvas_light_occluder_attach_to_canvas(occluder_id, tile_map_node->get_canvas());
rs->canvas_light_occluder_set_light_mask(occluder_id, tile_set->get_occlusion_layer_light_mask(i));
r_cell_data.occluders.push_back(occluder_id);
@@ -783,6 +783,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
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);
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);
@@ -985,6 +986,7 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
for (unsigned int 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);
RID &region = r_cell_data.navigation_regions[navigation_layer_index];
@@ -1074,6 +1076,7 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V
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);
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;
@@ -3012,6 +3015,7 @@ void TileMap::_internal_update() {
}
// Update dirty quadrants on layers.
polygon_cache.clear();
for (Ref<TileMapLayer> &layer : layers) {
layer->internal_update();
}
@@ -3100,18 +3104,18 @@ void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<
dest_rect.size.x += FP_ADJUST;
dest_rect.size.y += FP_ADJUST;
bool transpose = tile_data->get_transpose();
bool transpose = tile_data->get_transpose() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
if (transpose) {
dest_rect.position = (p_position - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
} else {
dest_rect.position = (p_position - dest_rect.size / 2 - tile_offset);
}
if (tile_data->get_flip_h()) {
if (tile_data->get_flip_h() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) {
dest_rect.size.x = -dest_rect.size.x;
}
if (tile_data->get_flip_v()) {
if (tile_data->get_flip_v() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V)) {
dest_rect.size.y = -dest_rect.size.y;
}
@@ -3482,6 +3486,37 @@ 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") {
@@ -4384,6 +4419,57 @@ 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();
+5
View File
@@ -455,6 +455,10 @@ private:
void _tile_set_changed();
// 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;
@@ -595,6 +599,7 @@ 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);