Merge pull request #54396 from groud/implement_terrain_other_brushes
This commit is contained in:
commit
529968df30
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,8 +414,10 @@ 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];
|
||||
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);
|
||||
}
|
||||
@ -341,15 +427,11 @@ 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;
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user