diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | default.cfg | 5 | ||||
-rw-r--r-- | io.c | 25 | ||||
-rw-r--r-- | ppm.c | 21 | ||||
-rw-r--r-- | ppm.h | 6 | ||||
-rw-r--r-- | render.h | 1 | ||||
-rwxr-xr-x | render_sdl.c | 40 |
7 files changed, 99 insertions, 1 deletions
@@ -128,7 +128,7 @@ Z80OBJS=z80inst.o z80_to_x86.o AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o -MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o menu.o xband.o realtec.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) +MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o render_sdl.o ppm.o io.o romdb.o menu.o xband.o realtec.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) ifeq ($(CPU),x86_64) CFLAGS+=-DX86_64 -m64 diff --git a/default.cfg b/default.cfg index f3a4432..7a5edcd 100644 --- a/default.cfg +++ b/default.cfg @@ -18,6 +18,7 @@ bindings { [ ui.vdp_debug_mode ] ui.vdp_debug_pal u ui.enter_debugger + p ui.screenshot esc ui.exit ` ui.save_state 0 ui.set_speed.0 @@ -187,6 +188,10 @@ clocks { ui { rom menu.bin + #initial_path defaults to your home/user profile directory if not specified + #screenshot_path behaves the same way + #see strftime for the format specifiers valid in screenshot_template + screenshot_template blastem_%c.ppm } system { @@ -74,6 +74,7 @@ typedef enum { UI_TOGGLE_KEYBOARD_CAPTURE, UI_TOGGLE_FULLSCREEN, UI_SOFT_RESET, + UI_SCREENSHOT, UI_EXIT } ui_action; @@ -402,6 +403,10 @@ uint8_t keyboard_connected(sega_io *io) return is_keyboard(io->ports) || is_keyboard(io->ports+1) || is_keyboard(io->ports+2); } +#ifdef _WIN32 +#define localtime_r(a,b) localtime(a) +#endif + void handle_binding_up(keybinding * binding) { switch(binding->bind_type) @@ -491,6 +496,24 @@ void handle_binding_up(keybinding * binding) case UI_SOFT_RESET: current_system->soft_reset(current_system); break; + case UI_SCREENSHOT: { + char *screenshot_base = tern_find_path(config, "ui\0screenshot_path\0").ptrval; + if (!screenshot_base) { + screenshot_base = get_home_dir(); + } + time_t now = time(NULL); + struct tm local_store; + char fname_part[256]; + char *template = tern_find_path(config, "ui\0screenshot_template\0").ptrval; + if (!template) { + template = "blastem_%c.ppm"; + } + strftime(fname_part, sizeof(fname_part), template, localtime_r(&now, &local_store)); + char const *parts[] = {screenshot_base, PATH_SEP, fname_part}; + char *path = alloc_concat_m(3, parts); + render_save_screenshot(path); + break; + } case UI_EXIT: current_system->request_exit(current_system); break; @@ -665,6 +688,8 @@ int parse_binding_target(char * target, tern_node * padbuttons, tern_node *mouse *ui_out = UI_TOGGLE_FULLSCREEN; } else if (!strcmp(target + 3, "soft_reset")) { *ui_out = UI_SOFT_RESET; + } else if (!strcmp(target + 3, "screenshot")) { + *ui_out = UI_SCREENSHOT; } else if(!strcmp(target + 3, "exit")) { *ui_out = UI_EXIT; } else { @@ -0,0 +1,21 @@ +#include <stdint.h> +#include <stdio.h> + +void save_ppm(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch) +{ + fprintf(f, "P6\n%d %d\n255\n", width, height); + for(uint32_t y = 0; y < height; y++) + { + uint32_t *line = buffer; + for (uint32_t x = 0; x < width; x++, line++) + { + uint8_t buf[3] = { + *line >> 16, //red + *line >> 8, //green + *line //blue + }; + fwrite(buf, 1, sizeof(buf), f); + } + buffer = buffer + pitch / sizeof(uint32_t); + } +} @@ -0,0 +1,6 @@ +#ifndef PPM_H_ +#define PPM_H_ + +void save_ppm(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch); + +#endif //PPM_H_ @@ -70,6 +70,7 @@ typedef enum { #define RENDER_NOT_PLUGGED_IN -3 uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b); +void render_save_screenshot(char *path); uint32_t *render_get_framebuffer(uint8_t which, int *pitch); void render_framebuffer_updated(uint8_t which, int width); void render_init(int width, int height, char * title, uint8_t fullscreen); diff --git a/render_sdl.c b/render_sdl.c index f29c76e..e0fe476 100755 --- a/render_sdl.c +++ b/render_sdl.c @@ -12,6 +12,7 @@ #include "genesis.h" #include "io.h" #include "util.h" +#include "ppm.h" #ifndef DISABLE_OPENGL #include <GL/glew.h> @@ -488,6 +489,15 @@ void render_update_caption(char *title) fps_caption = NULL; } +static char *screenshot_path; +void render_save_screenshot(char *path) +{ + if (screenshot_path) { + free(screenshot_path); + } + screenshot_path = path; +} + uint32_t *locked_pixels; uint32_t locked_pitch; uint32_t *render_get_framebuffer(uint8_t which, int *pitch) @@ -538,6 +548,19 @@ void render_framebuffer_updated(uint8_t which, int width) uint32_t height = which <= FRAMEBUFFER_EVEN ? (video_standard == VID_NTSC ? 243 : 294) - (overscan_top[video_standard] + overscan_bot[video_standard]) : 240; + FILE *screenshot_file = NULL; + uint32_t shot_height; + if (screenshot_path && which == FRAMEBUFFER_ODD) { + screenshot_file = fopen(screenshot_path, "wb"); + if (screenshot_file) { + info_message("Saving screenshot to %s\n", screenshot_path); + } else { + warning("Failed to open screenshot file %s for writing\n", screenshot_path); + } + free(screenshot_path); + screenshot_path = NULL; + shot_height = video_standard == VID_NTSC ? 243 : 294; + } #ifndef DISABLE_OPENGL if (render_gl && which <= FRAMEBUFFER_EVEN) { glBindTexture(GL_TEXTURE_2D, textures[which]); @@ -568,6 +591,11 @@ void render_framebuffer_updated(uint8_t which, int width) glDisableVertexAttribArray(at_pos); SDL_GL_SwapWindow(main_window); + + if (screenshot_file) { + //properly supporting interlaced modes here is non-trivial, so only save the odd field for now + save_ppm(screenshot_file, texture_buf, width, shot_height, 320*sizeof(uint32_t)); + } } else { #endif if (which <= FRAMEBUFFER_EVEN && last != which) { @@ -586,6 +614,15 @@ void render_framebuffer_updated(uint8_t which, int width) } height = 480; } + if (screenshot_file) { + uint32_t shot_pitch = locked_pitch; + if (which == FRAMEBUFFER_EVEN) { + shot_height *= 2; + } else { + shot_pitch *= 2; + } + save_ppm(screenshot_file, locked_pixels, width, shot_height, shot_pitch); + } SDL_UnlockTexture(sdl_textures[which]); SDL_Rect src_clip = { .x = 0, @@ -598,6 +635,9 @@ void render_framebuffer_updated(uint8_t which, int width) #ifndef DISABLE_OPENGL } #endif + if (screenshot_file) { + fclose(screenshot_file); + } if (which <= FRAMEBUFFER_EVEN) { last = which; static uint32_t frame_counter, start; |