From 0da0139fcefb8c1e673802828c6fa2e58623e518 Mon Sep 17 00:00:00 2001 From: xtreme8000 Date: Sun, 24 Sep 2023 15:48:47 +0200 Subject: [PATCH] Screenshot feature --- config.json | 3 ++- config_pc.json | 3 ++- source/main.c | 21 +++++++++++++++-- source/platform/gfx.h | 2 ++ source/platform/input.c | 1 + source/platform/input.h | 1 + source/platform/pc/gfx.c | 27 +++++++++++++++++++++ source/platform/wii/gfx.c | 49 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 103 insertions(+), 4 deletions(-) diff --git a/config.json b/config.json index 6970748..af279c6 100644 --- a/config.json +++ b/config.json @@ -21,6 +21,7 @@ "gui_left": [2, 202], "gui_right": [3, 203], "gui_click": [4, 204], - "gui_click_alt": [5, 205] + "gui_click_alt": [5, 205], + "screenshot": [7], } } diff --git a/config_pc.json b/config_pc.json index 5a9c8b4..99a793d 100644 --- a/config_pc.json +++ b/config_pc.json @@ -21,6 +21,7 @@ "gui_left": [65], "gui_right": [68], "gui_click": [1000], - "gui_click_alt": [1001] + "gui_click_alt": [1001], + "screenshot": [291] } } diff --git a/source/main.c b/source/main.c index 7952cea..12e13d2 100644 --- a/source/main.c +++ b/source/main.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef PLATFORM_WII #include @@ -42,10 +43,9 @@ #include "cNBT/nbt.h" #include "cglm/cglm.h" +#include "lodepng/lodepng.h" int main(void) { - time_reset(); - gstate.quit = false; gstate.camera = (struct camera) { .x = 0, .y = 0, .z = 0, .rx = 0, .ry = 0, .controller = {0, 0, 0}}; @@ -183,6 +183,23 @@ int main(void) { gstate.current_screen->render2D(gstate.current_screen, gfx_width(), gfx_height()); + if(input_pressed(IB_SCREENSHOT)) { + size_t width, height; + gfx_copy_framebuffer(NULL, &width, &height); + + void* image = malloc(width * height * 4); + + if(image) { + gfx_copy_framebuffer(image, &width, &height); + + char name[64]; + snprintf(name, sizeof(name), "%ld.png", (long)time(NULL)); + + lodepng_encode32_file(name, image, width, height); + free(image); + } + } + input_poll(); gfx_finish(true); } diff --git a/source/platform/gfx.h b/source/platform/gfx.h index c622f8f..2547478 100644 --- a/source/platform/gfx.h +++ b/source/platform/gfx.h @@ -54,6 +54,8 @@ void gfx_clear_buffers(uint8_t r, uint8_t g, uint8_t b); int gfx_width(void); int gfx_height(void); +void gfx_copy_framebuffer(uint8_t* dest, size_t* width, size_t* height); + void gfx_matrix_projection(mat4 proj, bool is_perspective); void gfx_matrix_modelview(mat4 mv); void gfx_matrix_texture(bool enable, mat4 tex); diff --git a/source/platform/input.c b/source/platform/input.c index cc3de78..41eefa1 100644 --- a/source/platform/input.c +++ b/source/platform/input.c @@ -303,6 +303,7 @@ static const char* input_config_translate(enum input_button key) { case IB_GUI_RIGHT: return "input.gui_right"; case IB_GUI_CLICK: return "input.gui_click"; case IB_GUI_CLICK_ALT: return "input.gui_click_alt"; + case IB_SCREENSHOT: return "input.screenshot"; default: return NULL; } } diff --git a/source/platform/input.h b/source/platform/input.h index 73a2b8b..aa812db 100644 --- a/source/platform/input.h +++ b/source/platform/input.h @@ -41,6 +41,7 @@ enum input_button { IB_GUI_RIGHT, IB_GUI_CLICK, IB_GUI_CLICK_ALT, + IB_SCREENSHOT, }; enum input_category { diff --git a/source/platform/pc/gfx.c b/source/platform/pc/gfx.c index 4d99486..cc5e2dc 100644 --- a/source/platform/pc/gfx.c +++ b/source/platform/pc/gfx.c @@ -206,6 +206,33 @@ void gfx_bind_texture(struct tex_gfx* tex) { tex_gfx_bind(tex, 0); } +void gfx_copy_framebuffer(uint8_t* dest, size_t* width, size_t* height) { + assert(width && height); + + *width = gfx_width(); + *height = gfx_height(); + + if(!dest) + return; + + void* tmp = malloc(*width * 4); + + if(!tmp) + return; + + glReadPixels(0, 0, *width, *height, GL_RGBA, GL_UNSIGNED_BYTE, dest); + + // flip image + for(size_t y = 0; y < *height / 2; y++) { + memcpy(tmp, dest + y * (*width) * 4, *width * 4); + memcpy(dest + y * (*width) * 4, dest + (*height - 1 - y) * (*width) * 4, + *width * 4); + memcpy(dest + (*height - 1 - y) * (*width) * 4, tmp, *width * 4); + } + + free(tmp); +} + void gfx_mode_world() { gfx_write_buffers(true, true, true); gfx_matrix_texture(false, NULL); diff --git a/source/platform/wii/gfx.c b/source/platform/wii/gfx.c index b82205c..a87ce8b 100644 --- a/source/platform/wii/gfx.c +++ b/source/platform/wii/gfx.c @@ -252,6 +252,55 @@ void gfx_bind_texture(struct tex_gfx* tex) { tex_gfx_bind(tex, GX_TEXMAP0); } +void gfx_copy_framebuffer(uint8_t* dest, size_t* width, size_t* height) { + assert(width && height); + + *width = screenMode->fbWidth; + *height = screenMode->efbHeight; + + if(!dest) + return; + + size_t length + = GX_GetTexBufferSize(*width, *height, GX_TF_RGBA8, GX_FALSE, 0); + uint8_t* buffer = memalign(32, length); + + if(!buffer) + return; + + GX_SetTexCopySrc(0, 0, *width, *height); + GX_SetTexCopyDst(*width, *height, GX_TF_RGBA8, GX_FALSE); + GX_CopyTex(buffer, GX_FALSE); + GX_PixModeSync(); + GX_SetDrawDone(); + DCInvalidateRange(buffer, length); + GX_WaitDrawDone(); + + uint8_t* src = buffer; + + for(size_t y = 0; y < *height; y += 4) { + for(size_t x = 0; x < *width; x += 4) { + for(size_t by = 0; by < 4; by++) { + for(size_t bx = 0; bx < 4; bx++) { + uint8_t* col = dest + (x + bx + (y + by) * (*width)) * 4; + col[3] = *(src++); + col[0] = *(src++); + } + } + + for(size_t by = 0; by < 4; by++) { + for(size_t bx = 0; bx < 4; bx++) { + uint8_t* col = dest + (x + bx + (y + by) * (*width)) * 4; + col[1] = *(src++); + col[2] = *(src++); + } + } + } + } + + free(buffer); +} + void gfx_mode_world() { gfx_write_buffers(true, true, true); }