Lots of work on the bindings for the wfc module. Also smaller improvements.

This commit is contained in:
Relintai 2022-04-23 00:48:19 +02:00
parent 0f1c04e08d
commit 2f81373562
6 changed files with 200 additions and 48 deletions

View File

@ -3,8 +3,46 @@
#include "core/set.h"
void OverlappingWaveFormCollapse::set_input(const Array2D<int> &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<int> OverlappingWaveFormCollapse::orun() {
Array2D<int> result = run();
Array2D<int> OverlappingWaveFormCollapse::run() {
Array2D<int> result = WaveFormCollapse::run();
if (result.width == 0 && result.height == 0) {
return Array2D<int>(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");
}

View File

@ -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<int> &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<int> orun();
Array2D<int> run();
void init_ground();
@ -48,9 +56,14 @@ protected:
static void _bind_methods();
private:
Array2D<int> input;
Vector<Array2D<int>> patterns;
bool periodic_input;
int out_height;
int out_width;
int symmetry;
bool ground;
int pattern_size;
};
#endif

View File

@ -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<int>(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<Array2D<int>> Tile::generate_oriented(Array2D<int> data, Symmetry symmetry) {
Vector<Array2D<int>> Tile::generate_oriented(Array2D<int> data, WaveFormCollapse::Symmetry symmetry) {
Vector<Array2D<int>> 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<Array2D<int>> Tile::generate_oriented(Array2D<int> data, Symmetry symmetr
}
// Create a tile with its differents orientations, its symmetries and its weight on the distribution of tiles.
Tile::Tile(const Vector<Array2D<int>> &p_data, Symmetry p_symmetry, double p_weight) {
Tile::Tile(const Vector<Array2D<int>> &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<Array2D<int>> &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<int> &p_data, Symmetry p_symmetry, double p_weight) {
Tile::Tile(const Array2D<int> &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<int> TilingWaveFormCollapse::do_run() {
Array2D<int> a = run();
Array2D<int> TilingWaveFormCollapse::run() {
Array2D<int> a = WaveFormCollapse::run();
if (a.width == 0 && a.height == 0) {
return Array2D<int>(0, 0);
@ -243,6 +243,7 @@ Array2D<int> TilingWaveFormCollapse::id_to_tiling(Array2D<int> ids) {
void TilingWaveFormCollapse::initialize() {
generate_oriented_tile_ids();
generate_propagator();
WaveFormCollapse::initialize();
}

View File

@ -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<int> map[8];
@ -30,15 +22,15 @@ struct Tile {
static const uint8_t reflection_map[6][9];
Vector<Array2D<int>> 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<Array2D<int>> generate_oriented(Array2D<int> data, Symmetry symmetry);
static Vector<Array2D<int>> generate_oriented(Array2D<int> data, WaveFormCollapse::Symmetry symmetry);
Tile(const Vector<Array2D<int>> &p_data, Symmetry p_symmetry, double p_weight);
Tile(const Array2D<int> &p_data, Symmetry p_symmetry, double p_weight);
Tile(const Vector<Array2D<int>> &p_data, WaveFormCollapse::Symmetry p_symmetry, double p_weight);
Tile(const Array2D<int> &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<int> do_run();
Array2D<int> run();
Array2D<int> id_to_tiling(Array2D<int> ids);

View File

@ -77,6 +77,23 @@ void WaveFormCollapse::set_pattern_frequencies(const Vector<double> &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<int> WaveFormCollapse::run() {
while (true) {
// Define the value of an undefined cell.
@ -93,6 +110,34 @@ Array2D<int> WaveFormCollapse::run() {
}
}
PoolIntArray WaveFormCollapse::generate_image_index_data() {
PoolIntArray arr;
Array2D<int> 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() {
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);
}

View File

@ -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<PropagatorStateEntry> &p_propagator_state);
void set_pattern_frequencies(const Vector<double> &p_patterns_frequencies, const bool p_normalize = true);
Array2D<int> run();
virtual void set_input(const PoolIntArray &p_data, int p_width, int p_height);
virtual Array2D<int> run();
PoolIntArray generate_image_index_data();
ObserveStatus observe();
@ -125,7 +138,11 @@ public:
~WaveFormCollapse();
protected:
static void bind_methods();
static void _bind_methods();
Array2D<int> 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<uint8_t> data;
Array2D<int> data;
//Propagator
Vector<PropagatorStateEntry> 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<PropagatingEntry> propagating;
@ -185,4 +200,6 @@ private:
void init_compatible();
};
VARIANT_ENUM_CAST(WaveFormCollapse::Symmetry);
#endif