From e1b3347da56110563324b7b1afb0c38a9d172732 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 3 Feb 2015 12:41:47 +0100 Subject: Start mipmapping infrastructure --- src/MinedMap.cpp | 27 ++++++++++++++--- src/PNG.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/PNG.hpp | 6 +++- viewer/MinedMap.js | 2 +- 4 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/MinedMap.cpp b/src/MinedMap.cpp index 2cd90d4..bf6f4fb 100644 --- a/src/MinedMap.cpp +++ b/src/MinedMap.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -46,8 +47,7 @@ #include -using namespace MinedMap; - +namespace MinedMap { static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE; @@ -85,7 +85,7 @@ static void doRegion(const std::string &input, const std::string &output) { uint32_t image[DIM*DIM] = {}; World::Region::visitChunks(input.c_str(), [&image] (size_t X, size_t Z, const World::Chunk *chunk) { addChunk(image, X, Z, chunk); }); - writePNG(tmpfile.c_str(), image, DIM, DIM); + PNG::write(tmpfile.c_str(), reinterpret_cast(image), DIM, DIM); struct timespec times[2] = {instat.st_mtim, instat.st_mtim}; if (utimensat(AT_FDCWD, tmpfile.c_str(), times, 0) < 0) @@ -116,7 +116,21 @@ static bool checkFilename(const char *name, int *x, int *z) { } +static void makeDir(const std::string &name) { + if (mkdir(name.c_str(), 0777) < 0 && errno != EEXIST) + throw std::system_error(errno, std::generic_category(), "unable to create directory " + name); +} + +static void makeMipmaps(const std::string &outputdir, const Info &info) { +} + +} + + int main(int argc, char *argv[]) { + using namespace MinedMap; + + if (argc < 3) { std::fprintf(stderr, "Usage: %s \n", argv[0]); return 1; @@ -126,6 +140,9 @@ int main(int argc, char *argv[]) { std::string regiondir = inputdir + "/region"; std::string outputdir(argv[2]); + std::string regionoutdir = outputdir + "/0"; + + makeDir(regionoutdir); DIR *dir = opendir(regiondir.c_str()); if (!dir) { @@ -144,7 +161,7 @@ int main(int argc, char *argv[]) { info.addRegion(x, z); std::string name(entry->d_name); - doRegion(regiondir + "/" + name, outputdir + "/" + name.substr(0, name.length()-3) + "png"); + doRegion(regiondir + "/" + name, regionoutdir + "/" + name.substr(0, name.length()-3) + "png"); } closedir(dir); @@ -152,6 +169,8 @@ int main(int argc, char *argv[]) { World::Level level((inputdir + "/level.dat").c_str()); info.setSpawn(level.getSpawn()); + makeMipmaps(outputdir, info); + info.writeJSON((outputdir + "/info.json").c_str()); return 0; diff --git a/src/PNG.cpp b/src/PNG.cpp index 1e25712..0154f61 100644 --- a/src/PNG.cpp +++ b/src/PNG.cpp @@ -28,17 +28,19 @@ #include #include +#include #include #include namespace MinedMap { +namespace PNG { -void writePNG(const char *filename, const uint32_t *data, size_t width, size_t height) { +void write(const char *filename, const uint8_t *data, size_t width, size_t height) { std::FILE *f = std::fopen(filename, "wb"); if (!f) - throw std::system_error(errno, std::generic_category(), "unable to open output file"); + throw std::system_error(errno, std::generic_category(), "unable to open PNG file"); png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) @@ -63,13 +65,88 @@ void writePNG(const char *filename, const uint32_t *data, size_t width, size_t h uint8_t *row_pointers[height]; for (size_t i = 0; i < height; i++) - row_pointers[i] = const_cast(reinterpret_cast(&data[i*width])); + row_pointers[i] = const_cast(&data[4*i*width]); png_set_rows(png_ptr, info_ptr, row_pointers); - png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); png_destroy_write_struct(&png_ptr, &info_ptr); std::fclose(f); } +void read(const char *filename, uint8_t *data, size_t width, size_t height) { + std::FILE *f = std::fopen(filename, "rb"); + if (!f) + throw std::system_error(errno, std::generic_category(), "unable to open PNG file"); + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) + throw std::runtime_error("unable to create PNG read struct"); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + throw std::runtime_error("unable to create PNG info struct"); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw std::runtime_error("unable to create PNG info struct"); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(f); + throw std::runtime_error("unable to read PNG file"); + } + + png_init_io(png_ptr, f); + + png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); + + if (png_get_image_width(png_ptr, info_ptr) != width + || png_get_image_height(png_ptr, info_ptr) != height + || png_get_bit_depth(png_ptr, info_ptr) != 8 + || png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_RGB_ALPHA) + longjmp(png_jmpbuf(png_ptr), 1); + + uint8_t **row_pointers = png_get_rows(png_ptr, info_ptr); + for (size_t i = 0; i < height; i++) + std::memcpy(&data[4*i*width], row_pointers[i], 4*width); + + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + std::fclose(f); +} + +static void readScaled(uint8_t *data, size_t offset_w, size_t offset_h, const char *file, size_t width, size_t height) { + if (!file) + return; + + uint8_t input[4*width*height]; + read(file, input, width, height); + + for (size_t h = 0; h < width/2; h++) { + for (size_t w = 0; w < width/2; w++) { + for (size_t c = 0; c < 4; c++) { + size_t i = 8*width*h + 8*w + c; + data[4*width*(offset_h+h) + 4*(offset_w+w) + c] = (input[i] + input[i+4] + input[i+4*width] + input[i+4*width+4])/4; + } + } + } +} + +void mipmap(const char *output, size_t width, size_t height, const char *nw, const char *ne, const char *sw, const char *se) { + uint8_t data[4*width*height]; + std::memset(data, 0, sizeof(data)); + + readScaled(data, 0, 0, nw, width, height); + readScaled(data, width/2, 0, ne, width, height); + readScaled(data, 0, height/2, sw, width, height); + readScaled(data, width/2, height/2, se, width, height); + + write(output, data, width, height); +} + +} } diff --git a/src/PNG.hpp b/src/PNG.hpp index 62a9437..1647d03 100644 --- a/src/PNG.hpp +++ b/src/PNG.hpp @@ -31,7 +31,11 @@ namespace MinedMap { +namespace PNG { -void writePNG(const char *filename, const uint32_t *data, size_t width, size_t height); +void write(const char *filename, const uint8_t *data, size_t width, size_t height); +void read(const char *filename, uint8_t *data, size_t width, size_t height); +void mipmap(const char *output, size_t width, size_t height, const char *nw, const char *ne, const char *sw, const char *se); } +} diff --git a/viewer/MinedMap.js b/viewer/MinedMap.js index 959e3ed..464bd22 100644 --- a/viewer/MinedMap.js +++ b/viewer/MinedMap.js @@ -21,7 +21,7 @@ var MinedMapLayer = L.GridLayer.extend({ if (coords.x >= this._info.minX && coords.x <= this._info.maxX && coords.y >= this._info.minZ && coords.y <= this._info.maxZ && this._regions[coords.y-this._info.minZ][coords.x-this._info.minX]) - tile.src = 'data/r.'+coords.x+'.'+coords.y+'.png'; + tile.src = 'data/0/r.'+coords.x+'.'+coords.y+'.png'; return tile; }, -- cgit v1.2.3