diff --git a/src/coders/png.cpp b/src/coders/png.cpp index 19fd7937..d1be6da0 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -201,12 +201,12 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data, spng_set_ihdr(ctx, &ihdr); fmt = SPNG_FMT_PNG; - - ret = spng_encode_image(ctx, data, width * height , fmt, SPNG_ENCODE_FINALIZE); - + ret = spng_encode_image(ctx, data, (size_t)width * (size_t)height * pixsize , fmt, SPNG_ENCODE_FINALIZE); if (ret) { printf("spng_encode_image() error: %s\n", spng_strerror(ret)); - goto encode_error; + fflush(stdout); + spng_ctx_free(ctx); + return ret; } size_t png_size; @@ -218,9 +218,7 @@ int _png_write(const char* filename, uint width, uint height, const ubyte* data, else { files::write_bytes(filename, (const char*)png_buf, png_size); } - free(png_buf); - -encode_error: + fflush(stdout); spng_ctx_free(ctx); return ret; } diff --git a/src/engine.cpp b/src/engine.cpp index adb2cf0f..4f83b563 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -13,6 +13,7 @@ #include "window/Camera.h" #include "window/input.h" #include "graphics/Batch2D.h" +#include "graphics/ImageData.h" #include "world/World.h" #include "world/Level.h" #include "voxels/Chunk.h" @@ -23,8 +24,10 @@ #include "frontend/world_render.h" #include "frontend/hud.h" #include "frontend/gui/GUI.h" +#include "util/platform.h" #include "coders/json.h" +#include "coders/png.h" #include "files/files.h" using std::shared_ptr; @@ -73,6 +76,14 @@ void Engine::updateHotkeys() { if (Events::jpressed(keycode::O)) { occlusion = !occlusion; } + if (Events::jpressed(keycode::F2)) { + ImageData* image = Window::takeScreenshot(); + image->flipY(); + std::string filename = platform::get_screenshot_file("png"); + png::write_image(filename, image); + delete image; + std::cout << "saved screenshot as " << filename << std::endl; + } if (Events::jpressed(keycode::F3)) { level->player->debug = !level->player->debug; } diff --git a/src/graphics/ImageData.cpp b/src/graphics/ImageData.cpp index 318043ca..caf88c26 100644 --- a/src/graphics/ImageData.cpp +++ b/src/graphics/ImageData.cpp @@ -1,6 +1,7 @@ #include "ImageData.h" #include +#include inline int min(int a, int b) { return (a < b) ? a : b; @@ -23,7 +24,52 @@ ImageData::~ImageData() { } } -#include +void ImageData::flipX() { + uint size; + switch (format) { + case ImageFormat::rgb888: + case ImageFormat::rgba8888: { + size = (format == ImageFormat::rgba8888) ? 4 : 3; + ubyte* pixels = (ubyte*)data; + for (uint y = 0; y < height; y++) { + for (uint x = 0; x < width/2; x++) { + for (uint c = 0; c < size; c++) { + ubyte temp = pixels[(y * width + x) * size + c]; + pixels[(y * width + x) * size + c] = pixels[(y * width + (width - x - 1)) * size + c]; + pixels[(y * width + (width - x - 1)) * size + c] = temp; + } + } + } + break; + } + default: + throw std::runtime_error("format is not supported"); + } +} + +void ImageData::flipY() { + uint size; + switch (format) { + case ImageFormat::rgb888: + case ImageFormat::rgba8888: { + size = (format == ImageFormat::rgba8888) ? 4 : 3; + ubyte* pixels = (ubyte*)data; + for (uint y = 0; y < height/2; y++) { + for (uint x = 0; x < width; x++) { + for (uint c = 0; c < size; c++) { + ubyte temp = pixels[(y * width + x) * size + c]; + pixels[(y * width + x) * size + c] = pixels[((height-y-1) * width + x) * size + c]; + pixels[((height-y-1) * width + x) * size + c] = temp; + } + } + } + break; + } + default: + throw std::runtime_error("format is not supported"); + } +} + ImageData* add_atlas_margins(ImageData* image, int grid_size) { // RGBA is only supported assert(image->getFormat() == ImageFormat::rgba8888); diff --git a/src/graphics/ImageData.h b/src/graphics/ImageData.h index 87f2bb83..b236293d 100644 --- a/src/graphics/ImageData.h +++ b/src/graphics/ImageData.h @@ -17,6 +17,9 @@ public: ImageData(ImageFormat format, uint width, uint height, void* data); ~ImageData(); + void flipX(); + void flipY(); + void* getData() const { return data; } diff --git a/src/settings.h b/src/settings.h index 3b3b8f2c..77a7f235 100644 --- a/src/settings.h +++ b/src/settings.h @@ -15,7 +15,7 @@ struct DisplaySettings { /* GLFW swap interval value, 0 - unlimited fps, 1 - vsync*/ int swapInterval = 1; /* Window title */ - const char* title = "VoxelEngine-Cpp v0.13"; + const char* title = "VoxelEngine-Cpp v0.14"; }; struct ChunksSettings { diff --git a/src/util/platform.cpp b/src/util/platform.cpp index 60ff4be7..7cff5a7d 100644 --- a/src/util/platform.cpp +++ b/src/util/platform.cpp @@ -1,12 +1,46 @@ #include "platform.h" +#include +#include +#include +#include + +#include "../typedefs.h" + #define SETTINGS_FILE "settings.json" +#define SCREENSHOTS_FOLDER "screenshots" + +using std::string; -std::string platform::get_settings_file() { +string platform::get_settings_file() { return SETTINGS_FILE; } +string platform::get_screenshot_file(string ext) { + std::string folder = SCREENSHOTS_FOLDER; + if (!std::filesystem::is_directory(folder)) { + std::filesystem::create_directory(folder); + } + + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + + const char* format = "%d-%m-%Y_%H-%M-%S"; + + std::stringstream ss; + ss << std::put_time(&tm, format); + string datetimestr = ss.str(); + + string filename = folder+"/screenshot-"+datetimestr+"."+ext; + uint index = 0; + while (std::filesystem::exists(filename)) { + filename = folder+"/screenshot-"+datetimestr+"-"+std::to_string(index)+"."+ext; + index++; + } + return filename; +} + #ifdef WIN32 #include diff --git a/src/util/platform.h b/src/util/platform.h index a56e7d3a..948e0cf9 100644 --- a/src/util/platform.h +++ b/src/util/platform.h @@ -6,6 +6,7 @@ namespace platform { extern void configure_encoding(); extern std::string get_settings_file(); + extern std::string get_screenshot_file(std::string ext); } #endif // UTIL_PLATFORM_H_ \ No newline at end of file diff --git a/src/window/Window.cpp b/src/window/Window.cpp index 631a864c..dad4f119 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -1,6 +1,7 @@ #include #include "Window.h" #include "Events.h" +#include "../graphics/ImageData.h" #include #include @@ -180,4 +181,10 @@ void Window::swapBuffers(){ double Window::time() { return glfwGetTime(); +} + +ImageData* Window::takeScreenshot() { + ubyte* data = new ubyte[width * height * 3]; + glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); + return new ImageData(ImageFormat::rgb888, width, height, data); } \ No newline at end of file diff --git a/src/window/Window.h b/src/window/Window.h index fd5d2e01..fe25efa0 100644 --- a/src/window/Window.h +++ b/src/window/Window.h @@ -10,6 +10,7 @@ #include class GLFWwindow; +class ImageData; class Window { static GLFWwindow* window; @@ -33,8 +34,9 @@ public: static void resetScissor(); static void clear(); - static double time(); + + static ImageData* takeScreenshot(); }; #endif /* WINDOW_WINDOW_H_ */