Fix transform of TileMap nodes and tilemap selection

This commit is contained in:
Gilles Roudière 2021-09-14 12:02:13 +02:00
parent bbdfc547ca
commit 73cc6f94bf
6 changed files with 101 additions and 89 deletions

View file

@ -327,10 +327,12 @@ void TileAtlasView::_draw_base_tiles_shape_grid() {
Vector2i tile_id = tile_set_atlas_source->get_tile_id(i); Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_effective_texture_offset(tile_id, 0); Vector2 in_tile_base_offset = tile_set_atlas_source->get_tile_effective_texture_offset(tile_id, 0);
Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id); Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(tile_id);
Vector2 origin = texture_region.position + (texture_region.size - tile_shape_size) / 2 + in_tile_base_offset;
// Draw only if the tile shape fits in the texture region // Draw only if the tile shape fits in the texture region
tile_set->draw_tile_shape(base_tiles_shape_grid, Rect2(origin, tile_shape_size), grid_color); Transform2D tile_xform;
tile_xform.set_origin(texture_region.position + texture_region.size / 2 + in_tile_base_offset);
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(base_tiles_shape_grid, tile_xform, grid_color);
} }
} }

View file

@ -124,7 +124,9 @@ void GenericTilePolygonEditor::_base_control_draw() {
base_control->draw_set_transform_matrix(xform); base_control->draw_set_transform_matrix(xform);
// Draw the tile shape filled. // Draw the tile shape filled.
tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), Color(1.0, 1.0, 1.0, 0.3), true); Transform2D tile_xform;
tile_xform.set_scale(tile_size);
tile_set->draw_tile_shape(base_control, tile_xform, Color(1.0, 1.0, 1.0, 0.3), true);
// Draw the background. // Draw the background.
if (background_texture.is_valid()) { if (background_texture.is_valid()) {
@ -213,7 +215,7 @@ void GenericTilePolygonEditor::_base_control_draw() {
// Draw the tile shape line. // Draw the tile shape line.
base_control->draw_set_transform_matrix(xform); base_control->draw_set_transform_matrix(xform);
tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), grid_color, false); tile_set->draw_tile_shape(base_control, tile_xform, grid_color, false);
base_control->draw_set_transform_matrix(Transform2D()); base_control->draw_set_transform_matrix(Transform2D());
} }
@ -1072,14 +1074,15 @@ void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Tran
ERR_FAIL_COND(!tile_data); ERR_FAIL_COND(!tile_data);
Vector2i tile_set_tile_size = tile_set->get_tile_size(); Vector2i tile_set_tile_size = tile_set->get_tile_size();
Rect2i rect = Rect2i(-tile_set_tile_size / 2, tile_set_tile_size);
Color color = Color(1.0, 0.0, 0.0); Color color = Color(1.0, 0.0, 0.0);
if (p_selected) { if (p_selected) {
Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
color = selection_color; color = selection_color;
} }
tile_set->draw_tile_shape(p_canvas_item, p_transform.xform(rect), color); Transform2D tile_xform;
tile_xform.set_scale(tile_set_tile_size);
tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, color);
} }
void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
@ -1514,9 +1517,10 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
} }
} else { } else {
// Draw hovered tile. // Draw hovered tile.
Vector2i tile_size = tile_set->get_tile_size(); Transform2D tile_xform;
Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size)); tile_xform.set_origin(position);
tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true); tile_xform.set_scale(tile_set->get_tile_size());
tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} }
} }
} }
@ -1686,9 +1690,10 @@ void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_til
} }
} else { } else {
// Draw hovered tile. // Draw hovered tile.
Vector2i tile_size = tile_set->get_tile_size(); Transform2D tile_xform;
Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size)); tile_xform.set_origin(position);
tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true); tile_xform.set_scale(tile_set->get_tile_size());
tile_set->draw_tile_shape(p_canvas_item, p_transform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} }
} }
} }

View file

@ -636,8 +636,10 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
for (int y = rect.position.y; y < rect.get_end().y; y++) { for (int y = rect.position.y; y < rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y); Vector2i coords = Vector2i(x, y);
if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) { if (tile_map->get_cell_source_id(tile_map_layer, coords) != TileSet::INVALID_SOURCE) {
Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - tile_shape_size / 2, tile_shape_size)); Transform2D tile_xform;
tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0), false); tile_xform.set_origin(tile_map->map_to_world(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
} }
} }
} }
@ -734,10 +736,12 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f); float bottom_opacity = CLAMP(Math::inverse_lerp((float)drawn_grid_rect.size.y, (float)(drawn_grid_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size)); Transform2D tile_xform;
tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color; Color color = grid_color;
color.a = color.a * opacity; color.a = color.a * opacity;
tile_set->draw_tile_shape(p_overlay, cell_region, color, false); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, false);
} }
} }
} }
@ -745,11 +749,11 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the preview. // Draw the preview.
for (Map<Vector2i, TileMapCell>::Element *E = preview.front(); E; E = E->next()) { for (Map<Vector2i, TileMapCell>::Element *E = preview.front(); E; E = E->next()) {
Vector2i size = tile_set->get_tile_size(); Transform2D tile_xform;
Vector2 position = tile_map->map_to_world(E->key()) - size / 2; tile_xform.set_origin(tile_map->map_to_world(E->key()));
Rect2 cell_region = xform.xform(Rect2(position, size)); tile_xform.set_scale(tile_set->get_tile_size());
if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) { if (!erase_button->is_pressed() && random_tile_checkbox->is_pressed()) {
tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0, 0.5), true); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} else { } else {
if (tile_set->has_source(E->get().source_id)) { if (tile_set->has_source(E->get().source_id)) {
TileSetSource *source = *tile_set->get_source(E->get().source_id); TileSetSource *source = *tile_set->get_source(E->get().source_id);
@ -791,10 +795,10 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the tile. // Draw the tile.
p_overlay->draw_texture_rect_region(atlas_source->get_texture(), dest_rect, source_rect, modulate * Color(1.0, 1.0, 1.0, 0.5), transpose, tile_set->is_uv_clipping()); p_overlay->draw_texture_rect_region(atlas_source->get_texture(), dest_rect, source_rect, modulate * Color(1.0, 1.0, 1.0, 0.5), transpose, tile_set->is_uv_clipping());
} else { } else {
tile_set->draw_tile_shape(p_overlay, cell_region, Color(1.0, 1.0, 1.0, 0.5), true); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0, 0.5), true);
} }
} else { } else {
tile_set->draw_tile_shape(p_overlay, cell_region, Color(0.0, 0.0, 0.0, 0.5), true); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(0.0, 0.0, 0.0, 0.5), true);
} }
} }
} }
@ -3689,8 +3693,10 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
0.8); 0.8);
// Draw the scaled tile. // Draw the scaled tile.
Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(coords) - Vector2(tile_shape_size) / 2, Vector2(tile_shape_size))); Transform2D tile_xform;
tile_set->draw_tile_shape(p_overlay, cell_region, color, true, warning_pattern_texture); tile_xform.set_origin(tile_map->map_to_world(coords));
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture);
} }
// Draw the warning icon. // Draw the warning icon.
@ -3746,10 +3752,12 @@ void TileMapEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f); float bottom_opacity = CLAMP(Math::inverse_lerp((float)displayed_rect.size.y, (float)(displayed_rect.size.y - fading), (float)pos_in_rect.y), 0.0f, 1.0f);
float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f); float opacity = CLAMP(MIN(left_opacity, MIN(right_opacity, MIN(top_opacity, bottom_opacity))) + 0.1, 0.0f, 1.0f);
Rect2 cell_region = xform.xform(Rect2(tile_map->map_to_world(Vector2(x, y)) - tile_shape_size / 2, tile_shape_size)); Transform2D tile_xform;
tile_xform.set_origin(tile_map->map_to_world(Vector2(x, y)));
tile_xform.set_scale(tile_shape_size);
Color color = grid_color; Color color = grid_color;
color.a = color.a * opacity; color.a = color.a * opacity;
tile_set->draw_tile_shape(p_overlay, cell_region, color, false); tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, false);
} }
} }
} }

View file

@ -2857,50 +2857,57 @@ void TileMap::draw_cells_outline(Control *p_control, Set<Vector2i> p_cells, Colo
// Create a set. // Create a set.
Vector2i tile_size = tile_set->get_tile_size(); Vector2i tile_size = tile_set->get_tile_size();
Vector<Vector2> uvs; Vector<Vector2> polygon = tile_set->get_tile_shape_polygon();
TileSet::TileShape shape = tile_set->get_tile_shape();
if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) {
uvs.append(Vector2(1.0, 0.0));
uvs.append(Vector2(1.0, 1.0));
uvs.append(Vector2(0.0, 1.0));
uvs.append(Vector2(0.0, 0.0));
} else {
float overlap = 0.0;
switch (tile_set->get_tile_shape()) {
case TileSet::TILE_SHAPE_ISOMETRIC:
overlap = 0.5;
break;
case TileSet::TILE_SHAPE_HEXAGON:
overlap = 0.25;
break;
case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE:
overlap = 0.0;
break;
default:
break;
}
uvs.append(Vector2(1.0, overlap));
uvs.append(Vector2(1.0, 1.0 - overlap));
uvs.append(Vector2(0.5, 1.0));
uvs.append(Vector2(0.0, 1.0 - overlap));
uvs.append(Vector2(0.0, overlap));
uvs.append(Vector2(0.5, 0.0));
if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
for (int i = 0; i < uvs.size(); i++) {
uvs.write[i] = Vector2(uvs[i].y, uvs[i].x);
}
}
}
for (Set<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) { for (Set<Vector2i>::Element *E = p_cells.front(); E; E = E->next()) {
Vector2 top_left = map_to_world(E->get()) - tile_size / 2; Vector2 center = map_to_world(E->get());
TypedArray<Vector2i> surrounding_tiles = get_surrounding_tiles(E->get());
for (int i = 0; i < surrounding_tiles.size(); i++) { #define DRAW_SIDE_IF_NEEDED(side, polygon_index_from, polygon_index_to) \
if (!p_cells.has(surrounding_tiles[i])) { if (!p_cells.has(get_neighbor_cell(E->get(), side))) { \
p_control->draw_line(p_transform.xform(top_left + uvs[i] * tile_size), p_transform.xform(top_left + uvs[(i + 1) % uvs.size()] * tile_size), p_color); Vector2 from = p_transform.xform(center + polygon[polygon_index_from] * tile_size); \
Vector2 to = p_transform.xform(center + polygon[polygon_index_to] * tile_size); \
p_control->draw_line(from, to, p_color); \
}
if (shape == TileSet::TILE_SHAPE_SQUARE) {
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 1, 2);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 2, 3);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 3, 0);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 0, 1);
} else {
if (tile_set->get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) {
if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0);
} else {
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 2, 3);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_LEFT_SIDE, 1, 2);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 5, 0);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, 4, 5);
}
} else {
if (shape == TileSet::TILE_SHAPE_ISOMETRIC) {
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3);
} else {
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, 3, 4);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, 4, 5);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, 5, 0);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, 0, 1);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_SIDE, 1, 2);
DRAW_SIDE_IF_NEEDED(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, 2, 3);
}
} }
} }
} }
#undef DRAW_SIDE_IF_NEEDED
} }
TypedArray<String> TileMap::get_configuration_warnings() const { TypedArray<String> TileMap::get_configuration_warnings() const {

View file

@ -982,10 +982,10 @@ void TileSet::clear_tile_proxies() {
Vector<Vector2> TileSet::get_tile_shape_polygon() { Vector<Vector2> TileSet::get_tile_shape_polygon() {
Vector<Vector2> points; Vector<Vector2> points;
if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { if (tile_shape == TileSet::TILE_SHAPE_SQUARE) {
points.append(Vector2(0.0, 0.0)); points.append(Vector2(-0.5, -0.5));
points.append(Vector2(1.0, 0.0)); points.append(Vector2(0.5, -0.5));
points.append(Vector2(1.0, 1.0)); points.append(Vector2(0.5, 0.5));
points.append(Vector2(0.0, 1.0)); points.append(Vector2(-0.5, 0.5));
} else { } else {
float overlap = 0.0; float overlap = 0.0;
switch (tile_shape) { switch (tile_shape) {
@ -1002,31 +1002,24 @@ Vector<Vector2> TileSet::get_tile_shape_polygon() {
break; break;
} }
points.append(Vector2(0.5, 0.0)); points.append(Vector2(0.0, -0.5));
points.append(Vector2(0.0, overlap)); points.append(Vector2(-0.5, overlap - 0.5));
points.append(Vector2(0.0, 1.0 - overlap)); points.append(Vector2(-0.5, 0.5 - overlap));
points.append(Vector2(0.5, 1.0)); points.append(Vector2(0.0, 0.5));
points.append(Vector2(1.0, 1.0 - overlap)); points.append(Vector2(0.5, 0.5 - overlap));
points.append(Vector2(1.0, overlap)); points.append(Vector2(0.5, overlap - 0.5));
points.append(Vector2(0.5, 0.0));
if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) {
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < points.size(); i++) {
points.write[i] = Vector2(points[i].y, points[i].x); points.write[i] = Vector2(points[i].y, points[i].x);
} }
} }
} }
for (int i = 0; i < points.size(); i++) {
points.write[i] = points[i] * tile_size - tile_size / 2;
}
return points; return points;
} }
void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled, Ref<Texture2D> p_texture) {
if (tile_meshes_dirty) { if (tile_meshes_dirty) {
Vector<Vector2> uvs = get_tile_shape_polygon(); Vector<Vector2> uvs = get_tile_shape_polygon();
for (int i = 0; i < uvs.size(); i++) {
uvs.write[i] = (uvs[i] + tile_size / 2) / tile_size;
}
Vector<Color> colors; Vector<Color> colors;
colors.resize(uvs.size()); colors.resize(uvs.size());
@ -1056,13 +1049,10 @@ void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p
tile_meshes_dirty = false; tile_meshes_dirty = false;
} }
Transform2D xform;
xform.scale(p_region.size);
xform.set_origin(p_region.get_position());
if (p_filled) { if (p_filled) {
p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, xform, p_color); p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, p_transform, p_color);
} else { } else {
p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), xform, p_color); p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), p_transform, p_color);
} }
} }

View file

@ -385,7 +385,7 @@ public:
// Helpers // Helpers
Vector<Vector2> get_tile_shape_polygon(); Vector<Vector2> get_tile_shape_polygon();
void draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()); void draw_tile_shape(CanvasItem *p_canvas_item, Transform2D p_transform, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>());
Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit); Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit);
void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data); void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data);