diff options
-rw-r--r-- | core.c | 4 | ||||
-rw-r--r-- | core.h | 1 | ||||
-rw-r--r-- | main.c | 119 | ||||
-rw-r--r-- | main.h | 2 | ||||
-rw-r--r-- | menu.c | 1 | ||||
-rw-r--r-- | plat_sdl.c | 9 |
6 files changed, 136 insertions, 0 deletions
@@ -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; @@ -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); @@ -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; @@ -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); @@ -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 } }; @@ -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) { } |