Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEO direct video memory dump option for screen snapshot #31

Closed
wants to merge 7 commits into from
2 changes: 2 additions & 0 deletions src/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ static const struct Config_Tag configs_Screen[] =
{ "nMaxHeight", Int_Tag, &ConfigureParams.Screen.nMaxHeight },
{ "nZoomFactor", Float_Tag, &ConfigureParams.Screen.nZoomFactor },
{ "bUseSdlRenderer", Bool_Tag, &ConfigureParams.Screen.bUseSdlRenderer },
{ "bNEOScreenSnapShot", Bool_Tag, &ConfigureParams.Screen.bNEOScreenSnapShot },
{ "bUseVsync", Bool_Tag, &ConfigureParams.Screen.bUseVsync },
{ NULL , Error_Tag, NULL }
};
Expand Down Expand Up @@ -741,6 +742,7 @@ void Configuration_SetDefault(void)
ConfigureParams.Screen.nZoomFactor = 1.0;
ConfigureParams.Screen.bUseSdlRenderer = true;
ConfigureParams.Screen.bUseVsync = false;
ConfigureParams.Screen.bNEOScreenSnapShot = false;

/* Set defaults for Sound */
ConfigureParams.Sound.bEnableMicrophone = true;
Expand Down
1 change: 1 addition & 0 deletions src/includes/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ typedef struct
bool bResizable;
bool bUseVsync;
bool bUseSdlRenderer;
bool bNEOScreenSnapShot;
float nZoomFactor;
int nSpec512Threshold;
int nVdiColors;
Expand Down
1 change: 1 addition & 0 deletions src/includes/screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ extern uint16_t HBLPalettes[HBL_PALETTE_LINES];
extern uint16_t *pHBLPalettes;
extern uint32_t HBLPaletteMasks[HBL_PALETTE_MASKS];
extern uint32_t *pHBLPaletteMasks;
extern int STScreenLineOffset[NUM_VISIBLE_LINES];

extern void Screen_Init(void);
extern void Screen_UnInit(void);
Expand Down
4 changes: 4 additions & 0 deletions src/includes/screenConvert.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
or at your option any later version. Read the file gpl.txt for details.
*/

/* Last used vw/vh/vbpp for Screen_GenConvert */
extern int ConvertW, ConvertH, ConvertBPP;

void Screen_RemapPalette(void);
void Screen_SetPaletteColor(Uint8 idx, Uint8 red, Uint8 green, Uint8 blue);
SDL_Color Screen_GetPaletteColor(Uint8 idx);
void ScreenConv_MemorySnapShot_Capture(bool bSave);

void Screen_GenConvert(uint32_t vaddr, void *fvram, int vw, int vh,
Expand Down
4 changes: 3 additions & 1 deletion src/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static int PCScreenOffsetX; /* how many pixels to skip from left when dr
static int PCScreenOffsetY; /* how many pixels to skip from top when drawing */
static SDL_Rect STScreenRect; /* screen size without statusbar */

static int STScreenLineOffset[NUM_VISIBLE_LINES]; /* Offsets for ST screen lines eg, 0,160,320... */
int STScreenLineOffset[NUM_VISIBLE_LINES]; /* Offsets for ST screen lines eg, 0,160,320... */
static Uint16 HBLPalette[16], PrevHBLPalette[16]; /* Current palette for line, also copy of first line */

static void (*ScreenDrawFunctionsNormal[3])(void); /* Screen draw functions */
Expand Down Expand Up @@ -748,6 +748,8 @@ void Screen_UnInit(void)
/* Free memory used for copies */
free(FrameBuffer.pSTScreen);
free(FrameBuffer.pSTScreenCopy);
FrameBuffer.pSTScreen = NULL;
FrameBuffer.pSTScreenCopy = NULL;

Screen_FreeSDL2Resources();
if (sdlWindow)
Expand Down
12 changes: 11 additions & 1 deletion src/screenConvert.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ static struct screen_zoom_s screen_zoom;
static bool bTTSampleHold = false; /* TT special video mode */
static int nSampleHoldIdx;
static uint32_t nScreenBaseAddr; /* address of screen in STRam */

int ConvertW = 0;
int ConvertH = 0;
int ConvertBPP = 1;

/* TOS palette (bpp < 16) to SDL color mapping */
static struct
Expand All @@ -50,6 +52,11 @@ void Screen_SetPaletteColor(Uint8 idx, Uint8 red, Uint8 green, Uint8 blue)
palette.native[idx] = SDL_MapRGB(sdlscrn->format, red, green, blue);
}

SDL_Color Screen_GetPaletteColor(Uint8 idx)
{
return palette.standard[idx];
}

void Screen_RemapPalette(void)
{
int i;
Expand Down Expand Up @@ -681,6 +688,9 @@ void Screen_GenConvert(uint32_t vaddr, void *fvram, int vw, int vh,
int upperBorderSize, int lowerBorderSize)
{
nScreenBaseAddr = vaddr;
ConvertW = vw;
ConvertH = vh;
ConvertBPP = vbpp;

if (nScreenZoomX * nScreenZoomY != 1) {
Screen_ConvertWithZoom(fvram, vw, vh, vbpp, nextline, hscroll,
Expand Down
151 changes: 151 additions & 0 deletions src/screenSnapShot.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ const char ScreenSnapShot_fileid[] = "Hatari screenSnapShot.c";
#include "log.h"
#include "paths.h"
#include "screen.h"
#include "screenConvert.h"
#include "screenSnapShot.h"
#include "statusbar.h"
#include "video.h"
#include "vdi.h"
/* after above that bring in config.h */
#if HAVE_LIBPNG
# include <png.h>
Expand All @@ -29,6 +31,15 @@ const char ScreenSnapShot_fileid[] = "Hatari screenSnapShot.c";


static int nScreenShots = 0; /* Number of screen shots saved */
static Uint8 NEOHeader[128];

/* From stMemory.h, but it seems to have some conflict with dirent.h? */
#if ENABLE_SMALL_MEM
extern uint8_t *STRam;
#else
extern uint8_t STRam[16*1024*1024];
#endif /* ENABLE_SMALL_MEM */
extern uint32_t STRamEnd;


/*-----------------------------------------------------------------------*/
Expand Down Expand Up @@ -222,6 +233,130 @@ int ScreenSnapShot_SavePNG_ToFile(SDL_Surface *surface, int dw, int dh,
}
#endif

/**
* Helper for writing NEO file header.
*/
static void StoreU16NEO(Uint16 val, int offset)
{
NEOHeader[offset+0] = (val >> 8) & 0xFF;
NEOHeader[offset+1] = (val >> 0) & 0xFF;
}

/**
* Save direct video memory dump to NEO file.
*/
static int ScreenSnapShot_SaveNEO(const char *filename)
{
FILE *fp = NULL;
int i, res, sw, sh, bpp, offset;
SDL_Color col;
uint32_t video_base, video_size;
bool 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. */

fp = fopen(filename, "wb");
if (!fp)
return -1;

res = (STRes == ST_HIGH_RES) ? 2 :
(STRes == ST_MEDIUM_RES) ? 1 :
0;
sw = (res > 0) ? 640 : 320;
sh = (res == 2) ? 400 : 200;
bpp = 4;
if (res == 1) bpp = 2;
else if (res == 2) bpp = 1;

if (genconv)
{
/* Assume resolution based on GenConvert. */
bpp = ConvertBPP;
sw = ConvertW;
sh = ConvertH;
/* 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;
}

memset(NEOHeader, 0, sizeof(NEOHeader));
StoreU16NEO(res, 2); /* Essentially treating the NEO resolution word as an indirect bpp indicator. */

/* 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+200/2)<<4)], 4+(2*i));
}
/* High resolution or other GenConvert: use stored GenConvert RGB palette. */
else
{
for (i=0; i<16; i++)
{
col = Screen_GetPaletteColor(i);
StoreU16NEO(
((col.r >> 5) << 8) |
((col.g >> 5) << 4) |
((col.b >> 5) << 0),
4+(2*i));
}
}
memcpy(NEOHeader+36,"HATARI 4BPP",12); /* Use internal filename to give a hint about bitplanes. */
NEOHeader[36+8] = '0' + (bpp % 10);
if (bpp >= 10) NEOHeader[36+7] = '0' + (bpp / 10);
StoreU16NEO(sw, 58);
StoreU16NEO(sh, 60);

fwrite(NEOHeader, 1, 128, fp);
/* ST modes fill pFrameBuffer->pSTScreen from each scanline, during Video_EndHBL. */
if (!genconv && pFrameBuffer && pFrameBuffer->pSTScreen)
{
for (i = 0; i < sh; i++)
{
video_size = (uint32_t)(bpp * sw) / 8; /* size of line data in bytes */
offset = (res == 2) ?
(SCREENBYTES_MONOLINE * i) :
(STScreenLineOffset[i+OVERSCAN_TOP] + SCREENBYTES_LEFT);
fwrite(pFrameBuffer->pSTScreen + offset, 1, video_size, fp);
}
}
/* TT/Falcon don't call Video_EndHBL, so pFrameBuffer is unused.
* As a fallback we just copy the video data from ST RAM. */
else
{
video_base = Video_GetScreenBaseAddr();
video_size = (uint32_t)(bpp * sw * sh) / 8;
if ((video_base + video_size) <= STRamEnd)
{
fwrite(STRam + video_base, 1, video_size, fp);
}
else
{
fclose(fp);
return -1;
}

/* Extended RGB palette added as a suffix, in case needed. */
if (bpp <= 8 && (bpp > 4 || !Config_IsMachineST()))
{
fwrite("RGB",1,3,fp);
for (i=0; i < (1 << bpp); i++)
{
col = Screen_GetPaletteColor(i);
fwrite(&col.r, 1, 1, fp);
fwrite(&col.g, 1, 1, fp);
fwrite(&col.b, 1, 1, fp);
}
}
}

fclose (fp);
return 1; /* >0 if OK, -1 if error */
}


/*-----------------------------------------------------------------------*/
/**
Expand All @@ -238,6 +373,17 @@ void ScreenSnapShot_SaveScreen(void)
ScreenSnapShot_GetNum();
/* Create our filename */
nScreenShots++;
/* NEO memory dump */
if (ConfigureParams.Screen.bNEOScreenSnapShot)
{
sprintf(szFileName,"%s/grab%4.4d.neo", Paths_GetScreenShotDir(), nScreenShots);
if (ScreenSnapShot_SaveNEO(szFileName) > 0)
fprintf(stderr, "Screen dump saved to: %s\n", szFileName);
else
fprintf(stderr, "NEO screen dump failed!\n");
free(szFileName);
return;
}
#if HAVE_LIBPNG
/* try first PNG */
sprintf(szFileName,"%s/grab%4.4d.png", Paths_GetScreenShotDir(), nScreenShots);
Expand Down Expand Up @@ -281,6 +427,11 @@ void ScreenSnapShot_SaveToFile(const char *szFileName)
success = SDL_SaveBMP(sdlscrn, szFileName) == 0;
}
else
if (File_DoesFileExtensionMatch(szFileName, ".neo"))
{
success = ScreenSnapShot_SaveNEO(szFileName) == 0;
}
else
{
fprintf(stderr, "ERROR: unknown screen dump file name extension: %s\n", szFileName);
return;
Expand Down