Merge pull request #54396 from groud/implement_terrain_other_brushes

This commit is contained in:
Rémi Verschelde 2021-11-01 22:27:06 +01:00 committed by GitHub
commit 529968df30
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 741 additions and 151 deletions

File diff suppressed because it is too large Load diff

View file

@ -75,14 +75,15 @@ private:
Button *line_tool_button;
Button *rect_tool_button;
Button *bucket_tool_button;
Button *picker_button;
HBoxContainer *tools_settings;
VSeparator *tools_settings_vsep;
Button *picker_button;
Button *erase_button;
CheckBox *bucket_continuous_checkbox;
VSeparator *tools_settings_vsep_2;
CheckBox *bucket_contiguous_checkbox;
CheckBox *random_tile_checkbox;
float scattering = 0.0;
Label *scatter_label;
@ -108,17 +109,16 @@ private:
DRAG_TYPE_CLIPBOARD_PASTE,
};
DragType drag_type = DRAG_TYPE_NONE;
bool drag_erasing = false;
Vector2 drag_start_mouse_pos;
Vector2 drag_last_mouse_pos;
Map<Vector2i, TileMapCell> drag_modified;
bool rmb_erasing = false;
TileMapCell _pick_random_tile(Ref<TileMapPattern> p_pattern);
Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos);
Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell);
Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous);
Map<Vector2i, TileMapCell> _draw_line(Vector2 p_start_drag_mouse_pos, Vector2 p_from_mouse_pos, Vector2 p_to_mouse_pos, bool p_erase);
Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase);
void _stop_dragging();
bool _is_erasing() const;
///// Selection system. /////
Set<Vector2i> tile_map_selection;
@ -220,32 +220,53 @@ private:
Ref<ButtonGroup> tool_buttons_group;
Button *paint_tool_button;
Button *line_tool_button;
Button *rect_tool_button;
Button *bucket_tool_button;
HBoxContainer *tools_settings;
VSeparator *tools_settings_vsep;
Button *picker_button;
Button *erase_button;
VSeparator *tools_settings_vsep_2;
CheckBox *bucket_contiguous_checkbox;
void _update_toolbar();
// Main vbox.
VBoxContainer *main_vbox_container;
// TileMap editing.
bool has_mouse = false;
void _mouse_exited_viewport();
enum DragType {
DRAG_TYPE_NONE = 0,
DRAG_TYPE_PAINT,
DRAG_TYPE_LINE,
DRAG_TYPE_RECT,
DRAG_TYPE_BUCKET,
DRAG_TYPE_PICK,
};
DragType drag_type = DRAG_TYPE_NONE;
bool drag_erasing = false;
Vector2 drag_start_mouse_pos;
Vector2 drag_last_mouse_pos;
Map<Vector2i, TileMapCell> drag_modified;
// Painting
Map<Vector2i, TileMapCell> _draw_terrains(const Map<Vector2i, TileSet::TerrainsPattern> &p_to_paint, int p_terrain_set) const;
Map<Vector2i, TileMapCell> _draw_line(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
Map<Vector2i, TileMapCell> _draw_rect(Vector2i p_start_cell, Vector2i p_end_cell, bool p_erase);
Set<Vector2i> _get_cells_for_bucket_fill(Vector2i p_coords, bool p_contiguous);
Map<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase);
void _stop_dragging();
int selected_terrain_set = -1;
TileSet::TerrainsPattern selected_terrains_pattern;
void _update_selection();
// Bottom panel.
Tree *terrains_tree;
ItemList *terrains_tile_list;
@ -265,7 +286,7 @@ private:
public:
virtual Vector<TabData> get_tabs() const override;
virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override;
//virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override;
TileMapEditorTerrainsPlugin();
~TileMapEditorTerrainsPlugin();

View file

@ -2146,18 +2146,16 @@ Set<TileSet::TerrainsPattern> TileMap::_get_valid_terrains_patterns_for_constrai
Set<TileSet::TerrainsPattern> compatible_terrain_tile_patterns;
for (TileSet::TerrainsPattern &terrain_pattern : tile_set->get_terrains_pattern_set(p_terrain_set)) {
int valid = true;
int in_pattern_count = 0;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, bit)) {
// Check if the bit is compatible with the constraints.
TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern[in_pattern_count]);
TerrainConstraint terrain_bit_constraint = TerrainConstraint(this, p_position, bit, terrain_pattern.get_terrain(bit));
Set<TerrainConstraint>::Element *in_set_constraint_element = p_constraints.find(terrain_bit_constraint);
if (in_set_constraint_element && in_set_constraint_element->get().get_terrain() != terrain_bit_constraint.get_terrain()) {
valid = false;
break;
}
in_pattern_count++;
}
}
@ -2249,13 +2247,11 @@ Set<TileMap::TerrainConstraint> TileMap::get_terrain_constraints_from_added_tile
// Compute the constraints needed from the surrounding tiles.
Set<TerrainConstraint> output;
int in_pattern_count = 0;
for (uint32_t i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) {
TerrainConstraint c = TerrainConstraint(this, p_position, side, p_terrains_pattern[in_pattern_count]);
TerrainConstraint c = TerrainConstraint(this, p_position, side, p_terrains_pattern.get_terrain(side));
output.insert(c);
in_pattern_count++;
}
}
@ -2312,8 +2308,11 @@ Map<Vector2i, TileSet::TerrainsPattern> TileMap::terrain_wave_function_collapse(
int pattern_index = 0;
for (const TileSet::TerrainsPattern &pattern : valid_tiles) {
Set<int> terrains;
for (int i = 0; i < pattern.size(); i++) {
terrains.insert(pattern[i]);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
TileSet::CellNeighbor side = TileSet::CellNeighbor(i);
if (tile_set->is_valid_peering_bit_terrain(p_terrain_set, side)) {
terrains.insert(pattern.get_terrain(side));
}
}
min_terrain_count = MIN(min_terrain_count, terrains.size());
terrains_counts.push_back(terrains.size());
@ -2369,7 +2368,7 @@ void TileMap::set_cells_from_surrounding_terrains(int p_layer, TypedArray<Vector
Map<Vector2i, TileSet::TerrainsPattern> wfc_output = terrain_wave_function_collapse(coords_set, p_terrain_set, constraints);
for (const KeyValue<Vector2i, TileSet::TerrainsPattern> &kv : wfc_output) {
TileMapCell cell = tile_set->get_random_tile_from_pattern(p_terrain_set, kv.value);
TileMapCell cell = tile_set->get_random_tile_from_terrains_pattern(p_terrain_set, kv.value);
set_cell(p_layer, kv.key, cell.source_id, cell.get_atlas_coords(), cell.alternative_tile);
}
}

View file

@ -225,6 +225,90 @@ void TileMapPattern::_bind_methods() {
/////////////////////////////// TileSet //////////////////////////////////////
bool TileSet::TerrainsPattern::is_valid() const {
return valid;
}
bool TileSet::TerrainsPattern::is_erase_pattern() const {
return not_empty_terrains_count == 0;
}
bool TileSet::TerrainsPattern::operator<(const TerrainsPattern &p_terrains_pattern) const {
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i] != p_terrains_pattern.is_valid_bit[i]) {
return is_valid_bit[i] < p_terrains_pattern.is_valid_bit[i];
}
}
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
return bits[i] < p_terrains_pattern.bits[i];
}
}
return false;
}
bool TileSet::TerrainsPattern::operator==(const TerrainsPattern &p_terrains_pattern) const {
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i] != p_terrains_pattern.is_valid_bit[i]) {
return false;
}
if (is_valid_bit[i] && bits[i] != p_terrains_pattern.bits[i]) {
return false;
}
}
return true;
}
void TileSet::TerrainsPattern::set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain) {
ERR_FAIL_COND(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX);
ERR_FAIL_COND(!is_valid_bit[p_peering_bit]);
ERR_FAIL_COND(p_terrain < -1);
// Update the "is_erase_pattern" status.
if (p_terrain >= 0 && bits[p_peering_bit] < 0) {
not_empty_terrains_count++;
} else if (p_terrain < 0 && bits[p_peering_bit] >= 0) {
not_empty_terrains_count--;
}
bits[p_peering_bit] = p_terrain;
}
int TileSet::TerrainsPattern::get_terrain(TileSet::CellNeighbor p_peering_bit) const {
ERR_FAIL_COND_V(p_peering_bit == TileSet::CELL_NEIGHBOR_MAX, -1);
ERR_FAIL_COND_V(!is_valid_bit[p_peering_bit], -1);
return bits[p_peering_bit];
}
void TileSet::TerrainsPattern::set_terrains_from_array(Array p_terrains) {
int in_array_index = 0;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
ERR_FAIL_COND(in_array_index >= p_terrains.size());
set_terrain(TileSet::CellNeighbor(i), p_terrains[in_array_index]);
in_array_index++;
}
}
}
Array TileSet::TerrainsPattern::get_terrains_as_array() const {
Array output;
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (is_valid_bit[i]) {
output.push_back(bits[i]);
}
}
return output;
}
TileSet::TerrainsPattern::TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set) {
ERR_FAIL_COND(p_terrain_set < 0);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
is_valid_bit[i] = (p_tile_set->is_valid_peering_bit_terrain(p_terrain_set, TileSet::CellNeighbor(i)));
bits[i] = -1;
}
valid = true;
}
const int TileSet::INVALID_SOURCE = -1;
const char *TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[] = {
@ -330,10 +414,13 @@ void TileSet::_update_terrains_cache() {
TileSet::TerrainsPattern terrains_pattern = tile_data->get_terrains_pattern();
// Terrain bits.
for (int i = 0; i < terrains_pattern.size(); i++) {
int terrain = terrains_pattern[i];
if (terrain >= 0) {
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
CellNeighbor bit = CellNeighbor(i);
if (is_valid_peering_bit_terrain(terrain_set, bit)) {
int terrain = terrains_pattern.get_terrain(bit);
if (terrain >= 0) {
per_terrain_pattern_tiles[terrain_set][terrains_pattern].insert(cell);
}
}
}
}
@ -344,12 +431,7 @@ void TileSet::_update_terrains_cache() {
// Add the empty cell in the possible patterns and cells.
for (int i = 0; i < terrain_sets.size(); i++) {
TileSet::TerrainsPattern empty_pattern;
for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) {
if (is_valid_peering_bit_terrain(i, TileSet::CellNeighbor(j))) {
empty_pattern.push_back(-1);
}
}
TileSet::TerrainsPattern empty_pattern(this, i);
TileMapCell empty_cell;
empty_cell.source_id = TileSet::INVALID_SOURCE;
@ -1283,7 +1365,7 @@ Set<TileMapCell> TileSet::get_tiles_for_terrains_pattern(int p_terrain_set, Terr
return per_terrain_pattern_tiles[p_terrain_set][p_terrain_tile_pattern];
}
TileMapCell TileSet::get_random_tile_from_pattern(int p_terrain_set, TileSet::TerrainsPattern p_terrain_tile_pattern) {
TileMapCell TileSet::get_random_tile_from_terrains_pattern(int p_terrain_set, TileSet::TerrainsPattern p_terrain_tile_pattern) {
ERR_FAIL_INDEX_V(p_terrain_set, terrain_sets.size(), TileMapCell());
_update_terrains_cache();
@ -4915,10 +4997,10 @@ bool TileData::is_valid_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit)
TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
ERR_FAIL_COND_V(!tile_set, TileSet::TerrainsPattern());
TileSet::TerrainsPattern output;
TileSet::TerrainsPattern output(tile_set, terrain_set);
for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
if (tile_set->is_valid_peering_bit_terrain(terrain_set, TileSet::CellNeighbor(i))) {
output.push_back(get_peering_bit_terrain(TileSet::CellNeighbor(i)));
output.set_terrain(TileSet::CellNeighbor(i), get_peering_bit_terrain(TileSet::CellNeighbor(i)));
}
}
return output;

View file

@ -253,7 +253,30 @@ public:
Ref<PackedScene> scene;
Vector2 offset;
};
typedef Array TerrainsPattern;
class TerrainsPattern {
bool valid = false;
int bits[TileSet::CELL_NEIGHBOR_MAX];
bool is_valid_bit[TileSet::CELL_NEIGHBOR_MAX];
int not_empty_terrains_count = 0;
public:
bool is_valid() const;
bool is_erase_pattern() const;
bool operator<(const TerrainsPattern &p_terrains_pattern) const;
bool operator==(const TerrainsPattern &p_terrains_pattern) const;
void set_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain);
int get_terrain(TileSet::CellNeighbor p_peering_bit) const;
void set_terrains_from_array(Array p_terrains);
Array get_terrains_as_array() const;
TerrainsPattern(const TileSet *p_tile_set, int p_terrain_set);
TerrainsPattern() {}
};
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@ -478,7 +501,7 @@ public:
// Terrains.
Set<TerrainsPattern> get_terrains_pattern_set(int p_terrain_set);
Set<TileMapCell> get_tiles_for_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern);
TileMapCell get_random_tile_from_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern);
TileMapCell get_random_tile_from_terrains_pattern(int p_terrain_set, TerrainsPattern p_terrain_tile_pattern);
// Helpers
Vector<Vector2> get_tile_shape_polygon();