From 8c1629af42a10ff7e23bb40100a259bf334a9c60 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 2 Feb 2015 01:41:17 +0100 Subject: Change region reader to a visitor pattern Not keeping the whole region in memory reduces the needed space to less than 5MB (from about 140). --- src/MinedMap.cpp | 33 +++++++++++++++------------------ src/World/Region.cpp | 13 +++++++++---- src/World/Region.hpp | 16 ++++++---------- 3 files changed, 30 insertions(+), 32 deletions(-) (limited to 'src') diff --git a/src/MinedMap.cpp b/src/MinedMap.cpp index f9f9736..3af634d 100644 --- a/src/MinedMap.cpp +++ b/src/MinedMap.cpp @@ -40,7 +40,19 @@ using namespace MinedMap; -static void writePNG(const char *filename, const uint32_t data[World::Region::SIZE*World::Chunk::SIZE][World::Region::SIZE*World::Chunk::SIZE]) { +static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE; + + +static void addChunk(uint32_t image[DIM][DIM], size_t X, size_t Z, const World::Chunk *chunk) { + World::Chunk::Blocks layer = chunk->getTopLayer(); + + for (size_t x = 0; x < World::Chunk::SIZE; x++) { + for (size_t z = 0; z < World::Chunk::SIZE; z++) + image[Z*World::Chunk::SIZE+z][X*World::Chunk::SIZE+x] = htonl(layer.blocks[x][z].getColor()); + } +} + +static void writePNG(const char *filename, const uint32_t data[DIM][DIM]) { std::FILE *f = std::fopen(filename, "wb"); if (!f) throw std::system_error(errno, std::generic_category(), "unable to open output file"); @@ -82,24 +94,9 @@ int main(int argc, char *argv[]) { return 1; } - World::Region region(argv[1]); - - uint32_t image[World::Region::SIZE*World::Chunk::SIZE][World::Region::SIZE*World::Chunk::SIZE] = {}; - - for (size_t X = 0; X < World::Region::SIZE; X++) { - for (size_t Z = 0; Z < World::Region::SIZE; Z++) { - const World::Chunk *chunk = region(X, Z); - if (!chunk) - continue; + uint32_t image[DIM][DIM] = {}; - World::Chunk::Blocks layer = chunk->getTopLayer(); - - for (size_t x = 0; x < World::Chunk::SIZE; x++) { - for (size_t z = 0; z < World::Chunk::SIZE; z++) - image[Z*World::Chunk::SIZE+z][X*World::Chunk::SIZE+x] = htonl(layer.blocks[x][z].getColor()); - } - } - } + World::Region::visitChunks(argv[1], [&image] (size_t X, size_t Z, const World::Chunk *chunk) { addChunk(image, X, Z, chunk); }); writePNG(argv[2], image); diff --git a/src/World/Region.cpp b/src/World/Region.cpp index fec732c..4551d73 100644 --- a/src/World/Region.cpp +++ b/src/World/Region.cpp @@ -54,7 +54,7 @@ Region::ChunkMap Region::processHeader(const uint8_t header[4096]) { return map; } -Region::Region(const char *filename) { +void Region::visitChunks(const char *filename, ChunkVisitor visitor) { std::ifstream file; file.exceptions(std::ios::failbit | std::ios::badbit); file.open(filename, std::ios::in | std::ios::binary); @@ -68,6 +68,8 @@ Region::Region(const char *filename) { chunkMap = processHeader(header); } + bool seen[SIZE][SIZE] = {}; + size_t i = 1, c = 0; while (!file.eof()) { auto it = chunkMap.find(i); @@ -80,16 +82,19 @@ Region::Region(const char *filename) { size_t x, z, len; std::tie(x, z, len) = it->second; - if (chunks[x][z]) + if (seen[x][z]) throw std::invalid_argument("duplicate chunk"); + seen[x][z] = true; + c++; + uint8_t buffer[len * 4096]; file.read((char *)buffer, len * 4096); - chunks[x][z].reset(new Chunk(Buffer(buffer, len * 4096))); + Chunk chunk(Buffer(buffer, len * 4096)); + visitor(x, z, &chunk); i += len; - c++; } if (c != chunkMap.size()) diff --git a/src/World/Region.hpp b/src/World/Region.hpp index 0843724..d88dbe1 100644 --- a/src/World/Region.hpp +++ b/src/World/Region.hpp @@ -28,6 +28,7 @@ #include "Chunk.hpp" +#include #include #include #include @@ -41,23 +42,18 @@ class Region { public: static const size_t SIZE = 32; + typedef std::function ChunkVisitor; + + Region() = delete; + private: typedef std::tuple ChunkDesc; typedef std::unordered_map ChunkMap; - std::unique_ptr chunks[SIZE][SIZE]; - static ChunkMap processHeader(const uint8_t header[4096]); public: - Region(const char *filename); - - const Chunk * operator()(size_t x, size_t z) { - if (x >= SIZE || z >= SIZE) - throw std::range_error("Region(): bad coordinates"); - - return chunks[x][z].get(); - } + static void visitChunks(const char *filename, ChunkVisitor visitor); }; } -- cgit v1.2.3