diff --git a/doc/images/screen.png b/doc/images/screen.png
index 60a815d9c..6e7da194a 100644
Binary files a/doc/images/screen.png and b/doc/images/screen.png differ
diff --git a/doc/manual.html b/doc/manual.html
index 52f753e6d..7a9165eb9 100644
--- a/doc/manual.html
+++ b/doc/manual.html
@@ -240,7 +240,7 @@
Built-in debugger and profiler
@@ -800,6 +800,8 @@ Screen capture options
Use <file> to record AVI
--screenshot-dir <dir>
Save screenshots in the directory <dir>
+--screenshot-format <x>
+Select screenshot file format (x = bmp/png/neo/ximg).
Devices options
-j,
@@ -1864,8 +1866,13 @@
The Hatari Screen Dialog
not be enabled on very slow computers.
Click the Screenshot button to create
-a screenshot in PNG (or BMP) format to the current working directory
-or click the Record AVI button to
+a screenshot in the selected format to the current working directory.
+PNG and BMP formats will match the visual output of Hatari.
+NEO and XIMG formats will produce Atari ST native images, but will not include
+borders, or raster palette effects. NEO is limited to the 3 standard ST
+resolutions.
+
+Click the Record AVI button to
record an AVI format video of Hatari screen (and audio) output.
diff --git a/src/gui-sdl/dlgScreen.c b/src/gui-sdl/dlgScreen.c
index 42b354501..e1a0ff014 100644
--- a/src/gui-sdl/dlgScreen.c
+++ b/src/gui-sdl/dlgScreen.c
@@ -103,13 +103,14 @@ static SGOBJ monitordlg[] =
#define DLGSCRN_FORMAT_PNG 27
#define DLGSCRN_FORMAT_BMP 28
#define DLGSCRN_FORMAT_NEO 29
-#define DLGSCRN_CROP 30
-#define DLGSCRN_CAPTURE 31
-#define DLGSCRN_RECANIM 32
-#define DLGSCRN_GPUSCALE 35
-#define DLGSCRN_RESIZABLE 36
-#define DLGSCRN_VSYNC 37
-#define DLGSCRN_EXIT_WINDOW 38
+#define DLGSCRN_FORMAT_XIMG 30
+#define DLGSCRN_CROP 31
+#define DLGSCRN_CAPTURE 32
+#define DLGSCRN_RECANIM 33
+#define DLGSCRN_GPUSCALE 36
+#define DLGSCRN_RESIZABLE 37
+#define DLGSCRN_VSYNC 38
+#define DLGSCRN_EXIT_WINDOW 39
/* needs to match Frame skip values in windowdlg[]! */
static const int skip_frames[] = { 0, 1, 2, 4, AUTO_FRAMESKIP_LIMIT };
@@ -151,12 +152,13 @@ static SGOBJ windowdlg[] =
{ SGBUTTON, 0, 0, 43,9, 1,1, "\x03", SG_SHORTCUT_DOWN },
{ SGBOX, 0, 0, 1,12, 50,5, NULL },
- { SGRADIOBUT, 0, 0, 8,13, 5,1, "PNG" },
- { SGRADIOBUT, 0, 0, 14,13, 5,1, "BMP" },
- { SGRADIOBUT, 0, 0, 20,13, 5,1, "NEO" },
- { SGCHECKBOX, 0, 0, 8,15, 16,1, "_Crop statusbar" },
- { SGBUTTON, 0, 0, 29,13, 14,1, " _Screenshot " },
- { SGBUTTON, 0, 0, 29,15, 14,1, NULL }, /* Record text set later */
+ { SGRADIOBUT, 0, 0, 5,13, 5,1, "PNG" },
+ { SGRADIOBUT, 0, 0, 11,13, 5,1, "BMP" },
+ { SGRADIOBUT, 0, 0, 17,13, 5,1, "NEO" },
+ { SGRADIOBUT, 0, 0, 23,13, 5,1, "XIMG" },
+ { SGCHECKBOX, 0, 0, 5,15, 16,1, "_Crop statusbar" },
+ { SGBUTTON, 0, 0, 32,13, 14,1, " _Screenshot " },
+ { SGBUTTON, 0, 0, 32,15, 14,1, NULL }, /* Record text set later */
{ SGBOX, 0, 0, 1,18, 50,4, NULL },
{ SGTEXT, 0, 0, 20,18, 12,1, "SDL2 options" },
@@ -309,6 +311,8 @@ static void DlgScreen_SetScreenShot_Format ( void )
{
if ( windowdlg[DLGSCRN_FORMAT_NEO].state & SG_SELECTED )
ConfigureParams.Screen.ScreenShotFormat = SCREEN_SNAPSHOT_NEO;
+ else if ( windowdlg[DLGSCRN_FORMAT_XIMG].state & SG_SELECTED )
+ ConfigureParams.Screen.ScreenShotFormat = SCREEN_SNAPSHOT_XIMG;
#if HAVE_LIBPNG
else if ( windowdlg[DLGSCRN_FORMAT_PNG].state & SG_SELECTED )
ConfigureParams.Screen.ScreenShotFormat = SCREEN_SNAPSHOT_PNG;
@@ -370,8 +374,11 @@ void Dialog_WindowDlg(void)
windowdlg[DLGSCRN_FORMAT_PNG].state &= ~SG_SELECTED;
windowdlg[DLGSCRN_FORMAT_BMP].state &= ~SG_SELECTED;
windowdlg[DLGSCRN_FORMAT_NEO].state &= ~SG_SELECTED;
+ windowdlg[DLGSCRN_FORMAT_XIMG].state &= ~SG_SELECTED;
if (ConfigureParams.Screen.ScreenShotFormat == SCREEN_SNAPSHOT_NEO )
windowdlg[DLGSCRN_FORMAT_NEO].state |= SG_SELECTED;
+ else if (ConfigureParams.Screen.ScreenShotFormat == SCREEN_SNAPSHOT_XIMG )
+ windowdlg[DLGSCRN_FORMAT_XIMG].state |= SG_SELECTED;
#if HAVE_LIBPNG
else if (ConfigureParams.Screen.ScreenShotFormat == SCREEN_SNAPSHOT_PNG)
windowdlg[DLGSCRN_FORMAT_PNG].state |= SG_SELECTED;
diff --git a/src/includes/screenConvert.h b/src/includes/screenConvert.h
index 919348e28..6121f21f3 100644
--- a/src/includes/screenConvert.h
+++ b/src/includes/screenConvert.h
@@ -6,7 +6,7 @@
*/
/* Last used vw/vh/vbpp for Screen_GenConvert */
-extern int ConvertW, ConvertH, ConvertBPP;
+extern int ConvertW, ConvertH, ConvertBPP, ConvertNextLine;
void Screen_RemapPalette(void);
void Screen_SetPaletteColor(Uint8 idx, Uint8 red, Uint8 green, Uint8 blue);
diff --git a/src/includes/screenSnapShot.h b/src/includes/screenSnapShot.h
index b10c412ec..b5ae8c341 100644
--- a/src/includes/screenSnapShot.h
+++ b/src/includes/screenSnapShot.h
@@ -13,6 +13,7 @@
#define SCREEN_SNAPSHOT_BMP 1
#define SCREEN_SNAPSHOT_PNG 2
#define SCREEN_SNAPSHOT_NEO 3
+#define SCREEN_SNAPSHOT_XIMG 4
extern int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int destw,
diff --git a/src/options.c b/src/options.c
index c33dc7dfc..252ad70be 100644
--- a/src/options.c
+++ b/src/options.c
@@ -321,7 +321,7 @@ static const opt_t HatariOptions[] = {
{ OPT_SCRSHOT_DIR, NULL, "--screenshot-dir",
"
", "Save screenshots in the directory " },
{ OPT_SCRSHOT_FORMAT, NULL, "--screenshot-format",
- "", "Select file formatc (x = bmp/png/neo)" },
+ "", "Select file formatc (x = bmp/png/neo/ximg)" },
{ OPT_HEADER, NULL, NULL, NULL, "Devices" },
{ OPT_JOYSTICK, "-j", "--joystick",
@@ -1357,6 +1357,10 @@ bool Opt_ParseParameters(int argc, const char * const argv[])
{
ConfigureParams.Screen.ScreenShotFormat = SCREEN_SNAPSHOT_NEO;
}
+ else if (strcasecmp(argv[i], "ximg") == 0)
+ {
+ ConfigureParams.Screen.ScreenShotFormat = SCREEN_SNAPSHOT_XIMG;
+ }
else
{
return Opt_ShowError(OPT_SCRSHOT_FORMAT, argv[i], "Unknown screenshot format");
diff --git a/src/screenConvert.c b/src/screenConvert.c
index 60738bc5d..6eb6da8f8 100644
--- a/src/screenConvert.c
+++ b/src/screenConvert.c
@@ -34,6 +34,7 @@ static uint32_t nScreenBaseAddr; /* address of screen in STRam */
int ConvertW = 0;
int ConvertH = 0;
int ConvertBPP = 1;
+int ConvertNextLine = 0;
/* TOS palette (bpp < 16) to SDL color mapping */
static struct
@@ -359,6 +360,7 @@ static void Screen_ConvertWithoutZoom(Uint16 *fvram, int vw, int vh, int vbpp, i
if (hscrolloffset) {
/* Yes, so we need to adjust offset to next line: */
nextline += vbpp;
+ ConvertNextLine = nextline * 2;
}
/* The sample-hold feature exists only on the TT */
@@ -617,6 +619,7 @@ static void Screen_ConvertWithZoom(Uint16 *fvram, int vw, int vh, int vbpp, int
if (hscrolloffset) {
/* Yes, so we need to adjust offset to next line: */
nextline += vbpp;
+ ConvertNextLine = nextline * 2;
}
/* Integer zoom coef ? */
@@ -691,6 +694,7 @@ void Screen_GenConvert(uint32_t vaddr, void *fvram, int vw, int vh,
ConvertW = vw;
ConvertH = vh;
ConvertBPP = vbpp;
+ ConvertNextLine = nextline * 2; /* bytes per line */
/* Override drawing palette for screenshots */
ConvertPalette = palette.native;
diff --git a/src/screenSnapShot.c b/src/screenSnapShot.c
index 475ee3413..e8b958709 100644
--- a/src/screenSnapShot.c
+++ b/src/screenSnapShot.c
@@ -20,8 +20,8 @@ const char ScreenSnapShot_fileid[] = "Hatari screenSnapShot.c";
#include "screenConvert.h"
#include "screenSnapShot.h"
#include "statusbar.h"
+#include "vdi.h"
#include "video.h"
-#include "videl.h"
#include "stMemory.h"
/* after above that bring in config.h */
#if HAVE_LIBPNG
@@ -32,7 +32,6 @@ const char ScreenSnapShot_fileid[] = "Hatari screenSnapShot.c";
static int nScreenShots = 0; /* Number of screen shots saved */
-static Uint8 NEOHeader[128];
/*-----------------------------------------------------------------------*/
@@ -116,7 +115,6 @@ int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int dw, int dh,
int sh = surface->h - CropTop - CropBottom;
Uint8 *src_ptr;
Uint8 *rowbuf;
- SDL_PixelFormat *fmt = surface->format;
png_infop info_ptr = NULL;
png_structp png_ptr;
png_text pngtext;
@@ -124,8 +122,8 @@ int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int dw, int dh,
char text[] = "Hatari screenshot";
off_t start;
bool do_palette = true;
- static png_color png_pal[256];
- static Uint8 palbuf[3];
+ png_color png_pal[256];
+ Uint8 palbuf[3];
if (!dw)
dw = sw;
@@ -138,19 +136,15 @@ int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int dw, int dh,
do_lock = SDL_MUSTLOCK(surface);
if (do_lock)
SDL_LockSurface(surface);
- for (y = 0; y < dh && do_palette; y++)
+ for (y = 0; y < dh; y++)
{
src_ptr = (Uint8 *)surface->pixels
+ (CropTop + (y * sh + dh/2) / dh) * surface->pitch
+ CropLeft * surface->format->BytesPerPixel;
- switch (fmt->BytesPerPixel)
+ if (!PixelConvert_32to8Bits(rowbuf, (Uint32*)src_ptr, dw, surface))
{
- case 4:
- if (!PixelConvert_32to8Bits(rowbuf, (Uint32*)src_ptr, dw, surface))
- do_palette = false;
+ do_palette = false;
break;
- default:
- abort();
}
}
if (do_lock)
@@ -209,14 +203,7 @@ int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int dw, int dh,
/* Generate palette for PNG */
for (y = 0; y < ConvertPaletteSize; y++)
{
- switch (fmt->BytesPerPixel)
- {
- case 4:
- PixelConvert_32to24Bits(palbuf, (Uint32*)(ConvertPalette+y), 1, surface);
- break;
- default:
- abort();
- }
+ PixelConvert_32to24Bits(palbuf, (Uint32*)(ConvertPalette+y), 1, surface);
png_pal[y].red = palbuf[0];
png_pal[y].green = palbuf[1];
png_pal[y].blue = palbuf[2];
@@ -234,37 +221,18 @@ int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int dw, int dh,
/* need to lock the surface while accessing it directly */
if (do_lock)
SDL_LockSurface(surface);
-
-
src_ptr = (Uint8 *)surface->pixels
+ (CropTop + (y * sh + dh/2) / dh) * surface->pitch
+ CropLeft * surface->format->BytesPerPixel;
if (!do_palette)
- {
- switch (fmt->BytesPerPixel)
- {
- case 4:
- /* unpack 32-bit RGBA pixels */
- PixelConvert_32to24Bits(rowbuf, (Uint32*)src_ptr, dw, surface);
- break;
- default:
- abort();
- }
- }
+ /* unpack 32-bit RGBA pixels */
+ PixelConvert_32to24Bits(rowbuf, (Uint32*)src_ptr, dw, surface);
else
- {
/* Reindex back to ST palette
* Note that this cannot disambiguate indices if the palette has duplicate colors */
- switch (fmt->BytesPerPixel)
- {
- case 4:
- PixelConvert_32to8Bits(rowbuf, (Uint32*)src_ptr, dw, surface);
- break;
- default:
- abort();
- }
- }
+ PixelConvert_32to8Bits(rowbuf, (Uint32*)src_ptr, dw, surface);
+
/* and unlock surface before syscalls */
if (do_lock)
SDL_UnlockSurface(surface);
@@ -286,32 +254,62 @@ int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int dw, int dh,
/**
- * Helper for writing NEO file header
+ * Determine the internally used screen dimensions, bits per pixel, and whether GenConv is used.
*/
-static void StoreU16NEO(Uint16 val, int offset)
+static void ScreenSnapShot_GetInternalFormat(bool *genconv, int *sw, int *sh, int *bpp, uint32_t* line_size)
{
- NEOHeader[offset+0] = (val >> 8) & 0xFF;
- NEOHeader[offset+1] = (val >> 0) & 0xFF;
+ *genconv = Config_IsMachineFalcon() || Config_IsMachineTT() || bUseVDIRes;
+ /* genconv here is almost the same as Screen_UseGenConvScreen, but omits bUseHighRes,
+ * which is a hybrid GenConvert that also fills pFrameBuffer. */
+
+ *sw = (STRes == ST_LOW_RES) ? 320 : 640;
+ *sh = (STRes == ST_HIGH_RES) ? 400 : 200;
+ *bpp = 4;
+ if (STRes == ST_MEDIUM_RES) *bpp = 2;
+ if (STRes == ST_HIGH_RES) *bpp = 1;
+ if (*genconv)
+ {
+ /* Assume resolution based on GenConvert. */
+ *bpp = ConvertBPP;
+ *sw = ConvertW;
+ *sh = ConvertH;
+ }
+ *line_size = (uint32_t)(*bpp * ((*sw + 15) & ~15)) / 8; /* size of line data in bytes, rounded up to 16 pixels */
}
+
/**
* Save direct video memory dump to NEO file
*/
static int ScreenSnapShot_SaveNEO(const char *filename)
{
FILE *fp = NULL;
- int i, res, sw, sh, stride, offset;
+ int i, res, sw, sh, bpp, offset;
+ bool genconv;
SDL_Color col;
- uint32_t video_base;
-
- if (pFrameBuffer == NULL || pFrameBuffer->pSTScreen == NULL)
+ uint32_t video_base, line_size;
+ uint16_t header[64];
+
+ ScreenSnapShot_GetInternalFormat(&genconv, &sw, &sh, &bpp, &line_size);
+ /* If BPP matches an ST resolution, use that, otherwise just use the BPP itself instead of that number. */
+ res = bpp;
+ if (bpp == 4) res = 0;
+ else if (bpp == 2) res = 1;
+ else if (bpp == 1) res = 2;
+
+ /* Preventing NEO screenshots with unexpected BPP or dimensions. */
+ if (res > 2)
+ {
+ /* The NEO header contains only 16 palette entries, so 8bpp would need extra palette information,
+ * and 16bpp true color mode is not supported by existing NEO tools. */
+ Log_AlertDlg(LOG_ERROR,"The current video mode has too many colors for the .NEO screenshot format");
return -1;
-
- /* Return an error if using Falcon or TT with a video mode not compatible with ST/STE */
- if ( ( Config_IsMachineFalcon() && !VIDEL_Use_STShifter() )
- || ( Config_IsMachineTT() && ( TTRes > 2 ) ) )
+ }
+ if ((res == 0 && sw != 320) || (res < 2 && sh != 200) || (res > 0 && sw != 640) || (res == 2 && sh != 400))
{
- Log_AlertDlg(LOG_ERROR,"The current video mode is not compatible with the .NEO screenshot format");
+ /* The NEO header contains dimension info, and any width that is a multiple of 16 pixels should be theoretically valid,
+ * but existing NEO tools mostly ignore the dimension fields. */
+ Log_AlertDlg(LOG_ERROR,"The current video mode has non-standard resolution dimensions, unable to save in .NEO screenshot format");
return -1;
}
@@ -319,67 +317,197 @@ static int ScreenSnapShot_SaveNEO(const char *filename)
if (!fp)
return -1;
- if (Config_IsMachineFalcon() || Config_IsMachineTT()) /* Compatible ST/STE video modes */
- {
- /* Assume resolution based on GenConvert. */
- if (ConvertW < ((640+320)/2))
- res = 0;
- else
- res = (ConvertH < ((400+200)/2)) ? 1 : 2;
- }
- else /* Native ST/STE video modes */
- {
- res = (STRes == ST_HIGH_RES) ? 2 :
- (STRes == ST_MEDIUM_RES) ? 1 :
- 0;
- }
-
- sw = (res > 0) ? 640 : 320;
- sh = (res == 2) ? 400 : 200;
- stride = (res == 2) ? 80 : 160;
+ memset(header, 0, sizeof(header));
+ header[0] = be_swap16(0); /* Flags field (always 0). */
+ header[1] = be_swap16(res); /* NEO resolution word is the primary indicator of BPP. */
- memset(NEOHeader, 0, sizeof(NEOHeader));
- StoreU16NEO(res, 2);
- if (!Screen_UseGenConvScreen()) /* Low/Medium resolution: use middle line's palette for whole image */
+ /* ST Low/Medium resolution stores a palette for each line. Using the centre line's palette. */
+ if (!genconv && res != 2 && pFrameBuffer)
{
for (i=0; i<16; i++)
- StoreU16NEO(pFrameBuffer->HBLPalettes[i+((OVERSCAN_TOP+sh/2)<<4)], 4+(2*i));
+ header[2+i] = be_swap16(pFrameBuffer->HBLPalettes[i+((OVERSCAN_TOP+sh/2)<<4)]);
}
- else /* High resolution or GenConvert: use stored GenConvert RGB palette. */
+ else /* High resolution or other GenConvert: use stored GenConvert RGB palette. */
{
- for (i=0; i<16;i++)
+ for (i=0; i<16; i++)
{
col = Screen_GetPaletteColor(i);
- StoreU16NEO(
+ header[2+i] = be_swap16(
((col.r >> 5) << 8) |
((col.g >> 5) << 4) |
- ((col.b >> 5) << 0),
- 4+(2*i));
+ ((col.b >> 5) << 0));
}
+ /* Note that this 24-bit palette is being approximated as a 9-bit ST color palette,
+ * and 256 colors needed for 8bpp cannot be expressed in this header. */
}
- memcpy(NEOHeader+36," . ",12);
- StoreU16NEO(sw, 58);
- StoreU16NEO(sh, 60);
- fwrite(NEOHeader, 1, 128, fp);
+ memcpy(header+18,"HATARI 4BPP",12); /* Use filename field indicate Hatari source and format. */
+ ((uint8_t*)(header+18))[8] = '0' + (bpp % 10);
+ if (bpp >= 10)
+ ((uint8_t*)(header+18))[7] = '0' + (bpp / 10);
+ header[29] = be_swap16(sw); /* screen width */
+ header[30] = be_swap16(sh); /* screen height */
+
+ fwrite(header, 1, 128, fp);
- if (!Config_IsMachineFalcon() && !Config_IsMachineTT())
+ /* ST modes fill pFrameBuffer->pSTScreen from each scanline, during Video_EndHBL. */
+ if (!genconv && pFrameBuffer && pFrameBuffer->pSTScreen)
{
for (i = 0; i < sh; i++)
{
offset = (res == 2) ?
(SCREENBYTES_MONOLINE * i) :
(STScreenLineOffset[i+OVERSCAN_TOP] + SCREENBYTES_LEFT);
- fwrite(pFrameBuffer->pSTScreen + offset, 1, stride, fp);
+ fwrite(pFrameBuffer->pSTScreen + offset, 1, line_size, fp);
}
}
- else /* TT/Falcon bypass Video_EndHBL which prepare the FrameBuffer,
- * so as a fallback we just try to copy the video data from ST RAM. */
+ else /* TT/Falcon bypass Video_EndHBL, so pFrameBuffer is unused.
+ * As a fallback we just copy the video data from ST RAM. */
{
video_base = Video_GetScreenBaseAddr();
- if ((video_base + 32000) <= STRamEnd)
+
+ for (i = 0; i < sh; i++)
{
- fwrite(STRam + video_base, 1, 32000, fp);
+ if ((video_base + line_size) <= STRamEnd)
+ {
+ fwrite(STRam + video_base, 1, line_size, fp);
+ video_base += ConvertNextLine;
+ }
+ else
+ {
+ fclose(fp);
+ return -1;
+ }
+ }
+ }
+
+ fclose (fp);
+ return 1; /* >0 if OK, -1 if error */
+}
+
+
+/**
+ * Save direct video memory dump to XIMG file
+ */
+static int ScreenSnapShot_SaveXIMG(const char *filename)
+{
+ FILE *fp = NULL;
+ int i, j, k, sw, sh, bpp, offset;
+ bool genconv;
+ SDL_Color col;
+ uint16_t colst, colr, colg, colb;
+ uint32_t video_base, line_size;
+ uint16_t header_size;
+ uint8_t *scanline;
+ uint16_t header[11];
+
+ ScreenSnapShot_GetInternalFormat(&genconv, &sw, &sh, &bpp, &line_size);
+
+ if (bpp > 8 && bpp != 16)
+ {
+ /* bpp = 24 is a possible format for XIMG but Hatari's screenConvert only supports 16-bit true color. */
+ Log_AlertDlg(LOG_ERROR,"XIMG screenshot only supports up to 8-bit palette, or 16-bit true color.");
+ return -1;
+ }
+
+ fp = fopen(filename, "wb");
+ if (!fp)
+ return -1;
+
+ /* XIMG header */
+ header_size = (8 + 3) * 2; /* IMG + XIMG */
+ if (bpp <= 8) /* palette */
+ header_size += (3 * 2) * (1 << bpp);
+ memset(header, 0, sizeof(header));
+ header[0] = be_swap16(1); /* version */
+ header[1] = be_swap16(header_size/2);
+ header[2] = be_swap16(bpp); /* bitplanes */
+ header[3] = be_swap16(2); /* pattern length (unused) */
+ header[4] = be_swap16(0x55); /* pixel width (microns) */
+ header[5] = be_swap16(0x55); /* pixel height (microns) */
+ header[6] = be_swap16(sw); /* screen width */
+ header[7] = be_swap16(sh); /* screen height */
+ memcpy(header+8,"XIMG",4);
+ header[10] = be_swap16(0); /* XIMG RGB palette format */
+ fwrite(header, 1, (8 + 3) * 2, fp);
+
+ /* XIMG RGB format, word triples each 0-1000 */
+ if (bpp <= 8)
+ {
+ for (i=0; i<(1<HBLPalettes[i+((OVERSCAN_TOP+sh/2)<<4)];
+ colr = (uint16_t)((((colst >> 8) & 7) * 1000) / 7);
+ colg = (uint16_t)((((colst >> 4) & 7) * 1000) / 7);
+ colb = (uint16_t)((((colst >> 0) & 7) * 1000) / 7);
+ }
+ else /* High resolution or GenConvert palette */
+ {
+ col = Screen_GetPaletteColor(i);
+ colr = (uint16_t)((col.r * 1000) / 255);
+ colg = (uint16_t)((col.g * 1000) / 255);
+ colb = (uint16_t)((col.b * 1000) / 255);
+ }
+ header[0] = be_swap16(colr);
+ header[1] = be_swap16(colg);
+ header[2] = be_swap16(colb);
+ fwrite(header, 1, 3 * 2, fp);
+ }
+ }
+
+ /* Image data, no compression is attempted */
+ for (i = 0; i < sh; i++)
+ {
+ /* Find line of scanline data */
+ if (!genconv && pFrameBuffer && pFrameBuffer->pSTScreen)
+ {
+ scanline = pFrameBuffer->pSTScreen + (
+ (sh >= 300) ? (SCREENBYTES_MONOLINE * i) :
+ (STScreenLineOffset[i+OVERSCAN_TOP] + SCREENBYTES_LEFT) );
+ }
+ else
+ {
+ video_base = Video_GetScreenBaseAddr() + (i * ConvertNextLine);
+ if ((video_base + line_size) <= STRamEnd)
+ {
+ scanline = STRam + video_base;
+ }
+ else
+ {
+ fclose(fp);
+ return -1;
+ }
+ }
+
+ if (bpp <= 8)
+ {
+ /* de-interleave scanline into XIMG format */
+ for (j=0; j 0) /* break into <= 254 byte packets */
+ {
+ k = (j > 254) ? 254 : j; /* bytes in packet */
+ fputc(0x80,fp);
+ fputc(k,fp);
+ fwrite(scanline,1,k,fp);
+ j -= k;
+ scanline += k;
+ }
}
else
{
@@ -447,6 +575,17 @@ void ScreenSnapShot_SaveScreen(void)
free(szFileName);
return;
}
+ /* XIMG format */
+ else if (ConfigureParams.Screen.ScreenShotFormat == SCREEN_SNAPSHOT_XIMG )
+ {
+ sprintf(szFileName,"%s/grab%4.4d.ximg", Paths_GetScreenShotDir(), nScreenShots);
+ if (ScreenSnapShot_SaveXIMG(szFileName) > 0)
+ fprintf(stderr, "XMIG screen dump saved to: %s\n", szFileName);
+ else
+ fprintf(stderr, "XIMG screen dump failed!\n");
+ free(szFileName);
+ return;
+ }
sprintf(szFileName,"%s/grab%4.4d.bmp", Paths_GetScreenShotDir(), nScreenShots);
if (SDL_SaveBMP(sdlscrn, szFileName))
@@ -484,6 +623,10 @@ void ScreenSnapShot_SaveToFile(const char *szFileName)
{
success = ScreenSnapShot_SaveNEO(szFileName) == 0;
}
+ else if (File_DoesFileExtensionMatch(szFileName, ".ximg") || File_DoesFileExtensionMatch(szFileName, ".img"))
+ {
+ success = ScreenSnapShot_SaveXIMG(szFileName) == 0;
+ }
else
{
fprintf(stderr, "ERROR: unknown screen dump file name extension: %s\n", szFileName);