diff --git a/modules/wfc/SCsub b/modules/wfc/SCsub index 5c97a839e..14fb43549 100644 --- a/modules/wfc/SCsub +++ b/modules/wfc/SCsub @@ -9,4 +9,4 @@ env_wfc.add_source_files(env.modules_sources, "register_types.cpp") env_wfc.add_source_files(env.modules_sources, "wave_form_collapse.cpp") env_wfc.add_source_files(env.modules_sources, "tiling_wave_form_collapse.cpp") -#env_wfc.add_source_files(env.modules_sources, "overlapping_wave_form_collapse.cpp") +env_wfc.add_source_files(env.modules_sources, "overlapping_wave_form_collapse.cpp") diff --git a/modules/wfc/overlapping_wave_form_collapse.cpp b/modules/wfc/overlapping_wave_form_collapse.cpp index 1f669b64f..281cd612c 100644 --- a/modules/wfc/overlapping_wave_form_collapse.cpp +++ b/modules/wfc/overlapping_wave_form_collapse.cpp @@ -1,18 +1,24 @@ #include "overlapping_wave_form_collapse.h" +#include "core/set.h" + +void OverlappingWaveFormCollapse::set_input(const Array2D &data) { + input = data; +} + uint32_t OverlappingWaveFormCollapse::get_wave_height() const { return periodic_output ? out_height : out_height - pattern_size + 1; } -//Get the wave width given these options. +//Get the wave width given these uint32_t OverlappingWaveFormCollapse::get_wave_width() const { return periodic_output ? out_width : out_width - pattern_size + 1; } // Run the WFC algorithm, and return the result if the algorithm succeeded. -Array2D OverlappingWaveFormCollapse::run() { - Array2D result = wfc.run(); +Array2D OverlappingWaveFormCollapse::orun() { + Array2D result = run(); if (result.width == 0 && result.height == 0) { return Array2D(0, 0); @@ -21,29 +27,29 @@ Array2D OverlappingWaveFormCollapse::run() { return to_image(result); } -void OverlappingWaveFormCollapse::init_ground(WFC &wfc, const Array2D &input, const Vector> &patterns, const OverlappingWFCOptions &options) { - uint32_t ground_pattern_id = get_ground_pattern_id(input, patterns, options); +void OverlappingWaveFormCollapse::init_ground() { + uint32_t ground_pattern_id = get_ground_pattern_id(); - for (uint32_t j = 0; j < options.get_wave_width(); j++) { - set_pattern(ground_pattern_id, options.get_wave_height() - 1, j); + for (uint32_t j = 0; j < get_wave_width(); j++) { + set_pattern(ground_pattern_id, get_wave_height() - 1, j); } - for (uint32_t i = 0; i < options.get_wave_height() - 1; i++) { - for (uint32_t j = 0; j < options.get_wave_width(); j++) { - wfc.remove_wave_pattern(i, j, ground_pattern_id); + for (uint32_t i = 0; i < get_wave_height() - 1; i++) { + for (uint32_t j = 0; j < get_wave_width(); j++) { + remove_wave_pattern(i, j, ground_pattern_id); } } - wfc.propagate(); + propagate(); } // Set the pattern at a specific position. // Returns false if the given pattern does not exist, or if the // coordinates are not in the wave bool OverlappingWaveFormCollapse::set_pattern(const Array2D &pattern, uint32_t i, uint32_t j) { - auto pattern_id = get_pattern_id(pattern); + uint32_t pattern_id = get_pattern_id(pattern); - if (pattern_id == std::nullopt || i >= options.get_wave_height() || j >= options.get_wave_width()) { + if (pattern_id == static_cast(-1) || i >= get_wave_height() || j >= get_wave_width()) { return false; } @@ -51,9 +57,9 @@ bool OverlappingWaveFormCollapse::set_pattern(const Array2D &pattern, return true; } -static uint32_t OverlappingWaveFormCollapse::get_ground_pattern_id(const Array2D &input, const Vector> &patterns, const OverlappingWFCOptions &options) { +uint32_t OverlappingWaveFormCollapse::get_ground_pattern_id() { // Get the pattern. - Array2D ground_pattern = input.get_sub_array(input.height - 1, input.width / 2, options.pattern_size, options.pattern_size); + Array2D ground_pattern = input.get_sub_array(input.height - 1, input.width / 2, pattern_size, pattern_size); // Retrieve the id of the pattern. for (int i = 0; i < patterns.size(); i++) { @@ -66,10 +72,10 @@ static uint32_t OverlappingWaveFormCollapse::get_ground_pattern_id(const Array2D } uint32_t OverlappingWaveFormCollapse::get_pattern_id(const Array2D &pattern) { - uint32_t *pattern_id = std::find(patterns.begin(), patterns.end(), pattern); - - if (pattern_id != patterns.end()) { - return *pattern_id; + for (int i = 0; i < patterns.size(); ++i) { + if (patterns[i] == pattern) { + return i; + } } return -1; @@ -79,45 +85,59 @@ uint32_t OverlappingWaveFormCollapse::get_pattern_id(const Array2D &pa // pattern_id needs to be a valid pattern id, and i and j needs to be in the wave range void OverlappingWaveFormCollapse::set_pattern(uint32_t pattern_id, uint32_t i, uint32_t j) { for (int p = 0; p < patterns.size(); p++) { - if (pattern_id != p) { - wfc.remove_wave_pattern(i, j, p); + if (pattern_id != static_cast(p)) { + remove_wave_pattern(i, j, p); } } } //Return the list of patterns, as well as their probabilities of apparition. -static std::pair>, Vector> OverlappingWaveFormCollapse::get_patterns(const Array2D &input, const OverlappingWFCOptions &options) { - std::unordered_map, uint32_t> patterns_id; - Vector> patterns; +void OverlappingWaveFormCollapse::get_patterns() { + //OAHashMap, uint32_t> patterns_id; + + LocalVector> patterns_id; + + patterns.clear(); // The number of time a pattern is seen in the input image. Vector patterns_weight; - Vector> symmetries(8, Array2D(options.pattern_size, options.pattern_size)); - uint32_t max_i = options.periodic_input ? input.height : input.height - options.pattern_size + 1; - uint32_t max_j = options.periodic_input ? input.width : input.width - options.pattern_size + 1; + Vector> symmetries; + symmetries.resize(8); + + for (int i = 0; i < 8; ++i) { + symmetries.write[i].resize(pattern_size, pattern_size); + } + + uint32_t max_i = periodic_input ? input.height : input.height - pattern_size + 1; + uint32_t max_j = periodic_input ? input.width : input.width - pattern_size + 1; for (uint32_t i = 0; i < max_i; i++) { for (uint32_t j = 0; j < max_j; j++) { // Compute the symmetries of every pattern in the image. - symmetries[0].data = input.get_sub_array(i, j, options.pattern_size, options.pattern_size).data; - symmetries[1].data = symmetries[0].reflected().data; - symmetries[2].data = symmetries[0].rotated().data; - symmetries[3].data = symmetries[2].reflected().data; - symmetries[4].data = symmetries[2].rotated().data; - symmetries[5].data = symmetries[4].reflected().data; - symmetries[6].data = symmetries[4].rotated().data; - symmetries[7].data = symmetries[6].reflected().data; + symmetries.write[0].data = input.get_sub_array(i, j, pattern_size, pattern_size).data; + symmetries.write[1].data = symmetries[0].reflected().data; + symmetries.write[2].data = symmetries[0].rotated().data; + symmetries.write[3].data = symmetries[2].reflected().data; + symmetries.write[4].data = symmetries[2].rotated().data; + symmetries.write[5].data = symmetries[4].reflected().data; + symmetries.write[6].data = symmetries[4].rotated().data; + symmetries.write[7].data = symmetries[6].reflected().data; - // The number of symmetries in the option class define which symetries - // will be used. - for (uint32_t k = 0; k < options.symmetry; k++) { - auto res = patterns_id.insert(std::make_pair(symmetries[k], patterns.size())); + // The number of symmetries in the option class define which symetries will be used. + for (uint32_t k = 0; k < symmetry; k++) { + int indx = patterns.size(); - // If the pattern already exist, we just have to increase its number - // of appearance. - if (!res.second) { - patterns_weight[res.first->second] += 1; + for (uint32_t h = 0; h < patterns_id.size(); ++h) { + if (patterns_id[h] == symmetries[k]) { + indx = h; + break; + } + } + + if (indx != patterns.size()) { + // If the pattern already exist, we just have to increase its number of appearance. + patterns_weight.write[indx] += 1; } else { patterns.push_back(symmetries[k]); patterns_weight.push_back(1); @@ -126,11 +146,11 @@ static std::pair>, Vector> OverlappingWaveFormC } } - return { patterns, patterns_weight }; + set_pattern_frequencies(patterns_weight); } //Return true if the pattern1 is compatible with pattern2 when pattern2 is at a distance (dy,dx) from pattern1. -static bool OverlappingWaveFormCollapse::agrees(const Array2D &pattern1, const Array2D &pattern2, int dy, int dx) { +bool OverlappingWaveFormCollapse::agrees(const Array2D &pattern1, const Array2D &pattern2, int dy, int dx) { uint32_t xmin = dx < 0 ? 0 : dx; uint32_t xmax = dx < 0 ? dx + pattern2.width : pattern1.width; uint32_t ymin = dy < 0 ? 0 : dy; @@ -153,8 +173,8 @@ static bool OverlappingWaveFormCollapse::agrees(const Array2D &pattern // If agrees(pattern1, pattern2, dy, dx), then compatible[pattern1][direction] // contains pattern2, where direction is the direction defined by (dy, dx) // (see direction.hpp). -static Vector OverlappingWaveFormCollapse::generate_compatible(const Vector> &patterns) { - Vector compatible; +Vector OverlappingWaveFormCollapse::generate_compatible() { + Vector compatible; compatible.resize(patterns.size()); // Iterate on every dy, dx, pattern1 and pattern2 @@ -162,7 +182,7 @@ static Vector OverlappingWaveFormCollapse::generate_compat for (uint32_t direction = 0; direction < 4; direction++) { for (int pattern2 = 0; pattern2 < patterns.size(); pattern2++) { if (agrees(patterns[pattern1], patterns[pattern2], directions_y[direction], directions_x[direction])) { - compatible[pattern1][direction].push_back(pattern2); + compatible.write[pattern1].directions[direction].push_back(pattern2); } } } @@ -173,41 +193,41 @@ static Vector OverlappingWaveFormCollapse::generate_compat // Transform a 2D array containing the patterns id to a 2D array containing the pixels. Array2D OverlappingWaveFormCollapse::to_image(const Array2D &output_patterns) const { - Array2D output = Array2D(options.out_height, options.out_width); + Array2D output = Array2D(out_height, out_width); - if (options.periodic_output) { - for (uint32_t y = 0; y < options.get_wave_height(); y++) { - for (uint32_t x = 0; x < options.get_wave_width(); x++) { + if (periodic_output) { + for (uint32_t y = 0; y < get_wave_height(); y++) { + for (uint32_t x = 0; x < get_wave_width(); x++) { output.get(y, x) = patterns[output_patterns.get(y, x)].get(0, 0); } } } else { - for (uint32_t y = 0; y < options.get_wave_height(); y++) { - for (uint32_t x = 0; x < options.get_wave_width(); x++) { + for (uint32_t y = 0; y < get_wave_height(); y++) { + for (uint32_t x = 0; x < get_wave_width(); x++) { output.get(y, x) = patterns[output_patterns.get(y, x)].get(0, 0); } } - for (uint32_t y = 0; y < options.get_wave_height(); y++) { - const Array2D &pattern = patterns[output_patterns.get(y, options.get_wave_width() - 1)]; - for (uint32_t dx = 1; dx < options.pattern_size; dx++) { - output.get(y, options.get_wave_width() - 1 + dx) = pattern.get(0, dx); + for (uint32_t y = 0; y < get_wave_height(); y++) { + const Array2D &pattern = patterns[output_patterns.get(y, get_wave_width() - 1)]; + for (uint32_t dx = 1; dx < pattern_size; dx++) { + output.get(y, get_wave_width() - 1 + dx) = pattern.get(0, dx); } } - for (uint32_t x = 0; x < options.get_wave_width(); x++) { - const Array2D &pattern = patterns[output_patterns.get(options.get_wave_height() - 1, x)]; - for (uint32_t dy = 1; dy < options.pattern_size; dy++) { - output.get(options.get_wave_height() - 1 + dy, x) = + for (uint32_t x = 0; x < get_wave_width(); x++) { + const Array2D &pattern = patterns[output_patterns.get(get_wave_height() - 1, x)]; + for (uint32_t dy = 1; dy < pattern_size; dy++) { + output.get(get_wave_height() - 1 + dy, x) = pattern.get(dy, 0); } } - const Array2D &pattern = patterns[output_patterns.get(options.get_wave_height() - 1, options.get_wave_width() - 1)]; + const Array2D &pattern = patterns[output_patterns.get(get_wave_height() - 1, get_wave_width() - 1)]; - for (uint32_t dy = 1; dy < options.pattern_size; dy++) { - for (uint32_t dx = 1; dx < options.pattern_size; dx++) { - output.get(options.get_wave_height() - 1 + dy, options.get_wave_width() - 1 + dx) = pattern.get(dy, dx); + for (uint32_t dy = 1; dy < pattern_size; dy++) { + for (uint32_t dx = 1; dx < pattern_size; dx++) { + output.get(get_wave_height() - 1 + dy, get_wave_width() - 1 + dx) = pattern.get(dy, dx); } } } @@ -215,32 +235,25 @@ Array2D OverlappingWaveFormCollapse::to_image(const Array2D return output; } -/* - - OverlappingWFC(const Array2D &input, const OverlappingWFCOptions &options, int seed) : - OverlappingWFC(input, options, seed, get_patterns(input, options)) {} - - OverlappingWFC( - const Array2D &input, const OverlappingWFCOptions &options, - const int &seed, - const std::pair>, Vector> &patterns, - const Vector &propagator) : - input(input), options(options), patterns(patterns.first), wfc(options.periodic_output, seed, patterns.second, propagator, options.get_wave_height(), options.get_wave_width()) { - // If necessary, the ground is set. - if (options.ground) { - init_ground(wfc, input, patterns.first, options); - } +void OverlappingWaveFormCollapse::initialize() { + // If necessary, the ground is set. + if (ground) { + init_ground(); } - OverlappingWFC(const Array2D &input, const OverlappingWFCOptions &options, - const int &seed, - const std::pair>, Vector> - &patterns) : - OverlappingWFC(input, options, seed, patterns, - generate_compatible(patterns.first)) {} -*/ + set_propagator_state(generate_compatible()); + + WaveFormCollapse::initialize(); +} OverlappingWaveFormCollapse::OverlappingWaveFormCollapse() { + periodic_input = false; + periodic_output = false; + out_height = 0; + out_width = 0; + symmetry = 0; + ground = false; + pattern_size = 0; } OverlappingWaveFormCollapse::~OverlappingWaveFormCollapse() { } diff --git a/modules/wfc/overlapping_wave_form_collapse.h b/modules/wfc/overlapping_wave_form_collapse.h index 930d78020..b372f3905 100644 --- a/modules/wfc/overlapping_wave_form_collapse.h +++ b/modules/wfc/overlapping_wave_form_collapse.h @@ -18,25 +18,29 @@ public: bool ground; uint32_t pattern_size; + void set_input(const Array2D &data); + uint32_t get_wave_height() const; uint32_t get_wave_width() const; - Array2D run(); + Array2D orun(); - void init_ground(const Array2D &input, const Vector> &patterns, const OverlappingWFCOptions &options); + void init_ground(); bool set_pattern(const Array2D &pattern, uint32_t i, uint32_t j); - static uint32_t get_ground_pattern_id(const Array2D &input, const Vector> &patterns, const OverlappingWFCOptions &options); + uint32_t get_ground_pattern_id(); uint32_t get_pattern_id(const Array2D &pattern); void set_pattern(uint32_t pattern_id, uint32_t i, uint32_t j); - static std::pair>, Vector> get_patterns(const Array2D &input, const OverlappingWFCOptions &options); + void get_patterns(); - static bool agrees(const Array2D &pattern1, const Array2D &pattern2, int dy, int dx); + bool agrees(const Array2D &pattern1, const Array2D &pattern2, int dy, int dx); - static Vector generate_compatible(const Vector> &patterns); + Vector generate_compatible(); Array2D to_image(const Array2D &output_patterns) const; + void initialize(); + OverlappingWaveFormCollapse(); ~OverlappingWaveFormCollapse();