From cf3f263f7254eadf9eceaf15a1416807968e200b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 28 Aug 2024 11:41:04 +0300 Subject: [PATCH] update SurroundMap (WIP) --- src/world/generator/SurroundMap.cpp | 117 +++++++++++++++++++++++++++ src/world/generator/SurroundMap.hpp | 25 ++++-- test/world/generator/SurroundMap.cpp | 6 ++ 3 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 src/world/generator/SurroundMap.cpp diff --git a/src/world/generator/SurroundMap.cpp b/src/world/generator/SurroundMap.cpp new file mode 100644 index 00000000..e54da0e0 --- /dev/null +++ b/src/world/generator/SurroundMap.cpp @@ -0,0 +1,117 @@ +#include "SurroundMap.hpp" + +#include +#include +#include + +void SurroundMap::resetMarks() { + for (auto& [_, entry] : entries) { + entry.marked = false; + } +} + +bool SurroundMap::createEntry(const glm::ivec2& origin) { + auto& entry = entries[origin]; + if (entry.confirmed) { + return false; + } + entry.confirmed = true; + + // calculate initial number of surrounding entries (any level) + int bitOffset = 0; + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + if (x == y && x == 0) { + continue; + } + const auto& found = entries.find(origin + glm::ivec2(x, y)); + if (found != entries.end()) { + entry.surrounding |= (1 << bitOffset); + if (found->second.level == 0) { + found->second.surrounding |= (1 << (7 - bitOffset)); + } + } + bitOffset++; + } + } + return true; +} + +std::vector SurroundMap::upgrade() { + std::vector expansion; + std::queue expanding; + for (const auto& [pos, entry] : entries) { + if (entry.confirmed && entry.surrounding != 0xFF) { + expanding.push(pos); + } + } + while (!expanding.empty()) { + assert(expanding.size() < 64); + + glm::ivec2 pos = expanding.front(); + expanding.pop(); + + const auto& found = entries.find(pos); + assert(found != entries.end() && "concurrent modification"); + + auto& entry = found->second; + int uplevelSurrounding = 0; + int bitOffset = 0; + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + if (x == y && x == 0) { + continue; + } + glm::ivec2 npos = {pos.x+x, pos.y+y}; + const auto& nfound = entries.find(npos); + + if (entry.surrounding & (1 << bitOffset)) { + auto& nentry = nfound->second; + if (nentry.level > entry.level) { + uplevelSurrounding |= (1 << bitOffset); + } + bitOffset++; + continue; + } + if (entry.level == 0) { + // neighbour entry does not exist + createEntry(npos); + expansion.push_back(npos); + } else{ + assert(nfound != entries.end() && "invalid map state"); + if (nfound->second.level == entry.level + 1) { + nfound->second.surrounding |= (1 << (7 - bitOffset)); + expanding.push(npos); + } + } + bitOffset++; + } + } + // level up + entry.surrounding = uplevelSurrounding; + entry.level++; + } + return expansion; +} + +void SurroundMap::getLevels(unsigned char* out, int width, int height, int ox, int oy) const { + std::memset(out, 0, width * height); + for (const auto& [pos, entry] : entries) { + int x = pos.x - ox; + int y = pos.y - oy; + if (x < 0 || x >= width || y < 0 || y >= height) { + continue; + } + + int surroundNum = 0; + for (int i = 0; i < 8; i++) { + if (entry.surrounding & (1 << i)) { + surroundNum++; + } + } + if (surroundNum) { + out[y * width + x] = surroundNum + 1; + } + out[y * width + x] = entry.level + 1; + } +} diff --git a/src/world/generator/SurroundMap.hpp b/src/world/generator/SurroundMap.hpp index 45713870..f8bca041 100644 --- a/src/world/generator/SurroundMap.hpp +++ b/src/world/generator/SurroundMap.hpp @@ -10,11 +10,13 @@ class SurroundMap { /// @brief Level is increased when all surrounding (8) entries having // greather or equal confirmed level int level = 0; - /// @brief number of surrounding entries having greather or equal - /// confirmed level - int surrounding = 0; + /// @brief bits storing surrounding entries having greather or equal + /// confirmed level. + /// 0 - is x=-1,y=-1 offset, 1 is x=0,y=-1, ... 7 is x=1,y=1 + /// (Prevents extra access to the entries hashmap) + uint8_t surrounding = 0x0; /// @brief level confirmed status (entry is ready to expand) - bool confirmed = true; + bool confirmed = false; /// @brief mark used on sweep event (extra isles garbage collection) bool marked = false; }; @@ -24,15 +26,22 @@ public: void resetMarks(); /// @brief Mark all connected entries - /// @param point origin point - void markIsle(const glm::ivec2& point); + /// @param origin origin point + void markIsle(const glm::ivec2& origin); /// @brief Erase all non-marked isles /// @return erased entries positions std::vector sweep(); - /// @brief Expand all confirmed entries with specified level + /// @brief Attempt to upgrade all confirmed entries with specified level /// @param level target entries level /// @return All upgraded entries positions - std::vector expand(int level); + std::vector upgrade(); + + /// @brief Create entry if does not exist + /// @param origin entry position + /// @return true if new entry has been created + bool createEntry(const glm::ivec2& origin); + + void getLevels(unsigned char* out, int width, int height, int ox, int oy) const; }; diff --git a/test/world/generator/SurroundMap.cpp b/test/world/generator/SurroundMap.cpp index ede9217f..b9e0bbb2 100644 --- a/test/world/generator/SurroundMap.cpp +++ b/test/world/generator/SurroundMap.cpp @@ -3,5 +3,11 @@ #include "world/generator/SurroundMap.hpp" TEST(SurroundMap, InitTest) { + int w = 8; + int h = 8; + SurroundMap map; + map.createEntry({w/2, h/2}); + map.createEntry({w/2+1, h/2+1}); + EXPECT_EQ(map.upgrade().size(), 12); }