Make region iteration more efficient for sparse worlds

Do not iterate over each region coordinate in the bounding box.

Closes #12
This commit is contained in:
Matthias Schiffer 2021-02-13 09:57:45 +01:00
parent c06af49068
commit 9ac3b00b6e
Signed by: neocturne
GPG key ID: 16EF3F64CB201D9C
2 changed files with 35 additions and 33 deletions

View file

@ -29,6 +29,7 @@
#include <climits>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <map>
#include <set>
#include <tuple>
@ -40,6 +41,8 @@ namespace MinedMap {
class Info {
public:
typedef std::function<void (int, int)> RegionVisitor;
struct Level {
std::map<int, std::set<int>> regions;
std::tuple<int, int, int, int> bounds;
@ -82,8 +85,12 @@ public:
});
}
size_t getMipmapLevel() const {
return levels.size()-1;
void visitRegions(size_t level, const RegionVisitor &visitor) const {
for (const auto &item : levels[level].regions) {
int z = item.first;
for (int x : item.second)
visitor(x, z);
}
}
void setSpawn(const std::pair<int32_t, int32_t> &v) {

View file

@ -292,13 +292,9 @@ static void makeBiome(const std::string &regiondir, const std::string &outputdir
}
static void makeBiomes(const std::string &regiondir, const std::string &outputdir, const Info *info) {
int minX, maxX, minZ, maxZ;
std::tie(minX, maxX, minZ, maxZ) = info->getBounds(0);
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++)
info->visitRegions(0, [&] (int x, int z) {
makeBiome(regiondir, outputdir, x, z);
}
});
}
static void makeMap(const std::string &regiondir, const std::string &outputdir, int x, int z) {
@ -356,13 +352,9 @@ static void makeMap(const std::string &regiondir, const std::string &outputdir,
}
static void makeMaps(const std::string &regiondir, const std::string &outputdir, const Info *info) {
int minX, maxX, minZ, maxZ;
std::tie(minX, maxX, minZ, maxZ) = info->getBounds(0);
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++)
info->visitRegions(0, [&] (int x, int z) {
makeMap(regiondir, outputdir, x, z);
}
});
}
static bool makeMipmap(const std::string &dir, size_t level, int x, int z, PNG::Format imageFormat) {
@ -432,29 +424,32 @@ static bool makeMipmap(const std::string &dir, size_t level, int x, int z, PNG::
return true;
}
static int floored_half(int a) {
return (a - (a < 0)) / 2;
}
static void makeMipmaps(const std::string &dir, Info *info) {
for (size_t level = 0; ; level++) {
int minX, maxX, minZ, maxZ;
std::tie(minX, maxX, minZ, maxZ) = info->getBounds(0);
std::tie(minX, maxX, minZ, maxZ) = info->getBounds(level);
if (minX >= -1 && maxX <= 0 && minZ >= -1 && maxZ <= 0)
break;
while (minX < -1 || maxX > 0 || minZ < -1 || maxZ > 0) {
info->addMipmapLevel();
size_t level = info->getMipmapLevel();
makeDir(dir + "/map/" + format(level));
makeDir(dir + "/light/" + format(level));
makeDir(dir + "/map/" + format(level + 1));
makeDir(dir + "/light/" + format(level + 1));
minX = (minX-1)/2;
maxX = maxX/2;
minZ = (minZ-1)/2;
maxZ = maxZ/2;
info->visitRegions(level, [&] (int x, int z) {
info->addRegion(floored_half(x), floored_half(z), level + 1);
});
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
if (makeMipmap(dir + "/map", level, x, z, PNG::RGB_ALPHA))
info->addRegion(x, z, level);
info->visitRegions(level + 1, [&] (int x, int z) {
if (makeMipmap(dir + "/map", level + 1, x, z, PNG::RGB_ALPHA))
info->addRegion(x, z, level + 1);
makeMipmap(dir + "/light", level, x, z, PNG::GRAY_ALPHA);
}
}
makeMipmap(dir + "/light", level + 1, x, z, PNG::GRAY_ALPHA);
});
}
}