Added support for saving text mode snapshot in BMP format if file extension is

set accordingly.
TODO #1: Text mode features split screen and h/v pel panning missing for now.
TODO #2: Show error messages related to dialogs in message boxes.
This commit is contained in:
Volker Ruppert 2020-10-16 17:25:50 +00:00
parent 1d0efc734f
commit dffaa9794b
5 changed files with 131 additions and 36 deletions

View File

@ -35,6 +35,7 @@ Changes after 2.6.11:
- GUI and display libraries
- Added support for calling a headerbar handler after pressing F7 (enabled
with "cmdmode" option / present in sdl, sdl2, win32 and x).
- Added support for saving text mode snapshot in BMP format.
- Write marker to log file by pressing "m" button (guis with "cmdmode" on).
- X11 keymaps: added new one for Swiss-German and improved Italian map.
- RFB: added support for the pixel format RGB332.

View File

@ -5604,9 +5604,12 @@ feature work.</para>
<listitem>
<para>snapshot button</para>
<para>Press this button if you want to save a snapshot of the Bochs screen. All
text and graphics modes are now supported. If gui dialogs are supported (e.g. on win32)
Bochs presents you a "Save as..." dialog box to specify the filename. All other
platforms are using the fixed filenames "snapshot.txt" or "snapshot.bmp".</para>
text and graphics modes are now supported. If gui dialogs are supported (e.g. on
win32) Bochs presents you a "Save as..." dialog box to specify the filename. In
text modes the formats BMP and TXT are supported depending on file extension.
Platforms without gui dialogs are using the fixed filenames "snapshot.txt" or
"snapshot.bmp".
</para>
</listitem>
<listitem><para>config button</para>
<para>This button stops the Bochs simulation and starts the runtime configuration.

View File

@ -504,6 +504,9 @@ void bx_gui_c::copy_handler(void)
}
}
#define BX_SNAPSHOT_TXT 0
#define BX_SNAPSHOT_BMP 1
// create a text snapshot and dump it to a file
void bx_gui_c::snapshot_handler(void)
{
@ -512,43 +515,41 @@ void bx_gui_c::snapshot_handler(void)
Bit8u *row_buffer, *pixel_ptr, *row_ptr;
Bit8u bmp_header[54], iBits, b1, b2;
Bit32u ilen, len, rlen;
char filename[BX_PATHNAME_LEN];
char filename[BX_PATHNAME_LEN], *ext;
Bit8u snap_fmt;
if (BX_GUI_THIS guest_textmode) {
make_text_snapshot((char**)&snapshot_ptr, &len);
if (!BX_GUI_THIS fullscreen_mode &&
(BX_GUI_THIS dialog_caps & BX_GUI_DLG_SNAPSHOT)) {
int ret = SIM->ask_filename (filename, sizeof(filename),
"Save snapshot as...", "snapshot.txt",
bx_param_string_c::SAVE_FILE_DIALOG);
if (ret < 0) { // cancelled
delete [] snapshot_ptr;
return;
}
} else {
strcpy (filename, "snapshot.txt");
}
FILE *fp = fopen(filename, "wb");
if (fp == NULL) {
BX_ERROR(("snapshot button failed: cannot create text file"));
delete [] snapshot_ptr;
strcpy(filename, "snapshot.txt");
snap_fmt = BX_SNAPSHOT_TXT;
} else {
strcpy(filename, "snapshot.bmp");
snap_fmt = BX_SNAPSHOT_BMP;
}
if (!BX_GUI_THIS fullscreen_mode &&
(BX_GUI_THIS dialog_caps & BX_GUI_DLG_SNAPSHOT)) {
int ret = SIM->ask_filename(filename, sizeof(filename),
"Save snapshot as...", filename,
bx_param_string_c::SAVE_FILE_DIALOG);
if (ret < 0) { // cancelled
return;
}
fwrite(snapshot_ptr, 1, len, fp);
fclose(fp);
delete [] snapshot_ptr;
} else {
if (!BX_GUI_THIS fullscreen_mode &&
(BX_GUI_THIS dialog_caps & BX_GUI_DLG_SNAPSHOT)) {
int ret = SIM->ask_filename (filename, sizeof(filename),
"Save snapshot as...", "snapshot.bmp",
bx_param_string_c::SAVE_FILE_DIALOG);
if (ret < 0) { // cancelled
ext = strrchr(filename, '.');
if (ext == NULL) {
BX_ERROR(("Unknown snapshot file format"));
return;
} else {
ext++;
if (BX_GUI_THIS guest_textmode && !strcmp(ext, "txt")) {
snap_fmt = BX_SNAPSHOT_TXT;
} else if (!strcmp(ext, "bmp")) {
snap_fmt = BX_SNAPSHOT_BMP;
} else {
BX_ERROR(("Unsupported snapshot file format '%s'", ext));
return;
}
} else {
strcpy (filename, "snapshot.bmp");
}
}
if (snap_fmt == BX_SNAPSHOT_BMP) {
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC
#ifdef O_BINARY
| O_BINARY
@ -632,6 +633,16 @@ void bx_gui_c::snapshot_handler(void)
delete [] row_buffer;
close(fd);
BX_GUI_THIS set_snapshot_mode(0);
} else {
make_text_snapshot((char**)&snapshot_ptr, &len);
FILE *fp = fopen(filename, "wb");
if (fp != NULL) {
fwrite(snapshot_ptr, 1, len, fp);
fclose(fp);
} else {
BX_ERROR(("snapshot button failed: cannot create text file"));
}
delete [] snapshot_ptr;
}
}
@ -1107,6 +1118,83 @@ void bx_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,
delete [] tile;
}
void bx_gui_c::text_update_common(Bit8u *old_text, Bit8u *new_text,
unsigned long cursor_x, unsigned long cursor_y,
bx_vga_tminfo_t *tm_info)
{
Bit16u curs, rows, hchars, text_cols, font_row, mask, offset, y;
Bit8u fheight, fwidth, fontline, fontrows, fontpixels, fgcolor, bgcolor;
Bit8u *new_line, *font_ptr, *buf, *buf_row, *buf_char;
bx_bool cursor_visible, dwidth, gfxcharw9, invert;
if (BX_GUI_THIS snapshot_mode) {
if (BX_GUI_THIS snapshot_buffer != NULL) {
fheight = BX_GUI_THIS guest_fsize >> 4;
fwidth = BX_GUI_THIS guest_fsize & 0x0f;
dwidth = (fwidth > 9);
rows = BX_GUI_THIS guest_yres / fheight;
text_cols = BX_GUI_THIS guest_xres / fwidth;
cursor_visible = ((tm_info->cs_start <= tm_info->cs_end) && (tm_info->cs_start < fheight));
if ((cursor_visible) && (cursor_y < rows) && (cursor_x < text_cols)) {
curs = cursor_y * tm_info->line_offset + cursor_x * 2;
} else {
curs = 0xffff;
}
y = 0;
buf_row = BX_GUI_THIS snapshot_buffer;
do {
buf = buf_row;
hchars = text_cols;
new_line = new_text;
offset = y * tm_info->line_offset;
do {
font_ptr = &vga_charmap[new_text[0] << 5];
gfxcharw9 = ((tm_info->line_graphics) && ((new_text[0] & 0xE0) == 0xC0));
fgcolor = tm_info->actl_palette[new_text[1] & 0x0f];
bgcolor = tm_info->actl_palette[(new_text[1] >> 4) & 0x07];
invert = (offset == curs);
fontrows = fheight;
fontline = 0;
buf_char = buf;
do {
font_row = *font_ptr++;
if (gfxcharw9) {
font_row = (font_row << 1) | (font_row & 0x01);
} else {
font_row <<= 1;
}
fontpixels = fwidth;
if ((invert) && (fontline >= tm_info->cs_start) && (fontline <= tm_info->cs_end))
mask = 0x100;
else
mask = 0x00;
do {
if ((font_row & 0x100) == mask)
*buf = bgcolor;
else
*buf = fgcolor;
buf++;
if (!dwidth || (fontpixels & 1)) font_row <<= 1;
} while (--fontpixels);
buf -= fwidth;
buf += BX_GUI_THIS guest_xres;
fontline++;
} while (--fontrows);
buf = buf_char;
buf += fwidth;
new_text += 2;
offset += 2;
} while (--hchars);
buf_row += (BX_GUI_THIS guest_xres * fheight);
new_text = new_line + tm_info->line_offset;
y++;
} while (--rows);
}
} else {
text_update(old_text, new_text, cursor_x, cursor_y, tm_info);
}
}
void bx_gui_c::graphics_tile_update_common(Bit8u *tile, unsigned x, unsigned y)
{
unsigned i, pitch, pixel_bytes, nbytes, tilebytes;

View File

@ -168,6 +168,9 @@ public:
void init(int argc, char **argv, unsigned max_xres, unsigned max_yres,
unsigned x_tilesize, unsigned y_tilesize);
void cleanup(void);
void text_update_common(Bit8u *old_text, Bit8u *new_text,
unsigned long cursor_x, unsigned long cursor_y,
bx_vga_tminfo_t *tm_info);
void graphics_tile_update_common(Bit8u *tile, unsigned x, unsigned y);
bx_svga_tileinfo_t *graphics_tile_info_common(bx_svga_tileinfo_t *info);
Bit8u* get_snapshot_buffer(void) {return snapshot_buffer;}

View File

@ -1727,9 +1727,9 @@ void bx_vgacore_c::update(void)
cursor_x = ((cursor_address - start_address)/2) % (iWidth/cWidth);
cursor_y = ((cursor_address - start_address)/2) / (iWidth/cWidth);
}
bx_gui->text_update(BX_VGA_THIS s.text_snapshot,
&BX_VGA_THIS s.memory[start_address],
cursor_x, cursor_y, &tm_info);
bx_gui->text_update_common(BX_VGA_THIS s.text_snapshot,
&BX_VGA_THIS s.memory[start_address],
cursor_x, cursor_y, &tm_info);
if (BX_VGA_THIS s.vga_mem_updated) {
// screen updated, copy new VGA memory contents into text snapshot
memcpy(BX_VGA_THIS s.text_snapshot,