From 2f81373562e1a40775d491bff3b1d315bde1407e Mon Sep 17 00:00:00 2001 From: Relintai Date: Sat, 23 Apr 2022 00:48:19 +0200 Subject: [PATCH] Lots of work on the bindings for the wfc module. Also smaller improvements. --- .../wfc/overlapping_wave_form_collapse.cpp | 70 ++++++++++++++++-- modules/wfc/overlapping_wave_form_collapse.h | 35 ++++++--- modules/wfc/tiling_wave_form_collapse.cpp | 23 +++--- modules/wfc/tiling_wave_form_collapse.h | 20 ++--- modules/wfc/wave_form_collapse.cpp | 73 ++++++++++++++++++- modules/wfc/wave_form_collapse.h | 27 +++++-- 6 files changed, 200 insertions(+), 48 deletions(-) diff --git a/modules/wfc/overlapping_wave_form_collapse.cpp b/modules/wfc/overlapping_wave_form_collapse.cpp index 639d9accf..54610f015 100644 --- a/modules/wfc/overlapping_wave_form_collapse.cpp +++ b/modules/wfc/overlapping_wave_form_collapse.cpp @@ -3,8 +3,46 @@ #include "core/set.h" -void OverlappingWaveFormCollapse::set_input(const Array2D &data) { - input = data; +bool OverlappingWaveFormCollapse::get_periodic_input() const { + return periodic_input; +} +void OverlappingWaveFormCollapse::set_periodic_input(const bool val) { + periodic_input = val; +} + +int OverlappingWaveFormCollapse::get_out_height() const { + return out_height; +} +void OverlappingWaveFormCollapse::set_out_height(const int val) { + out_height = val; +} + +int OverlappingWaveFormCollapse::get_out_width() const { + return out_width; +} +void OverlappingWaveFormCollapse::set_out_width(const int val) { + periodic_output = val; +} + +int OverlappingWaveFormCollapse::get_symmetry() const { + return symmetry; +} +void OverlappingWaveFormCollapse::set_symmetry(const int val) { + symmetry = val; +} + +bool OverlappingWaveFormCollapse::get_ground() const { + return ground; +} +void OverlappingWaveFormCollapse::set_ground(const bool val) { + ground = val; +} + +int OverlappingWaveFormCollapse::get_pattern_size() const { + return pattern_size; +} +void OverlappingWaveFormCollapse::set_pattern_size(const int val) { + pattern_size = val; } int OverlappingWaveFormCollapse::get_wave_height() const { @@ -17,8 +55,8 @@ int OverlappingWaveFormCollapse::get_wave_width() const { } // Run the WFC algorithm, and return the result if the algorithm succeeded. -Array2D OverlappingWaveFormCollapse::orun() { - Array2D result = run(); +Array2D OverlappingWaveFormCollapse::run() { + Array2D result = WaveFormCollapse::run(); if (result.width == 0 && result.height == 0) { return Array2D(0, 0); @@ -248,7 +286,6 @@ void OverlappingWaveFormCollapse::initialize() { OverlappingWaveFormCollapse::OverlappingWaveFormCollapse() { periodic_input = false; - periodic_output = false; out_height = 0; out_width = 0; symmetry = 0; @@ -259,4 +296,27 @@ OverlappingWaveFormCollapse::~OverlappingWaveFormCollapse() { } void OverlappingWaveFormCollapse::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_periodic_input"), &OverlappingWaveFormCollapse::get_periodic_input); + ClassDB::bind_method(D_METHOD("set_periodic_input", "value"), &OverlappingWaveFormCollapse::set_periodic_input); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "periodic_input"), "set_periodic_input", "get_periodic_input"); + + ClassDB::bind_method(D_METHOD("get_out_height"), &OverlappingWaveFormCollapse::get_out_height); + ClassDB::bind_method(D_METHOD("set_out_height", "value"), &OverlappingWaveFormCollapse::set_out_height); + ADD_PROPERTY(PropertyInfo(Variant::INT, "out_height"), "set_out_height", "get_out_height"); + + ClassDB::bind_method(D_METHOD("get_out_width"), &OverlappingWaveFormCollapse::get_out_width); + ClassDB::bind_method(D_METHOD("set_out_width", "value"), &OverlappingWaveFormCollapse::set_out_width); + ADD_PROPERTY(PropertyInfo(Variant::INT, "out_width"), "set_out_width", "get_out_width"); + + ClassDB::bind_method(D_METHOD("get_symmetry"), &OverlappingWaveFormCollapse::get_symmetry); + ClassDB::bind_method(D_METHOD("set_symmetry", "value"), &OverlappingWaveFormCollapse::set_symmetry); + ADD_PROPERTY(PropertyInfo(Variant::INT, "symmetry"), "set_symmetry", "get_symmetry"); + + ClassDB::bind_method(D_METHOD("get_ground"), &OverlappingWaveFormCollapse::get_ground); + ClassDB::bind_method(D_METHOD("set_ground", "value"), &OverlappingWaveFormCollapse::set_ground); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ground"), "set_ground", "get_ground"); + + ClassDB::bind_method(D_METHOD("get_pattern_size"), &OverlappingWaveFormCollapse::get_pattern_size); + ClassDB::bind_method(D_METHOD("set_pattern_size", "value"), &OverlappingWaveFormCollapse::set_pattern_size); + ADD_PROPERTY(PropertyInfo(Variant::INT, "pattern_size"), "set_pattern_size", "get_pattern_size"); } diff --git a/modules/wfc/overlapping_wave_form_collapse.h b/modules/wfc/overlapping_wave_form_collapse.h index 766c66ede..16aee6e71 100644 --- a/modules/wfc/overlapping_wave_form_collapse.h +++ b/modules/wfc/overlapping_wave_form_collapse.h @@ -10,20 +10,28 @@ class OverlappingWaveFormCollapse : public WaveFormCollapse { GDCLASS(OverlappingWaveFormCollapse, WaveFormCollapse); public: - bool periodic_input; - bool periodic_output; - int out_height; - int out_width; - int symmetry; - bool ground; - int pattern_size; + bool get_periodic_input() const; + void set_periodic_input(const bool val); - void set_input(const Array2D &data); + int get_out_height() const; + void set_out_height(const int val); + + int get_out_width() const; + void set_out_width(const int val); + + int get_symmetry() const; + void set_symmetry(const int val); + + bool get_ground() const; + void set_ground(const bool val); + + int get_pattern_size() const; + void set_pattern_size(const int val); int get_wave_height() const; int get_wave_width() const; - Array2D orun(); + Array2D run(); void init_ground(); @@ -48,9 +56,14 @@ protected: static void _bind_methods(); private: - Array2D input; - Vector> patterns; + + bool periodic_input; + int out_height; + int out_width; + int symmetry; + bool ground; + int pattern_size; }; #endif diff --git a/modules/wfc/tiling_wave_form_collapse.cpp b/modules/wfc/tiling_wave_form_collapse.cpp index 9601460e4..f1dae78ba 100644 --- a/modules/wfc/tiling_wave_form_collapse.cpp +++ b/modules/wfc/tiling_wave_form_collapse.cpp @@ -30,7 +30,7 @@ const uint8_t Tile::reflection_map[6][9] = { // Actions 0, 1, 2, and 3 are 0°, 90°, 180°, and 270° anticlockwise rotations. // Actions 4, 5, 6, and 7 are actions 0, 1, 2, and 3 preceded by a reflection // on the x axis. -Tile::ActionMap Tile::generate_action_map(const Symmetry &symmetry) { +Tile::ActionMap Tile::generate_action_map(const WaveFormCollapse::Symmetry &symmetry) { int sindx = static_cast(symmetry); int size = rotation_map[sindx][0]; @@ -60,22 +60,22 @@ Tile::ActionMap Tile::generate_action_map(const Symmetry &symmetry) { } // Generate all distincts rotations of a 2D array given its symmetries; -Vector> Tile::generate_oriented(Array2D data, Symmetry symmetry) { +Vector> Tile::generate_oriented(Array2D data, WaveFormCollapse::Symmetry symmetry) { Vector> oriented; oriented.push_back(data); switch (symmetry) { - case SYMMETRY_I: - case SYMMETRY_BACKSLASH: + case WaveFormCollapse::SYMMETRY_I: + case WaveFormCollapse::SYMMETRY_BACKSLASH: oriented.push_back(data.rotated()); break; - case SYMMETRY_T: - case SYMMETRY_L: + case WaveFormCollapse::SYMMETRY_T: + case WaveFormCollapse::SYMMETRY_L: oriented.push_back(data = data.rotated()); oriented.push_back(data = data.rotated()); oriented.push_back(data = data.rotated()); break; - case SYMMETRY_P: + case WaveFormCollapse::SYMMETRY_P: oriented.push_back(data = data.rotated()); oriented.push_back(data = data.rotated()); oriented.push_back(data = data.rotated()); @@ -92,7 +92,7 @@ Vector> Tile::generate_oriented(Array2D data, Symmetry symmetr } // Create a tile with its differents orientations, its symmetries and its weight on the distribution of tiles. -Tile::Tile(const Vector> &p_data, Symmetry p_symmetry, double p_weight) { +Tile::Tile(const Vector> &p_data, WaveFormCollapse::Symmetry p_symmetry, double p_weight) { data = p_data; symmetry = p_symmetry; weight = p_weight; @@ -100,7 +100,7 @@ Tile::Tile(const Vector> &p_data, Symmetry p_symmetry, double p_wei // Create a tile with its base orientation, its symmetries and its weight on the distribution of tiles. // The other orientations are generated with its first one. -Tile::Tile(const Array2D &p_data, Symmetry p_symmetry, double p_weight) { +Tile::Tile(const Array2D &p_data, WaveFormCollapse::Symmetry p_symmetry, double p_weight) { data = generate_oriented(p_data, p_symmetry); symmetry = p_symmetry; weight = p_weight; @@ -211,8 +211,8 @@ void TilingWaveFormCollapse::set_tile(int tile_id, int i, int j) { } } -Array2D TilingWaveFormCollapse::do_run() { - Array2D a = run(); +Array2D TilingWaveFormCollapse::run() { + Array2D a = WaveFormCollapse::run(); if (a.width == 0 && a.height == 0) { return Array2D(0, 0); @@ -243,6 +243,7 @@ Array2D TilingWaveFormCollapse::id_to_tiling(Array2D ids) { void TilingWaveFormCollapse::initialize() { generate_oriented_tile_ids(); + generate_propagator(); WaveFormCollapse::initialize(); } diff --git a/modules/wfc/tiling_wave_form_collapse.h b/modules/wfc/tiling_wave_form_collapse.h index 1fde339ad..3ed04bc16 100644 --- a/modules/wfc/tiling_wave_form_collapse.h +++ b/modules/wfc/tiling_wave_form_collapse.h @@ -7,14 +7,6 @@ #include "wave_form_collapse.h" struct Tile { - enum Symmetry { - SYMMETRY_X = 0, - SYMMETRY_T, - SYMMETRY_I, - SYMMETRY_L, - SYMMETRY_BACKSLASH, - SYMMETRY_P - }; struct ActionMap { Vector map[8]; @@ -30,15 +22,15 @@ struct Tile { static const uint8_t reflection_map[6][9]; Vector> data; - Symmetry symmetry; + WaveFormCollapse::Symmetry symmetry; double weight; - static ActionMap generate_action_map(const Symmetry &symmetry); + static ActionMap generate_action_map(const WaveFormCollapse::Symmetry &symmetry); - static Vector> generate_oriented(Array2D data, Symmetry symmetry); + static Vector> generate_oriented(Array2D data, WaveFormCollapse::Symmetry symmetry); - Tile(const Vector> &p_data, Symmetry p_symmetry, double p_weight); - Tile(const Array2D &p_data, Symmetry p_symmetry, double p_weight); + Tile(const Vector> &p_data, WaveFormCollapse::Symmetry p_symmetry, double p_weight); + Tile(const Array2D &p_data, WaveFormCollapse::Symmetry p_symmetry, double p_weight); }; class TilingWaveFormCollapse : public WaveFormCollapse { @@ -94,7 +86,7 @@ public: void set_tile(int tile_id, int i, int j); bool set_tile(int tile_id, int orientation, int i, int j); - Array2D do_run(); + Array2D run(); Array2D id_to_tiling(Array2D ids); diff --git a/modules/wfc/wave_form_collapse.cpp b/modules/wfc/wave_form_collapse.cpp index 3b061f9ca..90d1a9639 100644 --- a/modules/wfc/wave_form_collapse.cpp +++ b/modules/wfc/wave_form_collapse.cpp @@ -77,6 +77,23 @@ void WaveFormCollapse::set_pattern_frequencies(const Vector &p_patterns_ } } +void WaveFormCollapse::set_input(const PoolIntArray &p_data, int p_width, int p_height) { + set_size(p_width, p_height); + + input.resize(p_width, p_height); + + ERR_FAIL_COND(input.data.size() != p_data.size()); + + int *w = input.data.ptrw(); + int s = input.data.size(); + + PoolIntArray::Read r = p_data.read(); + + for (int i = 0; i < s; ++i) { + w[i] = r[i]; + } +} + Array2D WaveFormCollapse::run() { while (true) { // Define the value of an undefined cell. @@ -93,6 +110,34 @@ Array2D WaveFormCollapse::run() { } } +PoolIntArray WaveFormCollapse::generate_image_index_data() { + PoolIntArray arr; + + Array2D a = run(); + + if (a.width == 0 && a.height == 0) { + return arr; + } + + print_error(String::num(a.width)); + print_error(String::num(a.height)); + print_error("---"); + + const int *r = a.data.ptr(); + int s = a.data.size(); + + arr.resize(s); + PoolIntArray::Write w = arr.write(); + + for (int i = 0; i < s; ++i) { + w[i] = r[i]; + } + + w.release(); + + return arr; +} + WaveFormCollapse::ObserveStatus WaveFormCollapse::observe() { // Get the cell with lowest entropy. int argmin = wave_get_min_entropy(); @@ -299,6 +344,7 @@ void WaveFormCollapse::propagate() { void WaveFormCollapse::initialize() { //wave + data.resize(0, 0); data.resize_fill(wave_width * wave_height, patterns_frequencies.size(), 1); plogp_patterns_frequencies = get_plogp(patterns_frequencies); @@ -354,5 +400,28 @@ WaveFormCollapse::WaveFormCollapse() { WaveFormCollapse::~WaveFormCollapse() { } -void WaveFormCollapse::bind_methods() { -} \ No newline at end of file +void WaveFormCollapse::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_width"), &WaveFormCollapse::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &WaveFormCollapse::get_height); + + ClassDB::bind_method(D_METHOD("get_periodic_output"), &WaveFormCollapse::get_periodic_output); + ClassDB::bind_method(D_METHOD("set_periodic_output", "value"), &WaveFormCollapse::set_periodic_output); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "periodic_output"), "set_periodic_output", "get_periodic_output"); + + ClassDB::bind_method(D_METHOD("set_seed", "seed"), &WaveFormCollapse::set_seed); + ClassDB::bind_method(D_METHOD("set_size", "width", "height"), &WaveFormCollapse::set_size); + + ClassDB::bind_method(D_METHOD("propagate"), &WaveFormCollapse::propagate); + ClassDB::bind_method(D_METHOD("initialize"), &WaveFormCollapse::initialize); + + ClassDB::bind_method(D_METHOD("set_input", "data", "width", "height"), &WaveFormCollapse::set_input); + + ClassDB::bind_method(D_METHOD("generate_image_index_data"), &WaveFormCollapse::generate_image_index_data); + + BIND_ENUM_CONSTANT(SYMMETRY_X); + BIND_ENUM_CONSTANT(SYMMETRY_T); + BIND_ENUM_CONSTANT(SYMMETRY_I); + BIND_ENUM_CONSTANT(SYMMETRY_L); + BIND_ENUM_CONSTANT(SYMMETRY_BACKSLASH); + BIND_ENUM_CONSTANT(SYMMETRY_P); +} diff --git a/modules/wfc/wave_form_collapse.h b/modules/wfc/wave_form_collapse.h index e7f5d3289..d6b4ed23e 100644 --- a/modules/wfc/wave_form_collapse.h +++ b/modules/wfc/wave_form_collapse.h @@ -14,6 +14,15 @@ class WaveFormCollapse : public Reference { GDCLASS(WaveFormCollapse, Reference); public: + enum Symmetry { + SYMMETRY_X = 0, + SYMMETRY_T, + SYMMETRY_I, + SYMMETRY_L, + SYMMETRY_BACKSLASH, + SYMMETRY_P + }; + enum ObserveStatus { OBSERVE_STATUS_SUCCESS, OBSERVE_STATUS_FAILURE, @@ -67,7 +76,11 @@ public: void set_propagator_state(const Vector &p_propagator_state); void set_pattern_frequencies(const Vector &p_patterns_frequencies, const bool p_normalize = true); - Array2D run(); + virtual void set_input(const PoolIntArray &p_data, int p_width, int p_height); + + virtual Array2D run(); + + PoolIntArray generate_image_index_data(); ObserveStatus observe(); @@ -125,7 +138,11 @@ public: ~WaveFormCollapse(); protected: - static void bind_methods(); + static void _bind_methods(); + + Array2D input; + + bool periodic_output; private: RandomPCG gen; @@ -164,13 +181,11 @@ private: // The actual wave. data.get(index, pattern) is equal to 0 if the pattern can // be placed in the cell index. - Array2D data; + Array2D data; //Propagator Vector propagator_state; - bool periodic_output; - // All the tuples (y, x, pattern) that should be propagated. // The tuple should be propagated when wave.get(y, x, pattern) is set to false. Vector propagating; @@ -185,4 +200,6 @@ private: void init_compatible(); }; +VARIANT_ENUM_CAST(WaveFormCollapse::Symmetry); + #endif