diff --git a/scp.c b/scp.c index 1caac147..47a44c0e 100644 --- a/scp.c +++ b/scp.c @@ -1660,6 +1660,13 @@ ASSERT failure have several different actions: #define HLP_EXIT "*Commands Exiting_The_Simulator" "2Exiting The Simulator\n" " EXIT (synonyms QUIT and BYE) returns control to the operating system.\n" + /***************** 80 character line width template *************************/ +#define HLP_SCREENSHOT "*Commands Screenshot_Video_Window" + "2Screenshot Video Window\n" + " Simulators with Video devices display the simulated video in a window\n" + " on the local system. The contents of that display can be saved in a\n" + " file with the SCREENSHOT command:\n\n" + " SCREENSHOT screenshotfile.bmp\n" #define HLP_SPAWN "*Commands Executing_System_Commands" "2Executing System Commands\n" " The simulator can execute operating system commands with the ! (spawn)\n" @@ -1722,6 +1729,9 @@ static CTAB cmd_table[] = { { "NOEXPECT", &expect_cmd, 0, HLP_EXPECT }, { "!", &spawn_cmd, 0, HLP_SPAWN }, { "HELP", &help_cmd, 0, HLP_HELP }, +#if defined(USE_SIM_VIDEO) + { "SCREENSHOT", &screenshot_cmd,0, HLP_SCREENSHOT }, +#endif { NULL, NULL, 0 } }; @@ -2589,6 +2599,15 @@ printf ("\n"); return status; } +/* Screenshot command */ + +t_stat screenshot_cmd (int32 flag, char *cptr) +{ +if ((cptr == NULL) || (strlen (cptr) == 0)) + return SCPE_ARG; +return vid_screenshot (cptr); +} + /* Echo command */ t_stat echo_cmd (int32 flag, char *cptr) diff --git a/scp.h b/scp.h index a205335e..1d25c5e8 100644 --- a/scp.h +++ b/scp.h @@ -97,6 +97,7 @@ t_stat assert_cmd (int32 flag, char *ptr); t_stat send_cmd (int32 flag, char *ptr); t_stat expect_cmd (int32 flag, char *ptr); t_stat help_cmd (int32 flag, char *ptr); +t_stat screenshot_cmd (int32 flag, char *ptr); t_stat spawn_cmd (int32 flag, char *ptr); t_stat echo_cmd (int32 flag, char *ptr); diff --git a/sim_video.c b/sim_video.c index 739c2ad5..af1a68a7 100644 --- a/sim_video.c +++ b/sim_video.c @@ -65,15 +65,16 @@ char vid_release_key[64] = "Ctrl-Right-Shift"; */ -#define EVENT_REDRAW 1 /* redraw event for SDL */ -#define EVENT_CLOSE 2 /* close event for SDL */ -#define EVENT_CURSOR 3 /* new cursor for SDL */ -#define EVENT_WARP 4 /* warp mouse position for SDL */ -#define EVENT_DRAW 5 /* draw/blit region for SDL */ -#define EVENT_SHOW 6 /* show SDL capabilities */ -#define EVENT_OPEN 7 /* vid_open request */ -#define EVENT_EXIT 8 /* program exit */ -#define MAX_EVENTS 20 /* max events in queue */ +#define EVENT_REDRAW 1 /* redraw event for SDL */ +#define EVENT_CLOSE 2 /* close event for SDL */ +#define EVENT_CURSOR 3 /* new cursor for SDL */ +#define EVENT_WARP 4 /* warp mouse position for SDL */ +#define EVENT_DRAW 5 /* draw/blit region for SDL */ +#define EVENT_SHOW 6 /* show SDL capabilities */ +#define EVENT_OPEN 7 /* vid_open request */ +#define EVENT_EXIT 8 /* program exit */ +#define EVENT_SCREENSHOT 9 /* show SDL capabilities */ +#define MAX_EVENTS 20 /* max events in queue */ typedef struct { SIM_KEY_EVENT events[MAX_EVENTS]; @@ -94,6 +95,7 @@ typedef struct { int vid_thread (void* arg); int vid_video_events (void); void vid_show_video_event (void); +void vid_screenshot_event (void); /* libSDL and libSDL2 have significantly different APIs. @@ -187,8 +189,12 @@ while (1) { if (event.user.code == EVENT_SHOW) vid_show_video_event (); else { - sim_printf ("main(): Unexpected User event: %d\n", event.user.code); - break; + if (event.user.code == EVENT_SCREENSHOT) + vid_screenshot_event (); + else { + sim_printf ("main(): Unexpected User event: %d\n", event.user.code); + break; + } } } } @@ -1459,6 +1465,10 @@ if (0) while (SDL_PeepEvents (&event, 1, SDL_GETEVENT, SD vid_show_video_event (); event.user.code = 0; /* Mark as done */ } + if (event.user.code == EVENT_SCREENSHOT) { + vid_screenshot_event (); + event.user.code = 0; /* Mark as done */ + } if (event.user.code != 0) { sim_printf ("vid_thread(): Unexpected user event code: %d\n", event.user.code); } @@ -1818,6 +1828,55 @@ while (_show_stat == -1) return _show_stat; } +static t_stat _vid_screenshot (const char *filename) +{ +if (!vid_active) { + sim_printf ("No video display is active\n"); + return SCPE_UDIS | SCPE_NOMESSAGE; + } +#if SDL_MAJOR_VERSION == 1 +SDL_SaveBMP(vid_image, filename); +#else +if (1) { + SDL_Surface *sshot = sim_end ? SDL_CreateRGBSurface(0, vid_width, vid_height, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000) : + SDL_CreateRGBSurface(0, vid_width, vid_height, 32, 0x0000ff00, 0x000ff000, 0xff000000, 0x000000ff) ; + SDL_RenderReadPixels(vid_renderer, NULL, SDL_PIXELFORMAT_ARGB8888, sshot->pixels, sshot->pitch); + SDL_SaveBMP(sshot, filename); + SDL_FreeSurface(sshot); + } +#endif +return SCPE_OK; +} + +static t_stat _screenshot_stat; +static const char *_screenshot_filename; + +void vid_screenshot_event (void) +{ +_screenshot_stat = _vid_screenshot (_screenshot_filename); +} + +t_stat vid_screenshot (const char *filename) +{ +SDL_Event user_event; + +_screenshot_stat = -1; +_screenshot_filename = filename; + +user_event.type = SDL_USEREVENT; +user_event.user.code = EVENT_SCREENSHOT; +user_event.user.data1 = NULL; +user_event.user.data2 = NULL; +#if defined (SDL_MAIN_AVAILABLE) +SDL_PushEvent (&user_event); +#else +vid_screenshot_event (); +#endif +while (_screenshot_stat == -1) + SDL_Delay (20); +return _screenshot_stat; +} + #else /* !(defined(USE_SIM_VIDEO) && defined(HAVE_LIBSDL)) */ /* Non-implemented versions */ @@ -1884,4 +1943,10 @@ t_stat vid_show_video (FILE* st, UNIT* uptr, int32 val, void* desc) fprintf (st, "video support unavailable"); return SCPE_OK; } + +t_stat vid_screenshot (char *filename) +{ +sim_printf ("video support unavailable\n"); +return SCPE_NOFNC|SCPE_NOMESSAGE; +} #endif /* defined(USE_SIM_VIDEO) */ diff --git a/sim_video.h b/sim_video.h index bd1df491..d7179aed 100644 --- a/sim_video.h +++ b/sim_video.h @@ -183,6 +183,7 @@ t_stat vid_set_release_key (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat vid_show_release_key (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat vid_show_video (FILE* st, UNIT* uptr, int32 val, void* desc); t_stat vid_show (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc); +t_stat vid_screenshot (const char *filename); extern t_bool vid_active; extern uint32 vid_mono_palette[2];