Skip to content

Commit

Permalink
Added support for saving SSX screen files
Browse files Browse the repository at this point in the history
These files hold the display memory data for the main screen area,
followed by the CLUT indices into the 128 SAM palette colours. They are
static image formats intended for preservation use.

Mid-display changes to VMPR or CLUT will give the wrong result for the
formats above, and if detected a raster-accurate representation of the
display is saved instead (512x192 palette indices).

A new SaveSSX action (51) is available for key bindings. Two screenshot
saving items are available on the Record menu in the Windows version.
  • Loading branch information
simonowen committed May 24, 2020
1 parent aa3f162 commit 270dd77
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 18 deletions.
11 changes: 8 additions & 3 deletions Base/Actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,12 @@ bool Do(Action action, bool pressed/*=true*/)
}
break;

case Action::SaveScreenshot:
Frame::SaveScreenshot();
case Action::SavePNG:
Frame::SavePNG();
break;

case Action::SaveSSX:
Frame::SaveSSX();
break;

case Action::Debugger:
Expand Down Expand Up @@ -394,7 +398,7 @@ std::string to_string(Action action)
{ Action::Debugger, "Debugger" },
{ Action::ImportData, "Import data" },
{ Action::ExportData, "Export data" },
{ Action::SaveScreenshot, "Save screenshot" },
{ Action::SavePNG, "Save screenshot (PNG)" },
{ Action::ResetButton, "Reset button" },
{ Action::NmiButton, "NMI button" },
{ Action::Pause, "Pause" },
Expand Down Expand Up @@ -429,6 +433,7 @@ std::string to_string(Action action)
{ Action::TapeInsert, "Insert Tape" },
{ Action::TapeEject, "Eject Tape" },
{ Action::TapeBrowser, "Tape Browser" },
{ Action::SaveSSX, "Save screenshot (SSX)" },
};

auto it = action_descs.find(action);
Expand Down
4 changes: 2 additions & 2 deletions Base/Actions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ enum class Action
{
NewDisk1, InsertFloppy1, EjectFloppy1, SaveFloppy1, NewDisk2, InsertFloppy2,
EjectFloppy2, SaveFloppy2, ExitApplication, Options, Debugger, ImportData,
ExportData, SaveScreenshot, ChangeProfiler_REMOVED, ResetButton, NmiButton,
ExportData, SavePNG, ChangeProfiler_REMOVED, ResetButton, NmiButton,
Pause, FrameStep, ToggleTurbo, TempTurbo, ToggleScanHiRes, ToggleFullscreen,
ChangeWindowSize_REMOVED, ChangeBorders_REMOVED, Toggle5_4, ToggleFilter,
ToggleScanlines, ToggleGreyscale, ToggleMute, ReleaseMouse, PrinterOnline,
FlushPrinter, About, Minimise, RecordGif, RecordGifLoop, RecordGifStop,
RecordWav, RecordWavSegment, RecordWavStop, RecordAvi, RecordAviHalf,
RecordAviStop, SpeedFaster, SpeedSlower, SpeedNormal, Paste, TapeInsert,
TapeEject, TapeBrowser
TapeEject, TapeBrowser, SaveSSX
};

namespace Actions
Expand Down
26 changes: 20 additions & 6 deletions Base/Frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include "OSD.h"
#include "PNG.h"
#include "Sound.h"
#include "SSX.h"
#include "Util.h"
#include "UI.h"

Expand All @@ -64,7 +65,7 @@ int s_nViewLeft, s_nViewRight;
CScreen* pScreen, * pLastScreen, * pGuiScreen, * pLastGuiScreen, * pDisplayScreen;
CFrame* pFrame;

bool fDrawFrame, g_fFlashPhase, fSaveScreen;
bool fDrawFrame, g_fFlashPhase, fSavePNG, fSaveSSX;
int nFrame;

int nLastLine, nLastBlock; // Line and block we've drawn up to so far this frame
Expand Down Expand Up @@ -346,6 +347,8 @@ static void DrawRaster(CScreen* pScreen_)
// Begin the frame by copying from the previous frame, up to the last cange
void Begin()
{
display_changed = false;

// Return if we're skipping this frame
if (!fDrawFrame)
return;
Expand Down Expand Up @@ -392,10 +395,18 @@ void End()
else
{
// Screenshot required?
if (fSaveScreen)
if (fSavePNG)
{
PNG::Save(pScreen);
fSaveScreen = false;
fSavePNG = false;
}

if (fSaveSSX)
{
auto main_x = (BORDER_BLOCKS - s_nViewLeft) << 4;
auto main_y = (TOP_BORDER_LINES - s_nViewTop);
SSX::Save(pScreen, main_x, main_y);
fSaveSSX = false;
}

// Add the frame to any recordings
Expand Down Expand Up @@ -583,12 +594,15 @@ void DrawOSD(CScreen* pScreen_)
}
}

// Screenshot save request
void SaveScreenshot()
void SavePNG()
{
fSaveScreen = true;
fSavePNG = true;
}

void SaveSSX()
{
fSaveSSX = true;
}

// Set a status message, which will remain on screen for a few seconds
void SetStatus(const char* pcszFormat_, ...)
Expand Down
3 changes: 2 additions & 1 deletion Base/Frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ void ChangeScreen(BYTE bNewBorder_);

void Sync();
void Redraw();
void SaveScreenshot();
void SavePNG();
void SaveSSX();

int GetWidth();
int GetHeight();
Expand Down
2 changes: 1 addition & 1 deletion Base/PNG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ bool Save(CScreen* pScreen_)

// Report what happened
if (fRet)
Frame::SetStatus("Saved %s", pszFile);
Frame::SetStatus("Saved %s", szPath);
else
Frame::SetStatus("PNG save failed!?");
#else
Expand Down
18 changes: 16 additions & 2 deletions Base/SAMIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ BYTE keyports[9]; // 8 rows of keys (+ 1 row for unscanned keys)
BYTE keybuffer[9]; // working buffer for key changed, activated mid-frame

bool fASICStartup; // If set, the ASIC will be unresponsive shortly after first power-on
bool display_changed; // Mid-frame main display change using VMPR or CLUT

int g_nAutoLoad = AUTOLOAD_NONE; // don't auto-load on startup

Expand Down Expand Up @@ -323,6 +324,14 @@ void OutVmpr(BYTE bVal_)
// The ASIC changes mode before page, so consider an on-screen artifact from the mode change
Frame::ChangeMode(bVal_);

if ((vmpr ^ bVal_) & (VMPR_MODE_MASK | VMPR_PAGE_MASK))
{
int line;
Frame::GetRasterPos(&line);
if (IsScreenLine(line))
display_changed = true;
}

vmpr = bVal_ & (VMPR_MODE_MASK | VMPR_PAGE_MASK);
vmpr_mode = VMPR_MODE;

Expand Down Expand Up @@ -354,6 +363,11 @@ void OutClut(WORD wPort_, BYTE bVal_)
// Has the clut value actually changed?
if (clut[wPort_] != bVal_)
{
int line;
Frame::GetRasterPos(&line);
if (IsScreenLine(line))
display_changed = true;

// Draw up to the current point with the previous settings
Frame::Update();

Expand Down Expand Up @@ -434,13 +448,13 @@ BYTE In(WORD wPort_)
bRet = lmpr;
break;

// High memory page register
// High memory page register
case HMPR_PORT:
bRet = hmpr;
break;


// Video memory page register
// Video memory page register
case VMPR_PORT:
bRet = vmpr;
bRet |= 0x80; // RXMIDI bit always one for now
Expand Down
1 change: 1 addition & 0 deletions Base/SAMIO.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,4 @@ extern CDiskDevice* pFloppy1, * pFloppy2, * pBootDrive;
extern CIoDevice* pParallel1, * pParallel2;

extern int g_nAutoLoad;
extern bool display_changed;
101 changes: 101 additions & 0 deletions Base/SSX.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Part of SimCoupe - A SAM Coupe emulator
//
// SSX.cpp: SAM main screen data saving in raw formats
//
// These files hold the display memory data for the main screen area,
// followed by the CLUT indices into the 128 SAM palette colours.
//
// MODE 1 = 6144 data + 768 attrs + 16 CLUT = 6928 bytes.
// MODE 2 = 6144 data + 6144 attrs + 16 CLUT = 12304 bytes.
// MODE 3 = 24576 data + 4 CLUT = 24580 bytes.
// MODE 4 = 24576 data + 16 CLUT = 24592 bytes.
//
// Mid-display changes to VMPR or CLUT will give the wrong result for
// the dumps above. If detected the file is written in a different format:
//
// 512x192 pixels, each holding palette index (0-127) = 98304 bytes.
//
// The extra horizontal resolution is required for MODE 3. In other modes
// each native pixel is represented by a pair of thin pixels.

#include "SimCoupe.h"
#include "SAMIO.h"
#include "Memory.h"

namespace SSX
{

bool Save(CScreen* screen, int main_x, int main_y)
{
char szPath[MAX_PATH]{};
Util::GetUniqueFile("ssx", szPath, sizeof(szPath));

auto file = fopen(szPath, "wb");
if (!file)
{
Frame::SetStatus("Failed to open %s for writing!", szPath);
return false;
}

if (display_changed)
{
for (auto y = 0; y < SCREEN_LINES; ++y)
fwrite(screen->GetLine(main_y + y) + main_x, 2, SCREEN_PIXELS, file);
}
else
{
auto vmpr_page = VMPR_PAGE;
auto screen_mode = 1 + (VMPR_MODE >> VMPR_MODE_SHIFT);

const void* ptr0 = PageReadPtr(vmpr_page);
const void* ptr1 = nullptr;
size_t size0 = 0;
size_t size1 = 0;

switch (screen_mode)
{
case 1:
ptr0 = PageReadPtr(vmpr_page);
size0 = 32*192 + 32*24;
break;
case 2:
ptr0 = PageReadPtr(vmpr_page);
ptr1 = PageReadPtr(vmpr_page) + 0x2000;
size0 = size1 = 32*192;
break;
case 3:
case 4:
{
vmpr_page &= ~1;
ptr0 = PageReadPtr(vmpr_page);
ptr1 = PageReadPtr((vmpr_page + 1) & (MEM_PAGE_SIZE - 1));
size0 = 128*128;
size1 = 128*64;
break;
}
}

if (ptr0 && size0)
fwrite(ptr0, 1, size0, file);
if (ptr1 && size1)
fwrite(ptr1, 1, size1, file);

if (screen_mode == 3)
{
for (int i = 0; i < 4; ++i)
fputc(mode3clut[i], file);
}
else
{
for (int i = 0; i < N_CLUT_REGS; ++i)
fputc(clut[i], file);
}
}

fclose(file);
Frame::SetStatus("Saved %s", szPath);

return true;
}

}
11 changes: 11 additions & 0 deletions Base/SSX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Part of SimCoupe - A SAM Coupe emulator
//
// SSX.h: SAM main screen data saving in raw formats

#pragma once
#include "Screen.h"

namespace SSX
{
bool Save(CScreen* screen, int main_x, int main_y);
}
2 changes: 1 addition & 1 deletion SDL/Input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ bool Input::FilterEvent(SDL_Event* pEvent_)
case HK_KPPLUS: Actions::Do(fCtrl ? Action::TempTurbo : Action::SpeedFaster, fPress); break;
case HK_KPMINUS: Actions::Do(fCtrl ? Action::SpeedNormal : Action::SpeedSlower, fPress); break;

case HK_PRINT: Actions::Do(Action::SaveScreenshot, fPress); break;
case HK_PRINT: Actions::Do(Action::SavePNG, fPress); break;
case HK_SCROLL:
case HK_PAUSE: Actions::Do(fCtrl ? Action::ResetButton : fShift ? Action::FrameStep : Action::Pause, fPress); break;

Expand Down
2 changes: 1 addition & 1 deletion SDL/UI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ bool UI::CheckEvents()
case UE_TOGGLESCANLINES: Actions::Do(Action::ToggleScanlines); break;
case UE_TOGGLE54: Actions::Do(Action::Toggle5_4); break;
case UE_DEBUGGER: Actions::Do(Action::Debugger); break;
case UE_SAVESCREENSHOT: Actions::Do(Action::SaveScreenshot); break;
case UE_SAVESCREENSHOT: Actions::Do(Action::SavePNG); break;
case UE_PAUSE: Actions::Do(Action::Pause); break;
case UE_TOGGLETURBO: Actions::Do(Action::ToggleTurbo); break;
case UE_TOGGLEMUTE: Actions::Do(Action::ToggleMute); break;
Expand Down
3 changes: 3 additions & 0 deletions Win32/SimCoupe.rc
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,9 @@ BEGIN
MENUITEM SEPARATOR
MENUITEM "&Stop Recording", IDM_RECORD_WAV_STOP
END
MENUITEM SEPARATOR
MENUITEM "Save Screenshot (&PNG)" IDM_RECORD_SCREEN_PNG
MENUITEM "Save Screenshot (SS&X)" IDM_RECORD_SCREEN_SSX
END
POPUP "&System"
BEGIN
Expand Down
5 changes: 4 additions & 1 deletion Win32/UI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1824,7 +1824,7 @@ LRESULT CALLBACK WindowProc(HWND hwnd_, UINT uMsg_, WPARAM wParam_, LPARAM lPara
case VK_SNAPSHOT:
case VK_SCROLL:
if (!fPress)
Actions::Do(Action::SaveScreenshot);
Actions::Do(Action::SavePNG);
break;

// Use the default behaviour for anything we're not using
Expand Down Expand Up @@ -1881,6 +1881,9 @@ LRESULT CALLBACK WindowProc(HWND hwnd_, UINT uMsg_, WPARAM wParam_, LPARAM lPara
case IDM_RECORD_WAV_SEGMENT: Actions::Do(Action::RecordWavSegment); break;
case IDM_RECORD_WAV_STOP: Actions::Do(Action::RecordWavStop); break;

case IDM_RECORD_SCREEN_PNG: Actions::Do(Action::SavePNG); break;
case IDM_RECORD_SCREEN_SSX: Actions::Do(Action::SaveSSX); break;

case IDM_TOOLS_OPTIONS: Actions::Do(Action::Options); break;
case IDM_TOOLS_PASTE_CLIPBOARD: Actions::Do(Action::Paste); break;
case IDM_TOOLS_PRINTER_ONLINE: Actions::Do(Action::PrinterOnline); break;
Expand Down
2 changes: 2 additions & 0 deletions Win32/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@
#define IDM_RECORD_GIF_START 40231
#define IDM_RECORD_WAV_START 40232
#define IDM_RECORD_AVI_HALF 40235
#define IDM_RECORD_SCREEN_PNG 40236
#define IDM_RECORD_SCREEN_SSX 40237
#define IDM_SYSTEM_SPEED_50 40250
#define IDM_SYSTEM_SPEED_100 40251
#define IDM_SYSTEM_SPEED_200 40252
Expand Down

0 comments on commit 270dd77

Please sign in to comment.