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 @@

Emulator features

  • support for whole system state snapshot save/restore
  • driver for extended VDI resolutions
  • sound recording as .WAV or .YM files
  • -
  • screenshots in PNG or BMP format
  • +
  • screenshots in PNG, BMP, NEO or XIMG format
  • AVI video capture with sound
  • emulation speedup, slowdown and pause support
  • 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);