aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorneonloop2021-08-12 16:24:52 +0000
committerneonloop2021-08-12 16:24:52 +0000
commitb91949ebe7ccb6bed9b11d6229c4da8c20899c2c (patch)
tree23b0b19f5418b5ed1ef09864407ba87a01c31c9b
parent490f17e9bf7940f0e09eac66ff3c5a8d536f3624 (diff)
downloadpicoarch-b91949ebe7ccb6bed9b11d6229c4da8c20899c2c.tar.gz
picoarch-b91949ebe7ccb6bed9b11d6229c4da8c20899c2c.tar.bz2
picoarch-b91949ebe7ccb6bed9b11d6229c4da8c20899c2c.zip
Adds screenshot function
-rw-r--r--core.c4
-rw-r--r--core.h1
-rw-r--r--main.c119
-rw-r--r--main.h2
-rw-r--r--menu.c1
-rw-r--r--plat_sdl.c9
6 files changed, 136 insertions, 0 deletions
diff --git a/core.c b/core.c
index 37a2368..64741ae 100644
--- a/core.c
+++ b/core.c
@@ -55,6 +55,10 @@ void config_file_name(char *buf, size_t len, int is_game)
}
}
+void save_relative_path(char *buf, size_t len, const char *basename) {
+ snprintf(buf, len, "%s%s", save_dir, basename);
+}
+
void sram_write(void) {
char filename[MAX_PATH];
FILE *sram_file = NULL;
diff --git a/core.h b/core.h
index bd4ded9..aa3c776 100644
--- a/core.h
+++ b/core.h
@@ -37,6 +37,7 @@ extern unsigned audio_buffer_size_override;
extern int state_slot;
void config_file_name(char *buf, size_t len, int is_game);
+void save_relative_path(char *buf, size_t len, const char *basename);
void sram_read(void);
void sram_write(void);
diff --git a/main.c b/main.c
index b3998db..9a5effa 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,8 @@
+#include <png.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include "core.h"
#include "config.h"
#include "libpicofe/config_file.h"
@@ -23,6 +25,7 @@ unsigned current_audio_buffer_size;
char core_name[MAX_PATH];
char* content_path;
int config_override = 0;
+static int last_screenshot = 0;
static uint32_t vsyncs;
static uint32_t renders;
@@ -89,6 +92,119 @@ static void toggle_fast_forward(int force_off)
}
}
+static int screenshot_file_name(char *name, size_t len) {
+ char suffix[MAX_PATH];
+
+ for (int i = last_screenshot; i < 10000; i++) {
+ snprintf(suffix, MAX_PATH, "IMG_%04d.png", i);
+ save_relative_path(name, len, suffix);
+
+ if (access(name, F_OK) == -1) {
+ last_screenshot = i;
+ return 0;
+ }
+ }
+ *name = '\0';
+ return -1;
+}
+
+static int png_write_rgb565(const uint16_t *buf, png_structp png_ptr, int w, int h) {
+ png_byte *row_pointer = calloc(w * 3, sizeof(png_byte));
+ int ret = -1;
+
+ if (!row_pointer)
+ return ret;
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto finish;
+
+ for (int i = 0; i < h; i++) {
+ uint16_t *pbuf = &((uint16_t *)buf)[i * w];
+ png_byte *prow = row_pointer;
+
+ for (int j = 0; j < w; j++) {
+ uint16_t px = *pbuf++;
+ *prow++ = ((((px & 0xF800) >> 11) * 255 + 15) / 31);
+ *prow++ = ((((px & 0x07E0) >> 5) * 255 + 31) / 63);
+ *prow++ = ((((px & 0x001F)) * 255 + 15) / 31);
+ }
+ png_write_row(png_ptr, row_pointer);
+ }
+ ret = 0;
+
+finish:
+ if (row_pointer)
+ free(row_pointer);
+
+ return ret;
+}
+
+static int write_png(const uint16_t *buf, int w, int h, FILE *file) {
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ int ret = -1;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ goto finish;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ goto finish;
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto finish;
+
+ png_init_io(png_ptr, file);
+
+ png_set_IHDR(png_ptr, info_ptr, w, h, 8,
+ PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ png_write_info(png_ptr, info_ptr);
+
+ if (png_write_rgb565(buf, png_ptr, w, h))
+ goto finish;
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto finish;
+
+ png_write_end(png_ptr, info_ptr);
+ ret = 0;
+
+finish:
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return ret;
+}
+
+int screenshot(void) {
+ FILE *fp;
+ char filename[MAX_PATH];
+ int w, h;
+ void *buf = plat_prepare_screenshot(&w, &h, NULL);
+ int ret = -1;
+
+ if (screenshot_file_name(filename, MAX_PATH)) {
+ PA_ERROR("No available filename for screenshot\n");
+ return -1;
+ }
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ goto finish;
+
+ if (write_png(buf, w, h, fp))
+ goto finish;
+
+ PA_INFO("Wrote screenshot to %s\n", filename);
+ ret = 0;
+
+finish:
+ if (fp)
+ fclose(fp);
+ return ret;
+}
+
void set_defaults(void)
{
show_fps = 0;
@@ -271,6 +387,9 @@ void handle_emu_action(emu_action action)
case EACTION_TOGGLE_FF:
toggle_fast_forward(0);
break;
+ case EACTION_SCREENSHOT:
+ screenshot();
+ break;
case EACTION_QUIT:
should_quit = 1;
break;
diff --git a/main.h b/main.h
index 146db02..cf6025e 100644
--- a/main.h
+++ b/main.h
@@ -15,6 +15,7 @@ typedef enum {
EACTION_TOGGLE_FF,
EACTION_SAVE_STATE,
EACTION_LOAD_STATE,
+ EACTION_SCREENSHOT,
EACTION_QUIT,
} emu_action;
@@ -52,6 +53,7 @@ static inline bool has_suffix_i(const char *str, const char *suffix) {
#define PA_ERROR(...) pa_log(RETRO_LOG_ERROR, __VA_ARGS__)
#define PA_FATAL(...) do { pa_log(RETRO_LOG_ERROR, __VA_ARGS__); quit(-1); } while(0)
+int screenshot(void);
void set_defaults(void);
int save_config(int is_game);
diff --git a/menu.c b/menu.c
index 880dde5..d5e606a 100644
--- a/menu.c
+++ b/menu.c
@@ -109,6 +109,7 @@ me_bind_action emuctrl_actions[] =
{ "Load State ", 1 << EACTION_LOAD_STATE },
{ "Show/Hide FPS ", 1 << EACTION_TOGGLE_FPS },
{ "Toggle FF ", 1 << EACTION_TOGGLE_FF },
+ { "Take Screenshot ", 1 << EACTION_SCREENSHOT },
{ NULL, 0 }
};
diff --git a/plat_sdl.c b/plat_sdl.c
index 9467f5d..4726535 100644
--- a/plat_sdl.c
+++ b/plat_sdl.c
@@ -58,6 +58,15 @@ static void *fb_flip(void)
return screen->pixels;
}
+void *plat_prepare_screenshot(int *w, int *h, int *bpp)
+{
+ if (w) *w = SCREEN_WIDTH;
+ if (h) *h = SCREEN_HEIGHT;
+ if (bpp) *bpp = SCREEN_BPP;
+
+ return g_menuscreen_ptr;
+}
+
void plat_video_menu_enter(int is_rom_loaded)
{
}