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 screenshot support for more modes still compatible with the format #33

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/includes/screenConvert.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/screenConvert.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 ? */
Expand Down Expand Up @@ -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;
Expand Down
119 changes: 72 additions & 47 deletions src/screenSnapShot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -314,54 +314,68 @@ static void StoreU16NEO(Uint16 val, int offset)
static int ScreenSnapShot_SaveNEO(const char *filename)
{
FILE *fp = NULL;
int i, res, sw, sh, stride, offset;
int i, res, sw, sh, bpp, offset;
SDL_Color col;
uint32_t video_base;

if (pFrameBuffer == NULL || pFrameBuffer->pSTScreen == NULL)
return -1;
uint32_t video_base, line_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. */

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;

/* 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 (genconv)
{
Log_AlertDlg(LOG_ERROR,"The current video mode is not compatible with the .NEO screenshot format");
return -1;
/* 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;
}

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

if (Config_IsMachineFalcon() || Config_IsMachineTT()) /* Compatible ST/STE video modes */
/* Preventing NEO screenshots with unexpected BPP or dimensions. */
if (res > 2)
{
/* Assume resolution based on GenConvert. */
if (ConvertW < ((640+320)/2))
res = 0;
else
res = (ConvertH < ((400+200)/2)) ? 1 : 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;
}
else /* Native ST/STE video modes */
if ((res == 0 && sw != 320) || (res < 2 && sh != 200) || (res > 0 && sw != 640) || (res == 2 && sh != 400))
{
res = (STRes == ST_HIGH_RES) ? 2 :
(STRes == ST_MEDIUM_RES) ? 1 :
0;
/* 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;
}

sw = (res > 0) ? 640 : 320;
sh = (res == 2) ? 400 : 200;
stride = (res == 2) ? 80 : 160;
fp = fopen(filename, "wb");
if (!fp)
return -1;

memset(NEOHeader, 0, sizeof(NEOHeader));
StoreU16NEO(res, 2);
if (!Screen_UseGenConvScreen()) /* Low/Medium resolution: use middle line's palette for whole image */
StoreU16NEO(res, 2); /* NEO resolution word is the primary indicator of BPP. */

/* 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));
}
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(
Expand All @@ -370,36 +384,47 @@ static int ScreenSnapShot_SaveNEO(const char *filename)
((col.b >> 5) << 0),
4+(2*i));
}
/* 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);
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);

if (!Config_IsMachineFalcon() && !Config_IsMachineTT())
/* ST modes fill pFrameBuffer->pSTScreen from each scanline, during Video_EndHBL. */
line_size = (uint32_t)(bpp * ((sw + 15) & ~15)) / 8; /* size of line data in bytes */
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)
{
fwrite(STRam + video_base, 1, 32000, fp);
}
else
{
fclose(fp);
return -1;
}
video_base = Video_GetScreenBaseAddr();

for (i = 0; i < sh; i++)
{
if ((video_base + line_size) <= STRamEnd)
{
fwrite(STRam + video_base, 1, line_size, fp);
video_base += ConvertNextLine;
}
else
{
fclose(fp);
return -1;
}
}
}

fclose (fp);
Expand Down