From 7d9df41be4aa029fda62efed1a0af194721b8902 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 29 Sep 2021 13:30:42 +0200 Subject: [PATCH] Add screenshot key --- .gitignore | 1 + README.md | 3 +- snapshot.sh | 2 +- src/client/game.c | 131 +++++++++++++++++++++++++++++++++++--------- src/client/game.h | 2 + src/client/input.c | 7 +++ src/client/window.c | 2 + 7 files changed, 119 insertions(+), 29 deletions(-) diff --git a/.gitignore b/.gitignore index 21e15f0..0d0a330 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ Dragonblocks world.sqlite DragonblocksAlpha-*.zip src/version.h +screenshot-*.png diff --git a/README.md b/README.md index 3b58989..74a1626 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,9 @@ or alternatively: | F | Toggle flight | | C | Toggle collision | | T | Toggle timelapse | -| F11 | Toggle fullscreen | +| F2 | Take screenshot | | F3 | Toggle debug info | +| F11 | Toggle fullscreen | | ESC | Pause / unpause game | ## Dependencies diff --git a/snapshot.sh b/snapshot.sh index 06df6c6..55be6de 100755 --- a/snapshot.sh +++ b/snapshot.sh @@ -11,7 +11,7 @@ if ! (cmake -B . -S ../src -DCMAKE_BUILD_TYPE=Release && make clean && make -j$( fi cp Dragonblocks DragonblocksServer .. cd .. -rm -rf .git* deps src build BUILDING.md snapshot.sh upload.sh DragonblocksAlpha-*.zip +rm -rf .git* deps src build BUILDING.md snapshot.sh upload.sh DragonblocksAlpha-*.zip screenshot-*.png cd .. mv .build DragonblocksAlpha VERSION=`git tag --points-at HEAD` diff --git a/src/client/game.c b/src/client/game.c index e9dbebc..0f66bf0 100644 --- a/src/client/game.c +++ b/src/client/game.c @@ -3,6 +3,8 @@ #include #include #include +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include #include "client/camera.h" #include "client/client.h" #include "client/client_map.h" @@ -17,6 +19,8 @@ #include "day.h" #include "signal_handlers.h" +int window_width, window_height; + static void crosshair_init() { gui_add(&gui_root, (GUIElementDefinition) { @@ -35,6 +39,29 @@ static void crosshair_init() }); } +static void render() +{ + glEnable(GL_DEPTH_TEST); + glEnable(GL_ALPHA_TEST); + glEnable(GL_BLEND); + glEnable(GL_MULTISAMPLE); + glEnable(GL_CULL_FACE); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glAlphaFunc(GL_GREATER, 0.0f); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + scene_render(); + + glDisable(GL_CULL_FACE); + sky_render(); + + glDisable(GL_DEPTH_TEST); + gui_render(); +} + static void game_loop(Client *client) { f64 fps_update_timer = 1.0f; @@ -56,31 +83,14 @@ static void game_loop(Client *client) frames++; - debug_menu_update_time(); - debug_menu_update_daylight(); - debug_menu_update_sun_angle(); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_ALPHA_TEST); - glEnable(GL_BLEND); - glEnable(GL_MULTISAMPLE); - glEnable(GL_CULL_FACE); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glAlphaFunc(GL_GREATER, 0.0f); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - input_tick(); client_player_tick(dtime); - scene_render(); - - glDisable(GL_CULL_FACE); - sky_render(); + debug_menu_update_time(); + debug_menu_update_daylight(); + debug_menu_update_sun_angle(); - glDisable(GL_DEPTH_TEST); - gui_render(); + render(); glfwSwapBuffers(window.handle); glfwPollEvents(); @@ -89,11 +99,10 @@ static void game_loop(Client *client) bool game(Client *client) { - int width, height; - width = 1250; - height = 750; + window_width = 1250; + window_height = 750; - if (! window_init(width, height)) + if (! window_init(window_width, window_height)) return false; if (! font_init()) @@ -102,7 +111,7 @@ bool game(Client *client) if (! scene_init()) return false; - scene_on_resize(width, height); + scene_on_resize(window_width, window_height); if (! sky_init()) return false; @@ -116,7 +125,7 @@ bool game(Client *client) if (! gui_init()) return false; - gui_on_resize(width, height); + gui_on_resize(window_width, window_height); debug_menu_init(); debug_menu_toggle(); @@ -147,3 +156,71 @@ bool game(Client *client) return true; } + +void take_screenshot() +{ + // renderbuffer for depth & stencil buffer + GLuint RBO; + glGenRenderbuffers(1, &RBO); + glBindRenderbuffer(GL_RENDERBUFFER, RBO); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window_width, window_height); + + // 2 textures, one with AA, one without + + GLuint textures[2]; + glGenTextures(2, textures); + + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textures[0]); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window_width, window_height, GL_TRUE); + + glBindTexture(GL_TEXTURE_2D, textures[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + // 2 framebuffers, one with AA, one without + + GLuint FBOs[2]; + glGenFramebuffers(2, FBOs); + + glBindFramebuffer(GL_FRAMEBUFFER, FBOs[0]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textures[0], 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, RBO); + + glBindFramebuffer(GL_FRAMEBUFFER, FBOs[1]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0); + + // render scene + glBindFramebuffer(GL_FRAMEBUFFER, FBOs[0]); + render(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // blit AA-buffer into no-AA buffer + glBindFramebuffer(GL_READ_FRAMEBUFFER, FBOs[0]); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBOs[1]); + glBlitFramebuffer(0, 0, window_width, window_height, 0, 0, window_width, window_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // read data + GLubyte data[window_width * window_height * 3]; + glBindFramebuffer(GL_FRAMEBUFFER, FBOs[1]); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, window_width, window_height, GL_RGB, GL_UNSIGNED_BYTE, data); + + // create filename + char filename[BUFSIZ]; + time_t timep = time(0); + strftime(filename, BUFSIZ, "screenshot-%Y-%m-%d-%H:%M:%S.png", localtime(&timep)); + + // save screenshot + stbi_flip_vertically_on_write(true); + stbi_write_png(filename, window_width, window_height, 3, data, window_width * 3); + + // delete buffers + glDeleteRenderbuffers(1, &RBO); + glDeleteTextures(2, textures); + glDeleteFramebuffers(2, FBOs); +} + +void game_on_resize(int width, int height) +{ + window_width = width; + window_height = height; +} diff --git a/src/client/game.h b/src/client/game.h index ad4bb05..9941264 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -4,5 +4,7 @@ #include "client/client.h" bool game(Client *client); +void take_screenshot(); +void game_on_resize(int width, int height); #endif diff --git a/src/client/input.c b/src/client/input.c index 063e34b..687d6f3 100644 --- a/src/client/input.c +++ b/src/client/input.c @@ -3,6 +3,7 @@ #include "client/client.h" #include "client/client_player.h" #include "client/debug_menu.h" +#include "client/game.h" #include "client/gui.h" #include "client/input.h" #include "client/window.h" @@ -25,6 +26,7 @@ static struct KeyListener collision_listener; KeyListener timelapse_listener; KeyListener debug_menu_listener; + KeyListener screenshot_listener; } input; void input_on_cursor_pos(double current_x, double current_y) @@ -120,6 +122,7 @@ void input_tick() do_key_listener(&input.collision_listener); do_key_listener(&input.timelapse_listener); do_key_listener(&input.debug_menu_listener); + do_key_listener(&input.screenshot_listener); if (input.fly_listener.fired) { client_player.fly = ! client_player.fly; @@ -140,6 +143,9 @@ void input_tick() if (input.debug_menu_listener.fired) debug_menu_toggle(); + + if (input.screenshot_listener.fired) + take_screenshot(); } client_player.velocity.x = 0.0f; @@ -169,6 +175,7 @@ void input_init() input.collision_listener = create_key_listener(GLFW_KEY_C); input.timelapse_listener = create_key_listener(GLFW_KEY_T); input.debug_menu_listener = create_key_listener(GLFW_KEY_F3); + input.screenshot_listener = create_key_listener(GLFW_KEY_F2); input.pause_menu = gui_add(&gui_root, (GUIElementDefinition) { .pos = {0.0f, 0.0f}, diff --git a/src/client/window.c b/src/client/window.c index 15c7aee..29cab14 100644 --- a/src/client/window.c +++ b/src/client/window.c @@ -2,6 +2,7 @@ #include #include #include "client/debug_menu.h" +#include "client/game.h" #include "client/gui.h" #include "client/input.h" #include "client/scene.h" @@ -21,6 +22,7 @@ static void framebuffer_size_callback(unused GLFWwindow *handle, int width, int scene_on_resize(width, height); gui_on_resize(width, height); + game_on_resize(width, height); } static void cursor_pos_callback(unused GLFWwindow *handle, double current_x, double current_y) -- 2.44.0