Merge tag 'v1.28.0.0'

# Conflicts:
#	source/SaveState.cpp

Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
This commit is contained in:
Andrea Odetti 2019-04-19 20:45:50 +01:00
commit 2ee0a01959
42 changed files with 1098 additions and 468 deletions

View file

@ -913,6 +913,14 @@
RelativePath=".\source\Video.h"
>
</File>
<File
RelativePath=".\source\Video_OriginalColorTVMode.cpp"
>
</File>
<File
RelativePath=".\source\Video_OriginalColorTVMode.h"
>
</File>
</Filter>
<Filter
Name="Configuration"

View file

@ -8,9 +8,22 @@ https://github.com/AppleWin/AppleWin/issues/new
Tom Charlesworth
1.28.0.0 - 12 Jan 2019
----------------------
. [Change #357] Resurrected the AppleWin 1.25 "Color (Standard)" video mode as "Color (RGB Monitor)".
- This is equivalent to emulating RGB video, ie. a video mode with sharp text and pixels.
- NB. Unlike AppleWin 1.25, this is now cycle-accurate, so demos that synchronise with the video scanner will work correctly.
. [Change #603] Removed support for v1 save-state files.
- Any v1 save-state files should be loaded into AppleWin 1.27, and then re-saved to a v2 save-state file.
. [Change #597] Removed the functionality for CTRL+F10 to reveal the mouse cursor.
. [Change #585] Added a 'Swap' HDD button to the Configuration->Input property sheet.
. [Bug #608] Mockingboard's 6522 TIMER1 wasn't generating an interrupt quickly enough for Broadside's detection routine.
1.27.13.0 - 8 Dec 2018
----------------------
. [Bug #599] Fix for Ultima V not loading in Authentic Speed mode (regression introduced at 1.27.9.0).
. [Bug #303, #599] Fix for Ultima V not loading in Authentic Speed mode (regression introduced at 1.27.9.0).
. [Change #205] Added support for Apple II/II+ custom 2K video ROMs.
- Extended command line switch: -videorom <file>
- If the ROM size is 2K, then it replaces the video ROM for the Apple II/II+.

View file

@ -46,8 +46,7 @@
Use custom 2K ROM for any Apple II machine at [$F800..$FFFF]. &lt;file&gt; must be 2048 bytes long<br><br>
-videorom &lt;file&gt;<br>
Use an alternate custom 2K video ROM for Apple II or II+ machines (but not clones).<br>
Use an alternate European or custom 4K, 8K or 16K (top 8K only) video ROM for the Enhanced //e.<br>
NB. There's currently no support for using an alternate video ROM for the original Apple //e or clones.<br><br>
Use an alternate European or custom 4K, 8K or 16K (top 8K only) video ROM for the original or Enhanced //e (but not clones).<br><br>
-printscreen<br>
Enable the dialog box to display the last file saved to<br><br>
-no-printscreen-key<br>

View file

@ -1,23 +1,13 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Disk Settings</title>
</head>
<body style="background-color: rgb(255, 255, 255); font-family: verdana;" alink="#008000" link="#008000" vlink="#008000">
<h2 style="color: rgb(0, 128, 0);">Disk Settings</h2>
<hr size="4"><img style="width: 344px; height: 460px; float: right;" src="img/disk.png" alt="Disk settings" hspace="5" vspace="5">
<h3>Floppy Controller Settings:</h3>
<p><strong>Disk Access Speed:</strong><br>
Here you can choose the speed at which the system can access
@ -26,14 +16,14 @@ By default, you would want "Enhanced Speed" so that data can
be accessed as fast as possible. However, it is also possible that
certain programs might depend on the "Authentic Speed" to function
properly. This is the speed at which the real hardware
would&nbsp;access data from your drives.</p>
would&nbsp;access data from your drives.
</p>
<p><strong>Disk 1/2 drop-down menus:</strong><br>
These menus allow you to select floppy disk images (.dsk files) to
'insert' into the
emulated floppy drives 1 and 2. This can also be done during emulation by <a href="toolbar.html">using the toolbar</a> or using the F3/F4 keys. Diskettes can be swapped by pressing F5 during emulation. You can also eject images from this menu.</p>
emulated floppy drives 1 and 2. This can also be done during emulation by <a href="toolbar.html">using the toolbar</a> or using the F3/F4 keys. Diskettes can be swapped by pressing F5 during emulation. You can also eject images from this menu.
</p>
<h3>Hard disk Controller Settings:</h3>
@ -42,16 +32,20 @@ A hard disk controller (or interface) card can be plugged in to slot 7 by checki
See <a href="ddi-harddisk.html">Hard disk Images</a> for more details.
</p>
<p><strong>Swap:</strong><br>
Swap the hard disk images.<br>
WARNING! If done during image access this could result in undefined behavior (eg. Apple II program crash) or data corruption on the image.
</p>
<p><strong>HDD 1/2 drop-down menus:</strong><br>
These menus allow you to select hard disk images (eg. .hdv files) to
connect to the emulated hard disk controller card. You can also unplug images from this menu.</p>
<strong>Path to CiderPress:</strong><br>
connect to the emulated hard disk controller card. You can also unplug images from this menu.
</p>
<p><strong>Path to CiderPress:</strong><br>
Use this to specify where CiderPress is installed.<br>
The right mouse button context menu on either of the drive icons allows you to open CiderPress with the image in the drive.
</p>
</body>
</html>

View file

@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Transferring Disk Images</title>
<title>Hard Disk Images</title>
</head>
@ -20,8 +20,9 @@
Just check <span style="font-style: italic;">Enable hard disk controller in slot 7</span>.</p>
<p>There is provision to connect two hard disks to this card.
This is done by using .hdv files on your PC.
This is done by using .hdv or 800KB .2mg files on your PC.
Each hard disk can have a maximum capacity of 32MB.</p>
NB. The hard disk controller supports both fixed-disk types (up to 32MB) and 3.5" floppy types (800KB).
<p>On booting, the Apple will <span style="text-decoration: underline;">always</span>
attempt to
@ -33,9 +34,6 @@ interface card in it).</p>
<p>To boot a floppy disk with the hard disk card enabled, either hold down the Open-Apple key during an Apple II restart or
issue PR#6 from an AppleSoft prompt.</p>
<p>You can download sample .hdv
images from Asimov (eg. <a target="_blank" href="ftp://public.asimov.net/pub/apple_II/">ftp://public.asimov.net/pub/apple_II/images/utility/misc/hardpc.zip</a>).</p>
<p style="font-weight: bold;">Warnings:</p>
<ul>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View file

@ -74,6 +74,8 @@
Copy the text screen (auto detect 40/80 columns) to the clipboard.</p>
<p><span style="font-weight: bold;">Alt+Enter:</span><br>
Default: Toggle between windowed and full screen video modes. (NB. Will conflict with emulation and prevent Open Apple + Enter from being readable. Use the <a href="CommandLine.html">Command Line</a> switch to allow Open Apple + Enter to be readable.)</p>
<p><span style="font-weight: bold;">Ctrl+Left Mouse Button:</span><br>
This will show the Windows mouse cursor when emulating an Apple joystick with the PC's mouse or using a Mouse card.<br>
<p><span style="font-weight: bold;">Function Keys F1-F8:</span><br>
These PC function keys correspond to buttons on the <a href="toolbar.html">toolbar</a>.</p>
<p><span style="font-weight: bold;">Function Key F2 + Ctrl:</span><br>
@ -89,9 +91,6 @@
<p><span style="font-weight: bold;">Function Key F10:</span><br>
In //e or Enhanced //e emulation mode it will emulate the rocker switch for European video ROM selection. Use the <a href="CommandLine.html">Command Line</a> switch to use an alternate European video ROM file.<br>
In Pravets 8A emulation mode it servers as Caps Lock.</p>
<p><span style="font-weight: bold;">Function Key F10 + Ctrl (or Ctrl+left mouse button):</span><br>
This PC function key combo will stop emulating an Apple joystick with the PC's mouse.<br>
<p><span style="font-weight: bold;">Function Keys F11-F12:</span><br>
These PC function keys correspond to saving/loading a <a href="savestate.html">save-state</a>
file.</p>
<p><span style="font-weight: bold;">Function Keys F11-F12:</span><br>
These PC function keys correspond to saving/loading a <a href="savestate.html">save-state</a> file.</p>
</body></html>

View file

@ -12,7 +12,7 @@
Copyright © 1994-1996, Michael O'Brien<br>
Copyright © 2001, Oliver Schmidt<br>
Copyright © 2002-2005, Tom Charlesworth<BR>
Copyright © 2006-2018, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis
Copyright © 2006-2019, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis
<br>
<br>
<a href="applewin-team.html">AppleWin team</a>

View file

@ -175,6 +175,7 @@ BEGIN
GROUPBOX "Hard Disk Drives",IDC_STATIC,5,83,200,64
CONTROL "&Enable hard disk controller in slot 7",IDC_HDD_ENABLE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,96,122,10
PUSHBUTTON "Swap",IDC_HDD_SWAP,156,92,40,14
LTEXT "&Path to CiderPress:",IDC_STATIC,7,155,74,8
EDITTEXT IDC_CIDERPRESS_FILENAME,7,165,143,12,ES_AUTOHSCROLL | ES_READONLY
PUSHBUTTON "&Browse...",IDC_CIDERPRESS_BROWSE,156,164,50,14
@ -274,7 +275,7 @@ BEGIN
VALUE "FileDescription", "Apple //e Emulator for Windows"
VALUE "FileVersion", APPLEWIN_VERSION_STR
VALUE "InternalName", "APPLEWIN"
VALUE "LegalCopyright", " 1994-2018 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis"
VALUE "LegalCopyright", " 1994-2019 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis"
VALUE "OriginalFilename", "APPLEWIN.EXE"
VALUE "ProductName", "Apple //e Emulator"
VALUE "ProductVersion", APPLEWIN_VERSION_STR

View file

@ -66,6 +66,7 @@
#define IDC_EDIT_HDD1 1019
#define IDC_EDIT_HDD2 1020
#define IDC_HDD_ENABLE 1021
#define IDC_HDD_SWAP 1022
#define IDC_SPIN_XTRIM 1026
#define IDC_SPIN_YTRIM 1027
#define IDC_PHASOR_ENABLE 1029

View file

@ -1,4 +1,4 @@
#define APPLEWIN_VERSION 1,27,13,0
#define APPLEWIN_VERSION 1,28,0,0
#define xstr(a) str(a)
#define str(a) #a

View file

@ -60,6 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static UINT16 g_AppleWinVersion[4] = {0};
char VERSIONSTRING[16] = "xx.yy.zz.ww";
static UINT16 g_OldAppleWinVersion[4] = {0};
const TCHAR *g_pAppTitle = NULL;
@ -164,9 +165,9 @@ void SetApple2Type(eApple2Type type)
SetMainCpuDefault(type);
}
const UINT16* GetAppleWinVersion(void)
const UINT16* GetOldAppleWinVersion(void)
{
return &g_AppleWinVersion[0];
return g_OldAppleWinVersion;
}
bool GetLoadedSaveStateFlag(void)
@ -1134,6 +1135,29 @@ static void InsertHardDisks(LPSTR szImageName_harddisk[NUM_HARDDISKS], bool& bBo
MessageBox(g_hFrameWindow, "Failed to insert harddisk(s) - see log file", "Warning", MB_ICONASTERISK | MB_OK);
}
static bool CheckOldAppleWinVersion(void)
{
char szOldAppleWinVersion[sizeof(VERSIONSTRING)] = {0};
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, szOldAppleWinVersion, sizeof(szOldAppleWinVersion));
const bool bShowAboutDlg = strcmp(szOldAppleWinVersion, VERSIONSTRING) != 0;
// version: xx.yy.zz.ww
// offset : 0123456789
char* p0 = szOldAppleWinVersion;
szOldAppleWinVersion[strlen(szOldAppleWinVersion)] = '.'; // Overwrite null terminator with '.'
for (UINT i=0; i<4; i++)
{
char* p1 = strstr(p0, ".");
if (!p1)
break;
*p1 = 0;
g_OldAppleWinVersion[i] = atoi(p0);
p0 = p1+1;
}
return bShowAboutDlg;
}
//---------------------------------------------------------------------------
int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
@ -1477,6 +1501,9 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
g_bRestart = false;
ResetToLogoMode();
// NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video()
const bool bShowAboutDlg = CheckOldAppleWinVersion(); // Post: g_OldAppleWinVersion
LoadConfiguration();
LogFileOutput("Main: LoadConfiguration()\n");
@ -1531,10 +1558,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
MemInitialize();
LogFileOutput("Main: MemInitialize()\n");
char szOldAppleWinVersion[sizeof(VERSIONSTRING)] = {0};
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, szOldAppleWinVersion, sizeof(szOldAppleWinVersion));
const bool bShowAboutDlg = strcmp(szOldAppleWinVersion, VERSIONSTRING) != 0;
// Show About dialog after creating main window (need g_hFrameWindow)
if (bShowAboutDlg)
{
if (!AboutDlg())

View file

@ -9,7 +9,7 @@ void LogFileTimeUntilFirstKeyRead(void);
void SetCurrentCLK6502();
bool SetCurrentImageDir(const char* pszImageDir);
extern const UINT16* GetAppleWinVersion(void);
extern const UINT16* GetOldAppleWinVersion(void);
extern char VERSIONSTRING[]; // Constructed in WinMain()
extern const TCHAR *g_pAppTitle;

View file

@ -427,6 +427,13 @@ static __forceinline void CheckInterruptSources(ULONG uExecutedCycles)
}
}
// GH#608: IRQ needs to occur within 17 cycles (6 opcodes) of configuring the timer interrupt
void CpuAdjustIrqCheck(UINT uCyclesUntilInterrupt)
{
if (uCyclesUntilInterrupt < IRQ_CHECK_TIMEOUT)
g_nIrqCheckTimeout = uCyclesUntilInterrupt;
}
//===========================================================================
#include "CPU/cpu6502.h" // MOS 6502
@ -650,22 +657,6 @@ void CpuReset()
//===========================================================================
void CpuSetSnapshot_v1(const BYTE A, const BYTE X, const BYTE Y, const BYTE P, const BYTE SP, const USHORT PC, const unsigned __int64 CumulativeCycles)
{
regs.a = A;
regs.x = X;
regs.y = Y;
regs.ps = P | (AF_RESERVED | AF_BREAK);
regs.sp = ((USHORT)SP) | 0x100;
regs.pc = PC;
CpuIrqReset();
CpuNmiReset();
g_nCumulativeCycles = CumulativeCycles;
}
//
#define SS_YAML_KEY_CPU_TYPE "Type"
#define SS_YAML_KEY_REGA "A"
#define SS_YAML_KEY_REGX "X"

View file

@ -14,6 +14,7 @@ struct regsrec
extern regsrec regs;
extern unsigned __int64 g_nCumulativeCycles;
void CpuAdjustIrqCheck(UINT uCyclesUntilInterrupt);
void CpuDestroy ();
void CpuCalcCycles(ULONG nExecutedCycles);
DWORD CpuExecute(const DWORD uCycles, const bool bVideoUpdate);
@ -27,7 +28,6 @@ void CpuNmiReset();
void CpuNmiAssert(eIRQSRC Device);
void CpuNmiDeassert(eIRQSRC Device);
void CpuReset ();
void CpuSetSnapshot_v1(const BYTE A, const BYTE X, const BYTE Y, const BYTE P, const BYTE SP, const USHORT PC, const unsigned __int64 CumulativeCycles);
void CpuSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void CpuLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);

View file

@ -115,7 +115,9 @@ BOOL CPageDisk::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM l
case IDC_HDD_ENABLE:
EnableHDD(hWnd, IsDlgButtonChecked(hWnd, IDC_HDD_ENABLE));
break;
case IDC_HDD_SWAP:
HandleHDDSwap(hWnd);
break;
case IDC_CIDERPRESS_BROWSE:
{
std::string CiderPressLoc = m_PropertySheetHelper.BrowseToFile(hWnd, TEXT("Select path to CiderPress"), REGVALUE_CIDERPRESSLOC, TEXT("Applications (*.exe)\0*.exe\0") TEXT("All Files\0*.*\0") );
@ -131,8 +133,6 @@ BOOL CPageDisk::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM l
m_PropertySheetHelper.FillComboBox(hWnd, IDC_DISKTYPE, m_discchoices, Disk_GetEnhanceDisk() ? 1 : 0);
m_PropertySheetHelper.FillComboBox(hWnd, IDC_COMBO_DISK1, m_defaultDiskOptions, -1);
m_PropertySheetHelper.FillComboBox(hWnd, IDC_COMBO_DISK2, m_defaultDiskOptions, -1);
m_PropertySheetHelper.FillComboBox(hWnd, IDC_COMBO_HDD1, m_defaultHDDOptions, -1);
m_PropertySheetHelper.FillComboBox(hWnd, IDC_COMBO_HDD2, m_defaultHDDOptions, -1);
if (strlen(DiskGetFullName(DRIVE_1)) > 0)
{
@ -146,17 +146,7 @@ BOOL CPageDisk::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM l
SendDlgItemMessage(hWnd, IDC_COMBO_DISK2, CB_SETCURSEL, 0, 0);
}
if (strlen(HD_GetFullName(HARDDISK_1)) > 0)
{
SendDlgItemMessage(hWnd, IDC_COMBO_HDD1, CB_INSERTSTRING, 0, (LPARAM)HD_GetFullName(HARDDISK_1));
SendDlgItemMessage(hWnd, IDC_COMBO_HDD1, CB_SETCURSEL, 0, 0);
}
if (strlen(HD_GetFullName(HARDDISK_2)) > 0)
{
SendDlgItemMessage(hWnd, IDC_COMBO_HDD2, CB_INSERTSTRING, 0, (LPARAM)HD_GetFullName(HARDDISK_2));
SendDlgItemMessage(hWnd, IDC_COMBO_HDD2, CB_SETCURSEL, 0, 0);
}
InitComboHDD(hWnd);
TCHAR PathToCiderPress[MAX_PATH] = "";
RegLoadString(TEXT(REG_CONFIG), REGVALUE_CIDERPRESSLOC, 1, PathToCiderPress,MAX_PATH);
@ -176,6 +166,24 @@ BOOL CPageDisk::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM l
return FALSE;
}
void CPageDisk::InitComboHDD(HWND hWnd)
{
m_PropertySheetHelper.FillComboBox(hWnd, IDC_COMBO_HDD1, m_defaultHDDOptions, -1);
m_PropertySheetHelper.FillComboBox(hWnd, IDC_COMBO_HDD2, m_defaultHDDOptions, -1);
if (strlen(HD_GetFullName(HARDDISK_1)) > 0)
{
SendDlgItemMessage(hWnd, IDC_COMBO_HDD1, CB_INSERTSTRING, 0, (LPARAM)HD_GetFullName(HARDDISK_1));
SendDlgItemMessage(hWnd, IDC_COMBO_HDD1, CB_SETCURSEL, 0, 0);
}
if (strlen(HD_GetFullName(HARDDISK_2)) > 0)
{
SendDlgItemMessage(hWnd, IDC_COMBO_HDD2, CB_INSERTSTRING, 0, (LPARAM)HD_GetFullName(HARDDISK_2));
SendDlgItemMessage(hWnd, IDC_COMBO_HDD2, CB_SETCURSEL, 0, 0);
}
}
void CPageDisk::DlgOK(HWND hWnd)
{
const bool bNewEnhanceDisk = SendDlgItemMessage(hWnd, IDC_DISKTYPE,CB_GETCURSEL, 0, 0) ? true : false;
@ -207,6 +215,7 @@ void CPageDisk::EnableHDD(HWND hWnd, BOOL bEnable)
{
EnableWindow(GetDlgItem(hWnd, IDC_COMBO_HDD1), bEnable);
EnableWindow(GetDlgItem(hWnd, IDC_COMBO_HDD2), bEnable);
EnableWindow(GetDlgItem(hWnd, IDC_HDD_SWAP), bEnable);
}
void CPageDisk::EnableDisk(HWND hWnd, BOOL bEnable)
@ -340,19 +349,34 @@ void CPageDisk::HandleDiskCombo(HWND hWnd, UINT driveSelected, UINT comboSelecte
}
}
void CPageDisk::HandleHDDSwap(HWND hWnd)
{
if (!RemovalConfirmation(IDC_HDD_SWAP))
return;
if (!HD_ImageSwap())
return;
InitComboHDD(hWnd);
}
UINT CPageDisk::RemovalConfirmation(UINT uCommand)
{
TCHAR szText[100];
const size_t strLen = sizeof(szText)-1;
bool bMsgBox = true;
if (uCommand == IDC_COMBO_DISK1 || uCommand == IDC_COMBO_DISK2)
wsprintf(szText, "Do you really want to eject the disk in drive-%c ?", '1' + uCommand - IDC_COMBO_DISK1);
_snprintf(szText, strLen, "Do you really want to eject the disk in drive-%c ?", '1' + uCommand - IDC_COMBO_DISK1);
else if (uCommand == IDC_COMBO_HDD1 || uCommand == IDC_COMBO_HDD2)
wsprintf(szText, "Do you really want to unplug harddisk-%c ?", '1' + uCommand - IDC_COMBO_HDD1);
_snprintf(szText, strLen, "Do you really want to unplug harddisk-%c ?", '1' + uCommand - IDC_COMBO_HDD1);
else if (uCommand == IDC_HDD_SWAP)
_snprintf(szText, strLen, "Do you really want to swap the harddisk images?");
else
bMsgBox = false;
szText[strLen] = 0;
if (bMsgBox)
{
int nRes = MessageBox(g_hFrameWindow, szText, TEXT("Eject/Unplug Warning"), MB_ICONWARNING | MB_YESNO | MB_SETFOREGROUND);

View file

@ -25,10 +25,12 @@ protected:
private:
void InitOptions(HWND hWnd);
void InitComboHDD(HWND hWnd);
void EnableHDD(HWND hWnd, BOOL bEnable);
void EnableDisk(HWND hWnd, BOOL bEnable);
void HandleHDDCombo(HWND hWnd, UINT driveSelected, UINT comboSelected);
void HandleDiskCombo(HWND hWnd, UINT driveSelected, UINT comboSelected);
void HandleHDDSwap(HWND hWnd);
UINT RemovalConfirmation(UINT uCommand);
static CPageDisk* ms_this;

View file

@ -1301,94 +1301,6 @@ static BYTE __stdcall Disk_IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON
//===========================================================================
int DiskSetSnapshot_v1(const SS_CARD_DISK2* const pSS)
{
if(pSS->Hdr.UnitHdr.hdr.v1.dwVersion > MAKE_VERSION(1,0,0,2))
return -1;
phases = pSS->phases;
currdrive = pSS->currdrive;
//diskaccessed = pSS->diskaccessed; // deprecated
enhancedisk = pSS->enhancedisk ? true : false;
floppylatch = pSS->floppylatch;
floppymotoron = pSS->floppymotoron;
floppywritemode = pSS->floppywritemode;
// Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1
for(UINT i=0; i<NUM_DRIVES; i++)
{
DiskEject(i); // Remove any disk & update Registry to reflect empty drive
g_aFloppyDrive[i].clear();
}
for(UINT i=0; i<NUM_DRIVES; i++)
{
if(pSS->Unit[i].szFileName[0] == 0x00)
continue;
DWORD dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName);
if(dwAttributes == INVALID_FILE_ATTRIBUTES)
{
// Get user to browse for file
DiskSelectImage(i, pSS->Unit[i].szFileName);
dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName);
}
bool bImageError = false;
if(dwAttributes != INVALID_FILE_ATTRIBUTES)
{
if(DiskInsert(i, pSS->Unit[i].szFileName, dwAttributes & FILE_ATTRIBUTE_READONLY, IMAGE_DONT_CREATE) != eIMAGE_ERROR_NONE)
bImageError = true;
// DiskInsert() sets up:
// . imagename
// . fullname
// . writeprotected
}
//
// strcpy(g_aFloppyDrive[i].fullname, pSS->Unit[i].szFileName);
g_aFloppyDrive[i].track = pSS->Unit[i].track;
g_aFloppyDrive[i].phase = pSS->Unit[i].phase;
g_aFloppyDrive[i].spinning = pSS->Unit[i].spinning;
g_aFloppyDrive[i].writelight = pSS->Unit[i].writelight;
g_aFloppyDrive[i].disk.byte = pSS->Unit[i].byte;
// g_aFloppyDrive[i].disk.writeprotected = pSS->Unit[i].writeprotected;
g_aFloppyDrive[i].disk.trackimagedata = pSS->Unit[i].trackimagedata ? true : false;
g_aFloppyDrive[i].disk.trackimagedirty = pSS->Unit[i].trackimagedirty ? true : false;
g_aFloppyDrive[i].disk.nibbles = pSS->Unit[i].nibbles;
//
if(!bImageError)
{
if((g_aFloppyDrive[i].disk.trackimage == NULL) && g_aFloppyDrive[i].disk.nibbles)
AllocTrack(i);
if(g_aFloppyDrive[i].disk.trackimage == NULL)
bImageError = true;
else
memcpy(g_aFloppyDrive[i].disk.trackimage, pSS->Unit[i].nTrack, NIBBLES_PER_TRACK);
}
if(bImageError)
{
g_aFloppyDrive[i].disk.trackimagedata = false;
g_aFloppyDrive[i].disk.trackimagedirty = false;
g_aFloppyDrive[i].disk.nibbles = 0;
}
}
FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES);
return 0;
}
//===========================================================================
// Unit version history:
// 2: Added: Format Track state & DiskLastCycle
// 3: Added: DiskLastReadLatchCycle

View file

@ -72,7 +72,6 @@ void DiskUpdateDriveState(DWORD);
bool DiskDriveSwap(void);
void DiskLoadRom(LPBYTE pCxRomPeripheral, UINT uSlot);
int DiskSetSnapshot_v1(const struct SS_CARD_DISK2* const pSS);
std::string DiskGetSnapshotCardName(void);
void DiskSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
bool DiskLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);

View file

@ -1316,11 +1316,7 @@ LRESULT CALLBACK FrameWndProc (
}
else if (wparam == VK_F10)
{
if (KeybGetCtrlStatus())
{
SetUsingCursor(FALSE); // Ctrl+F10
}
else if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED)
if (g_Apple2Type == A2TYPE_APPLE2E || g_Apple2Type == A2TYPE_APPLE2EENHANCED)
{
SetVideoRomRockerSwitch( !GetVideoRomRockerSwitch() ); // F10: toggle rocker switch
NTSC_VideoInitAppleType();

View file

@ -695,6 +695,18 @@ void HD_GetLightStatus (Disk_Status_e *pDisk1Status_)
}
}
bool HD_ImageSwap(void)
{
std::swap(g_HardDisk[HARDDISK_1], g_HardDisk[HARDDISK_2]);
HD_SaveLastDiskImage(HARDDISK_1);
HD_SaveLastDiskImage(HARDDISK_2);
FrameRefreshStatus(DRAW_LEDS, false);
return true;
}
//===========================================================================
#define SS_YAML_VALUE_CARD_HDD "Generic HDD"

View file

@ -45,6 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// 1.19.0.0 Hard Disk Status/Indicator Light
void HD_GetLightStatus (Disk_Status_e *pDisk1Status_);
bool HD_ImageSwap(void);
std::string HD_GetSnapshotCardName(void);
void HD_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);

View file

@ -931,13 +931,6 @@ void JoyportControl(const UINT uControl)
//===========================================================================
void JoySetSnapshot_v1(const unsigned __int64 JoyCntrResetCycle)
{
g_nJoyCntrResetCycle = JoyCntrResetCycle;
}
//
#define SS_YAML_KEY_COUNTERRESETCYCLE "Counter Reset Cycle"
#define SS_YAML_KEY_JOY0TRIMX "Joystick0 TrimX"
#define SS_YAML_KEY_JOY0TRIMY "Joystick0 TrimY"

View file

@ -25,7 +25,6 @@ void JoySetTrim(short nValue, bool bAxisX);
short JoyGetTrim(bool bAxisX);
void JoyportControl(const UINT uControl);
void JoySetHookAltKeys(bool hook);
void JoySetSnapshot_v1(const unsigned __int64 JoyCntrResetCycle);
void JoySaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void JoyLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);

View file

@ -544,13 +544,6 @@ void KeybToggleP8ACapsLock ()
//===========================================================================
void KeybSetSnapshot_v1(const BYTE LastKey)
{
keycode = LastKey;
}
//
#define SS_YAML_KEY_LASTKEY "Last Key"
#define SS_YAML_KEY_KEYWAITING "Key Waiting"

View file

@ -18,6 +18,5 @@ void KeybToggleP8ACapsLock ();
void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended);
BYTE KeybReadData (void);
BYTE KeybReadFlag (void);
void KeybSetSnapshot_v1(const BYTE LastKey);
void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version);

View file

@ -229,7 +229,7 @@ static void ResetDefaultMachineMemTypes(void)
g_MemTypeAppleIIe = CT_Extended80Col;
}
// Called from MemInitialize(), MemLoadSnapshot(), MemSetSnapshot_v1()
// Called from MemInitialize(), MemLoadSnapshot()
static void SetExpansionMemTypeDefault(void)
{
SS_CARDTYPE defaultType = IsApple2Original(GetApple2Type()) ? g_MemTypeAppleII
@ -1702,7 +1702,6 @@ inline DWORD getRandomTime()
// Called by:
// . MemInitialize()
// . ResetMachineState() eg. Power-cycle ('Apple-Go' button)
// . Snapshot_LoadState_v1()
// . Snapshot_LoadState_v2()
void MemReset()
{
@ -2037,29 +2036,6 @@ LPVOID MemGetSlotParameters(UINT uSlot)
// . If we were to save the state when 'modechanging' is set, then on restoring the state, the 6502 code will immediately update the read memory mode.
// . This will work correctly.
void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux)
{
// Create default LC type for AppleII machine (do prior to loading saved LC state)
ResetDefaultMachineMemTypes();
g_MemTypeAppleII = CT_LanguageCard; // SSv1 doesn't save machine type - so if current machine is Apple II then give it 64K + LC
SetExpansionMemTypeDefault();
CreateLanguageCard(); // Create LC here, as for SSv1 there is no slot-0 state
SetMemMode(MemMode ^ MF_INTCXROM); // Convert from SLOTCXROM to INTCXROM
SetLastRamWrite(LastWriteRam);
memcpy(memmain, pMemMain, nMemMainSize);
memcpy(memaux, pMemAux, nMemAuxSize);
memset(memdirty, 0, 0x100);
//
// NB. MemUpdatePaging(TRUE) called at end of Snapshot_LoadState_v1()
UpdatePaging(1); // Initialize=1
}
//
#define SS_YAML_KEY_MEMORYMODE "Memory Mode"
#define SS_YAML_KEY_LASTRAMWRITE "Last RAM Write"
#define SS_YAML_KEY_IOSELECT "IO_SELECT"

View file

@ -81,7 +81,6 @@ void MemReset ();
void MemResetPaging ();
void MemUpdatePaging(BOOL initialize);
LPVOID MemGetSlotParameters (UINT uSlot);
void MemSetSnapshot_v1(const DWORD MemMode, const BOOL LastWriteRam, const BYTE* const pMemMain, const BYTE* const pMemAux);
std::string MemGetSnapshotUnitAuxSlotName(void);
void MemSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
bool MemLoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT version);

View file

@ -427,6 +427,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
pMB->sy6522.TIMER1_COUNTER.w = pMB->sy6522.TIMER1_LATCH.w;
StartTimer1(pMB);
CpuAdjustIrqCheck(pMB->sy6522.TIMER1_LATCH.w); // Sync IRQ check timeout with 6522 counter underflow - GH#608
break;
case 0x07: // TIMER1H_LATCH
// Clear Timer1 Interrupt Flag.
@ -444,6 +445,7 @@ static void SY6522_Write(BYTE nDevice, BYTE nReg, BYTE nValue)
pMB->sy6522.TIMER2_COUNTER.w = pMB->sy6522.TIMER2_LATCH.w;
StartTimer2(pMB);
CpuAdjustIrqCheck(pMB->sy6522.TIMER1_LATCH.w); // Sync IRQ check timeout with 6522 counter underflow - GH#608
break;
case 0x0a: // SERIAL_SHIFT
break;
@ -1871,52 +1873,6 @@ void MB_GetSnapshot_v1(SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot)
}
}
int MB_SetSnapshot_v1(const SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD /*dwSlot*/)
{
if(pSS->Hdr.UnitHdr.hdr.v1.dwVersion != MAKE_VERSION(1,0,0,0))
return -1;
UINT nMbCardNum = pSS->Hdr.Slot - SLOT4;
UINT nDeviceNum = nMbCardNum*2;
SY6522_AY8910* pMB = &g_MB[nDeviceNum];
g_nSSI263Device = 0;
g_nCurrentActivePhoneme = -1;
for(UINT i=0; i<MB_UNITS_PER_CARD_v1; i++)
{
memcpy(&pMB->sy6522, &pSS->Unit[i].RegsSY6522, sizeof(SY6522));
memcpy(AY8910_GetRegsPtr(nDeviceNum), &pSS->Unit[i].RegsAY8910, 16);
memcpy(&pMB->SpeechChip, &pSS->Unit[i].RegsSSI263, sizeof(SSI263A));
pMB->nAYCurrentRegister = pSS->Unit[i].nAYCurrentRegister;
pMB->state = AY_INACTIVE;
StartTimer1_LoadStateV1(pMB); // Attempt to start timer
//
// Crude - currently only support a single speech chip
// FIX THIS:
// . Speech chip could be Votrax instead
// . Is this IRQ compatible with Phasor?
if(pMB->SpeechChip.DurationPhoneme)
{
g_nSSI263Device = nDeviceNum;
if((pMB->SpeechChip.CurrentMode != MODE_IRQ_DISABLED) && (pMB->sy6522.PCR == 0x0C) && (pMB->sy6522.IER & IxR_PERIPHERAL))
{
UpdateIFR(pMB, 0, IxR_PERIPHERAL);
pMB->SpeechChip.CurrentMode |= 1; // Set SSI263's D7 pin
}
}
nDeviceNum++;
pMB++;
}
return 0;
}
//===========================================================================
// Unit version history:

View file

@ -18,7 +18,6 @@ DWORD MB_GetVolume();
void MB_SetVolume(DWORD dwVolume, DWORD dwVolumeMax);
void MB_GetSnapshot_v1(struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot); // For debugger
int MB_SetSnapshot_v1(const struct SS_CARD_MOCKINGBOARD_v1* const pSS, const DWORD dwSlot);
std::string MB_GetSnapshotCardName(void);
void MB_SaveSnapshot(class YamlSaveHelper& yamlSaveHelper, const UINT uSlot);
bool MB_LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);

View file

@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Frame.h"
#include "Memory.h" // MemGetMainPtr() MemGetAuxPtr()
#include "Video.h" // g_pFramebufferbits
#include "Video_OriginalColorTVMode.h"
#include "NTSC.h"
#include "NTSC_CharSet.h"
@ -470,8 +471,8 @@ static void set_csbits()
{
case A2TYPE_APPLE2: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2PLUS: csbits = &csbits_a2[0]; g_nVideoCharSet = 0; break;
case A2TYPE_APPLE2E: csbits = &csbits_2e[0]; break;
case A2TYPE_APPLE2EENHANCED:csbits = GetEnhanced2e_csbits(); break;
case A2TYPE_APPLE2E: csbits = Get2e_csbits(); break;
case A2TYPE_APPLE2EENHANCED:csbits = Get2e_csbits(); break;
case A2TYPE_PRAVETS82: csbits = &csbits_pravets82[0]; g_nVideoCharSet = 0; break; // Apple ][ clone
case A2TYPE_PRAVETS8M: csbits = &csbits_pravets8M[0]; g_nVideoCharSet = 0; break; // Apple ][ clone
case A2TYPE_PRAVETS8A: csbits = &csbits_pravets8C[0]; break; // Apple //e clone
@ -745,6 +746,26 @@ inline void updatePixels( uint16_t bits )
//===========================================================================
inline void updateVideoScannerHorzEOLSimple()
{
if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz)
{
g_nVideoClockHorz = 0;
if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT)
{
g_nVideoClockVert = 0;
updateFlashRate();
}
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
updateVideoScannerAddress();
}
}
}
#if !EXTEND_14M_VIDEO_BY_1_PIXEL
// NOTE: This writes out-of-bounds for a 560x384 framebuffer
inline void updateVideoScannerHorzEOL()
@ -881,8 +902,8 @@ inline void updateVideoScannerAddress()
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2*g_nVideoClockVert] : g_pScanLines[0];
// Adjust, as these video styles have 2x 14M pixels of pre-render
// NB. For VT_COLOR_MONITOR, also check color-burst so that TEXT and MIXED(HGR+TEXT) render the TEXT at the same offset (GH#341)
if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV || (g_eVideoType == VT_COLOR_MONITOR && GetColorBurst()))
// NB. For VT_COLOR_MONITOR_NTSC, also check color-burst so that TEXT and MIXED(HGR+TEXT) render the TEXT at the same offset (GH#341)
if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV || (g_eVideoType == VT_COLOR_MONITOR_NTSC && GetColorBurst()))
g_pVideoAddress -= 2;
// GH#555: For the 14M video modes (DHGR,DGR,80COL), start rendering 1x 14M pixel early to account for these video modes being shifted right by 1 pixel
@ -890,10 +911,11 @@ inline void updateVideoScannerAddress()
// . 7x 14M pixels early + 1x 14M pixel shifted right = 2 complete color phase rotations.
// . ie. the 14M colors are correct, but being 1 pixel out is the closest we can get the 7M and 14M video modes to overlap.
// . The alternative is to render the 14M correctly 7 pixels early, but have 7-pixel borders left (for 7M modes) or right (for 14M modes).
if ((g_pFuncUpdateGraphicsScreen == updateScreenDoubleHires80) ||
if (((g_pFuncUpdateGraphicsScreen == updateScreenDoubleHires80) ||
(g_pFuncUpdateGraphicsScreen == updateScreenDoubleLores80) ||
(g_pFuncUpdateGraphicsScreen == updateScreenText80) ||
(g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && g_pFuncUpdateTextScreen == updateScreenText80))
&& (g_eVideoType != VT_COLOR_MONITOR_RGB)) // Fix for "Ansi Story" (Turn the disk over) - Top row of TEXT80 is shifted by 1 pixel
{
g_pVideoAddress -= 1;
}
@ -1270,8 +1292,8 @@ inline void zeroPixel0_14M(void) // GH#555
if (g_nVideoClockHorz == VIDEO_SCANNER_HORZ_START)
{
UINT32* p = ((UINT32*)g_pVideoAddress) - 14; // Point back to pixel-0
// NB. For VT_COLOR_MONITOR, also check color-burst so that TEXT and MIXED(HGR+TEXT) render the TEXT at the same offset (GH#341)
if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV || (g_eVideoType == VT_COLOR_MONITOR && GetColorBurst()))
// NB. For VT_COLOR_MONITOR_NTSC, also check color-burst so that TEXT and MIXED(HGR+TEXT) render the TEXT at the same offset (GH#341)
if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV || (g_eVideoType == VT_COLOR_MONITOR_NTSC && GetColorBurst()))
{
p[2] = 0;
p[g_kFrameBufferWidth+2] = 0; // Next line (there are 2 lines per Apple II scanline)
@ -1318,6 +1340,36 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0
}
//===========================================================================
void updateScreenDoubleHires80Simplified (long cycles6502 ) // wsUpdateVideoDblHires
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen( cycles6502 );
return;
}
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = getVideoScannerAddressHGR();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressHGR();
UpdateDHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
@ -1396,6 +1448,36 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores
}
//===========================================================================
static void updateScreenDoubleLores80Simplified (long cycles6502) // wsUpdateVideoDblLores
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen( cycles6502 );
return;
}
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = getVideoScannerAddressTXT();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressTXT();
UpdateDLoResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
@ -1446,6 +1528,33 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores
}
//===========================================================================
static void updateScreenSingleHires40Simplified (long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen( cycles6502 );
return;
}
for (; cycles6502 > 0; --cycles6502)
{
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressHGR();
UpdateHiResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
void updateScreenSingleHires40 (long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
@ -1487,6 +1596,35 @@ void updateScreenSingleHires40 (long cycles6502)
}
//===========================================================================
static void updateScreenSingleLores40Simplified (long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
{
g_pFuncUpdateTextScreen( cycles6502 );
return;
}
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = getVideoScannerAddressTXT();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
g_nColorBurstPixels = 1024;
}
else if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint16_t addr = getVideoScannerAddressTXT();
UpdateLoResCell(g_nVideoClockHorz-VIDEO_SCANNER_HORZ_START, g_nVideoClockVert, addr, g_pVideoAddress);
g_pVideoAddress += 14;
}
}
updateVideoScannerHorzEOLSimple();
}
}
void updateScreenSingleLores40 (long cycles6502)
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
@ -1582,7 +1720,8 @@ void updateScreenText80 (long cycles6502)
aux ^= g_nTextFlashMask;
uint16_t bits = (main << 7) | (aux & 0x7f);
bits = (bits << 1) | g_nLastColumnPixelNTSC; // GH#555: Align TEXT80 chars with DHGR
if (g_eVideoType != VT_COLOR_MONITOR_RGB) // No extra 14M bit needed for VT_COLOR_MONITOR_RGB
bits = (bits << 1) | g_nLastColumnPixelNTSC; // GH#555: Align TEXT80 chars with DHGR
updatePixels( bits );
g_nLastColumnPixelNTSC = (bits >> 14) & 1;
@ -1686,38 +1825,71 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags )
g_nTextPage = 1;
g_nHiresPage = 1;
if (uVideoModeFlags & VF_PAGE2) {
if (uVideoModeFlags & VF_PAGE2)
{
// Apple IIe, Technical Notes, #3: Double High-Resolution Graphics
// 80STORE must be OFF to display page 2
if (0 == (uVideoModeFlags & VF_80STORE)) {
if (0 == (uVideoModeFlags & VF_80STORE))
{
g_nTextPage = 2;
g_nHiresPage = 2;
}
}
if (uVideoModeFlags & VF_TEXT) {
if (uVideoModeFlags & VF_TEXT)
{
if (uVideoModeFlags & VF_80COL)
g_pFuncUpdateGraphicsScreen = updateScreenText80;
else
g_pFuncUpdateGraphicsScreen = updateScreenText40;
}
else if (uVideoModeFlags & VF_HIRES) {
else if (uVideoModeFlags & VF_HIRES)
{
if (uVideoModeFlags & VF_DHIRES)
{
if (uVideoModeFlags & VF_80COL)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80;
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80;
}
else
{
g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires40;
}
}
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40;
}
else {
if (uVideoModeFlags & VF_DHIRES)
if (uVideoModeFlags & VF_80COL)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80;
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40;
}
}
else
{
if (uVideoModeFlags & VF_DHIRES)
{
if (uVideoModeFlags & VF_80COL)
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80;
}
else
{
g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores40;
}
}
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40;
{
if (g_eVideoType == VT_COLOR_MONITOR_RGB)
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40Simplified;
else
g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40;
}
}
}
@ -1745,7 +1917,7 @@ void NTSC_SetVideoStyle() // (int v, int s)
}
break;
case VT_COLOR_MONITOR:
case VT_COLOR_MONITOR_NTSC:
default:
r = 0xFF;
g = 0xFF;
@ -1776,7 +1948,6 @@ void NTSC_SetVideoStyle() // (int v, int s)
}
break;
// case VT_MONO_WHITE: //VT_MONO_MONITOR: //3:
case VT_MONO_AMBER:
r = 0xFF;
g = 0x80;
@ -1789,6 +1960,7 @@ void NTSC_SetVideoStyle() // (int v, int s)
b = 0x00;
goto _mono;
case VT_COLOR_MONITOR_RGB:
case VT_MONO_WHITE:
r = 0xFF;
g = 0xFF;
@ -1820,6 +1992,7 @@ _mono:
//===========================================================================
void GenerateVideoTables( void );
void GenerateBaseColors(baseColors_t pBaseNtscColors);
void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit
{
@ -1842,6 +2015,10 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit
VideoReinitialize(); // Setup g_pFunc_ntsc*Pixel()
bgra_t baseColors[kNumBaseColors];
GenerateBaseColors(&baseColors);
VideoInitializeOriginal(&baseColors);
#if HGR_TEST_PATTERN
// Init HGR to almost all-possible-combinations
// CALL-151
@ -2121,3 +2298,31 @@ static void GenerateVideoTables( void )
VideoResetState();
SetApple2Type(currentApple2Type);
}
void GenerateBaseColors(baseColors_t pBaseNtscColors)
{
for (UINT i=0; i<16; i++)
{
g_nColorPhaseNTSC = INITIAL_COLOR_PHASE;
g_nSignalBitsNTSC = 0;
// 12 iterations for colour to "stabilise", then 4 iterations to calc the average
// - after colour "stabilises" then it repeats through 4 phases (with different RGB values for each phase)
uint32_t bits = (i<<12) | (i<<8) | (i<<4) | i; // 16 bits
uint32_t colors[4];
for (UINT j=0; j<16; j++)
{
colors[j&3] = getScanlineColor(bits & 1, g_aHueColorTV[g_nColorPhaseNTSC]);
bits >>= 1;
updateColorPhase();
}
int r = (((colors[0]>>16)&0xff) + ((colors[1]>>16)&0xff) + ((colors[2]>>16)&0xff) + ((colors[3]>>16)&0xff)) / 4;
int g = (((colors[0]>> 8)&0xff) + ((colors[1]>> 8)&0xff) + ((colors[2]>> 8)&0xff) + ((colors[3]>> 8)&0xff)) / 4;
int b = (((colors[0] )&0xff) + ((colors[1] )&0xff) + ((colors[2] )&0xff) + ((colors[3] )&0xff)) / 4;
uint32_t color = ((r<<16) | (g<<8) | b) | ALPHA32_MASK;
(*pBaseNtscColors)[i] = * (bgra_t*) &color;
}
}

View file

@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "NTSC_CharSet.h"
unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
static unsigned char csbits_enhanced2e_pal[2][256][8]; // PAL Enhanced //e (2764 8K video ROM - top 4K) via rocker switch under keyboard
static unsigned char csbits_2e_pal[2][256][8]; // PAL Original or Enhanced //e (2764 8K video ROM - low 4K) via rocker switch under keyboard
unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext)
unsigned char csbits_a2[1][256][8]; // ][ and ][+
unsigned char csbits_pravets82[1][256][8]; // Pravets 82
@ -164,11 +164,15 @@ void userVideoRomForIIe(void)
if (size == kVideoRomSize4K)
{
userVideoRom4K(&csbits_enhanced2e[0], pVideoRom);
return;
}
else
{
userVideoRom4K(&csbits_2e_pal[0], pVideoRom);
userVideoRom4K(&csbits_enhanced2e[0], &pVideoRom[4*1024]);
}
userVideoRom4K(&csbits_enhanced2e_pal[0], pVideoRom);
userVideoRom4K(&csbits_enhanced2e[0], &pVideoRom[4*1024]);
// NB. Same *custom* US video ROM for Original & Enhanced //e
memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e));
}
//-------------------------------------
@ -224,17 +228,19 @@ void make_csbits(void)
memcpy(csbits_2e, csbits_enhanced2e, sizeof(csbits_enhanced2e));
memcpy(&csbits_2e[1][64], &csbits_2e[0][64], 32*8);
// Try to use any user-provided video ROM for Enhanced //e
// Try to use any user-provided video ROM for Original/Enhanced //e
userVideoRomForIIe();
// Try to use any user-provided video ROM for II/II+
userVideoRomForIIPlus();
}
csbits_t GetEnhanced2e_csbits(void)
csbits_t Get2e_csbits(void)
{
if (IsVideoRom4K())
return csbits_enhanced2e;
const csbits_t videoRom4K = (GetApple2Type() == A2TYPE_APPLE2E) ? csbits_2e : csbits_enhanced2e;
return GetVideoRomRockerSwitch() == false ? csbits_enhanced2e : csbits_enhanced2e_pal;
if (IsVideoRom4K()) // 4K means US-only, so no secondary PAL video ROM
return videoRom4K;
return GetVideoRomRockerSwitch() == false ? videoRom4K : csbits_2e_pal; // NB. Same PAL video ROM for Original & Enhanced //e
}

View file

@ -3,11 +3,10 @@
typedef unsigned char (*csbits_t)[256][8];
extern unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e (2732 4K video ROM)
extern unsigned char csbits_2e[2][256][8]; // Original //e (no mousetext)
extern unsigned char csbits_a2[1][256][8]; // ][ and ][+
extern unsigned char csbits_pravets82[1][256][8]; // Pravets 82
extern unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
extern unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C
void make_csbits(void);
csbits_t GetEnhanced2e_csbits(void);
csbits_t Get2e_csbits(void);

View file

@ -28,7 +28,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "SaveState_Structs_v1.h"
#include "YamlHelper.h"
#include "Applewin.h"
@ -112,129 +111,6 @@ const char* Snapshot_GetPath()
//-----------------------------------------------------------------------------
static void Snapshot_LoadState_v1() // .aws v1.0.0.1, up to (and including) AppleWin v1.25.0
{
std::string strOldImageDir(g_sCurrentDir);
APPLEWIN_SNAPSHOT_v1* pSS = (APPLEWIN_SNAPSHOT_v1*) new char[sizeof(APPLEWIN_SNAPSHOT_v1)]; // throw's bad_alloc
try
{
#if _MSC_VER >= 1600 // static_assert supported from VS2010 (cl.exe v16.00)
static_assert(kSnapshotSize_v1 == sizeof(APPLEWIN_SNAPSHOT_v1), "Save-state v1 struct size mismatch");
#else
#if 0
// A compile error here means sizeof(APPLEWIN_SNAPSHOT_v1) is wrong, eg. one of the constituent structs has been modified
typedef char VerifySizesAreEqual[kSnapshotSize_v1 == sizeof(APPLEWIN_SNAPSHOT_v1) ? 1 : -1];
#endif
#endif
if (kSnapshotSize_v1 != sizeof(APPLEWIN_SNAPSHOT_v1))
throw std::string("Save-state v1 struct size mismatch");
SetCurrentImageDir(g_strSaveStatePath.c_str()); // Allow .dsk's load without prompting
memset(pSS, 0, sizeof(APPLEWIN_SNAPSHOT_v1));
//
HANDLE hFile = CreateFile( g_strSaveStatePathname.c_str(),
GENERIC_READ,
0,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if(hFile == INVALID_HANDLE_VALUE)
throw std::string("File not found: ") + g_strSaveStatePathname;
DWORD dwBytesRead;
BOOL bRes = ReadFile( hFile,
pSS,
sizeof(APPLEWIN_SNAPSHOT_v1),
&dwBytesRead,
NULL);
CloseHandle(hFile);
if(!bRes || (dwBytesRead != sizeof(APPLEWIN_SNAPSHOT_v1)))
// File size wrong: probably because of version mismatch or corrupt file
throw std::string("File size mismatch");
if(pSS->Hdr.dwTag != AW_SS_TAG)
throw std::string("File corrupt");
if(pSS->Hdr.dwVersion != MAKE_VERSION(1,0,0,1))
throw std::string("Version mismatch");
// TO DO: Verify checksum
//
// Reset all sub-systems
MemReset();
DiskReset();
HD_Reset();
KeybReset();
VideoResetState();
MB_Reset();
sg_SSC.CommReset();
//
// Apple2 unit
//
SS_CPU6502& CPU = pSS->Apple2Unit.CPU6502;
CpuSetSnapshot_v1(CPU.A, CPU.X, CPU.Y, CPU.P, CPU.S, CPU.PC, CPU.nCumulativeCycles);
SS_IO_Comms& SSC = pSS->Apple2Unit.Comms;
sg_SSC.SetSnapshot_v1(SSC.baudrate, SSC.bytesize, SSC.commandbyte, SSC.comminactivity, SSC.controlbyte, SSC.parity, SSC.stopbits);
JoySetSnapshot_v1(pSS->Apple2Unit.Joystick.nJoyCntrResetCycle);
KeybSetSnapshot_v1(pSS->Apple2Unit.Keyboard.nLastKey);
SpkrSetSnapshot_v1(pSS->Apple2Unit.Speaker.nSpkrLastCycle);
VideoSetSnapshot_v1(pSS->Apple2Unit.Video.bAltCharSet, pSS->Apple2Unit.Video.dwVidMode);
MemSetSnapshot_v1(pSS->Apple2Unit.Memory.dwMemMode, pSS->Apple2Unit.Memory.bLastWriteRam, pSS->Apple2Unit.Memory.nMemMain, pSS->Apple2Unit.Memory.nMemAux);
//
//
// Slot4: Mockingboard
MB_SetSnapshot_v1(&pSS->Mockingboard1, 4);
//
// Slot5: Mockingboard
MB_SetSnapshot_v1(&pSS->Mockingboard2, 5);
//
// Slot6: Disk][
DiskSetSnapshot_v1(&pSS->Disk2);
SetLoadedSaveStateFlag(true);
MemUpdatePaging(TRUE);
// NB. g_Apple2Type doesn't change for v1, but replicate this (like v2)
VideoReinitialize(); // g_CharsetType changed
FrameUpdateApple2Type();
}
catch(std::string szMessage)
{
MessageBox( g_hFrameWindow,
szMessage.c_str(),
TEXT("Load State"),
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
SetCurrentImageDir(strOldImageDir.c_str());
PostMessage(g_hFrameWindow, WM_USER_RESTART, 0, 0); // Power-cycle VM (undoing all the new state just loaded)
}
delete [] pSS;
}
//-----------------------------------------------------------------------------
static HANDLE m_hFile = INVALID_HANDLE_VALUE;
static CConfigNeedingRestart m_ConfigNew;
@ -566,7 +442,12 @@ void Snapshot_LoadState()
const size_t pos = g_strSaveStatePathname.size() - ext_aws.size();
if (g_strSaveStatePathname.find(ext_aws, pos) != std::string::npos) // find ".aws" at end of pathname
{
Snapshot_LoadState_v1();
MessageBox( g_hFrameWindow,
"Save-state v1 no longer supported.\n"
"Please load using AppleWin 1.27, and re-save as a v2 state file.",
TEXT("Load State"),
MB_ICONEXCLAMATION | MB_SETFOREGROUND);
return;
}

View file

@ -1355,25 +1355,6 @@ void CSuperSerialCard::SetSerialPortName(const char* pSerialPortName)
//===========================================================================
void CSuperSerialCard::SetSnapshot_v1( const DWORD baudrate,
const BYTE bytesize,
const BYTE commandbyte,
const DWORD comminactivity,
const BYTE controlbyte,
const BYTE parity,
const BYTE stopbits)
{
// Redundant:
// . baudrate, stopbits, bytesize (encapsulated in controlbyte)
// . parity (encapsulated in commandbyte)
// Obsolete:
// . comminactivity
UpdateCommandAndControlRegs(commandbyte, controlbyte);
}
//===========================================================================
// Unit version history:
// 2: Added: Support DCD flag
// Removed: redundant data (encapsulated in Command & Control bytes)

View file

@ -32,7 +32,6 @@ public:
void CommReset();
void CommDestroy();
void CommSetSerialPort(HWND hWindow, DWORD dwNewSerialPortItem);
void SetSnapshot_v1(const DWORD baudrate, const BYTE bytesize, const BYTE commandbyte, const DWORD comminactivity, const BYTE controlbyte, const BYTE parity, const BYTE stopbits);
std::string GetSnapshotCardName(void);
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);

View file

@ -931,13 +931,6 @@ void Spkr_DSUninit()
//=============================================================================
void SpkrSetSnapshot_v1(const unsigned __int64 SpkrLastCycle)
{
g_nSpkrLastCycle = SpkrLastCycle;
}
//
#define SS_YAML_KEY_LASTCYCLE "Last Cycle"
static std::string SpkrGetSnapshotStructName(void)

View file

@ -33,7 +33,6 @@ void Spkr_Demute();
bool Spkr_IsActive();
bool Spkr_DSInit();
void Spkr_DSUninit();
void SpkrSetSnapshot_v1(const unsigned __int64 SpkrLastCycle);
void SpkrSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void SpkrLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);

View file

@ -83,14 +83,11 @@ static LPBITMAPINFO g_pFramebufferinfo = NULL;
HBITMAP g_hLogoBitmap;
const int MAX_SOURCE_Y = 512;
static LPBYTE g_aSourceStartofLine[ MAX_SOURCE_Y ];
COLORREF g_nMonochromeRGB = RGB(0xC0,0xC0,0xC0);
uint32_t g_uVideoMode = VF_TEXT; // Current Video Mode (this is the last set one as it may change mid-scan line!)
DWORD g_eVideoType = VT_COLOR_TV;
DWORD g_eVideoType = VT_DEFAULT;
DWORD g_uHalfScanLines = 1; // drop 50% scan lines for a more authentic look
static const bool g_bVideoScannerNTSC = true; // NTSC video scanning (or PAL)
@ -100,9 +97,10 @@ static const bool g_bVideoScannerNTSC = true; // NTSC video scanning (or PAL)
// NOTE: KEEP IN SYNC: VideoType_e g_aVideoChoices g_apVideoModeDesc
TCHAR g_aVideoChoices[] =
TEXT("Monochrome (Custom)\0")
TEXT("Color Monitor\0")
TEXT("B&W TV\0")
TEXT("Color (RGB Monitor)\0")
TEXT("Color (NTSC Monitor)\0")
TEXT("Color TV\0")
TEXT("B&W TV\0")
TEXT("Monochrome (Amber)\0")
TEXT("Monochrome (Green)\0")
TEXT("Monochrome (White)\0")
@ -113,9 +111,10 @@ static const bool g_bVideoScannerNTSC = true; // NTSC video scanning (or PAL)
char *g_apVideoModeDesc[ NUM_VIDEO_MODES ] =
{
"Monochrome Monitor (Custom)"
, "Color Monitor"
, "B&W TV"
, "Color (RGB Monitor)"
, "Color (NTSC Monitor)"
, "Color TV"
, "B&W TV"
, "Amber Monitor"
, "Green Monitor"
, "White Monitor"
@ -720,15 +719,6 @@ bool VideoGetSWAltCharSet(void)
//===========================================================================
void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode)
{
g_nAltCharSetOffset = !AltCharSet ? 0 : 256;
g_uVideoMode = VideoMode;
g_dwCyclesThisFrame = 0;
}
//
#define SS_YAML_KEY_ALTCHARSET "Alt Char Set"
#define SS_YAML_KEY_VIDEOMODE "Video Mode"
#define SS_YAML_KEY_CYCLESTHISFRAME "Cycles This Frame"
@ -1202,14 +1192,42 @@ bool IsVideoRom4K(void)
//===========================================================================
enum VideoType127_e
{
VT127_MONO_CUSTOM
, VT127_COLOR_MONITOR_NTSC
, VT127_MONO_TV
, VT127_COLOR_TV
, VT127_MONO_AMBER
, VT127_MONO_GREEN
, VT127_MONO_WHITE
, VT127_NUM_VIDEO_MODES
};
void Config_Load_Video()
{
REGLOAD(TEXT(REGVALUE_VIDEO_MODE ),&g_eVideoType);
REGLOAD(TEXT(REGVALUE_VIDEO_HALF_SCAN_LINES),&g_uHalfScanLines);
REGLOAD(TEXT(REGVALUE_VIDEO_MONO_COLOR ),&g_nMonochromeRGB);
const UINT16* pOldVersion = GetOldAppleWinVersion();
if (pOldVersion[0] == 1 && pOldVersion[1] <= 27 && pOldVersion[2] <= 13)
{
switch (g_eVideoType)
{
case VT127_MONO_CUSTOM: g_eVideoType = VT_MONO_CUSTOM; break;
case VT127_COLOR_MONITOR_NTSC: g_eVideoType = VT_COLOR_MONITOR_NTSC; break;
case VT127_MONO_TV: g_eVideoType = VT_MONO_TV; break;
case VT127_COLOR_TV: g_eVideoType = VT_COLOR_TV; break;
case VT127_MONO_AMBER: g_eVideoType = VT_MONO_AMBER; break;
case VT127_MONO_GREEN: g_eVideoType = VT_MONO_GREEN; break;
case VT127_MONO_WHITE: g_eVideoType = VT_MONO_WHITE; break;
default: g_eVideoType = VT_DEFAULT; break;
}
}
if (g_eVideoType >= NUM_VIDEO_MODES)
g_eVideoType = VT_COLOR_MONITOR;
g_eVideoType = VT_DEFAULT;
}
void Config_Save_Video()
@ -1242,9 +1260,9 @@ static void videoCreateDIBSection()
);
SelectObject(g_hDeviceDC,g_hDeviceBitmap);
// CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE FRAME BUFFER
// DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER
ZeroMemory( g_pFramebufferbits, GetFrameBufferWidth()*GetFrameBufferHeight()*sizeof(bgra_t) );
// CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE FRAME BUFFER
NTSC_VideoInit( g_pFramebufferbits );
}

View file

@ -7,13 +7,15 @@
enum VideoType_e
{
VT_MONO_CUSTOM
, VT_COLOR_MONITOR
, VT_MONO_TV
, VT_COLOR_MONITOR_RGB // Color rendering from AppleWin 1.25 (GH#357)
, VT_COLOR_MONITOR_NTSC
, VT_COLOR_TV
, VT_MONO_TV
, VT_MONO_AMBER
, VT_MONO_GREEN
, VT_MONO_WHITE
, NUM_VIDEO_MODES
, VT_DEFAULT = VT_COLOR_TV
};
extern TCHAR g_aVideoChoices[];
@ -24,7 +26,7 @@
VF_80COL = 0x00000001,
VF_DHIRES = 0x00000002,
VF_HIRES = 0x00000004,
VF_80STORE= 0x00000008, // was called VF_MASK2
VF_80STORE= 0x00000008,
VF_MIXED = 0x00000010,
VF_PAGE2 = 0x00000020,
VF_TEXT = 0x00000040
@ -61,6 +63,7 @@
#define PACKED // TODO: FIXME: gcc/clang __attribute__
#endif
// TODO: Replace with WinGDI.h / RGBQUAD
struct bgra_t
{
uint8_t b;
@ -182,7 +185,6 @@ bool VideoGetSWPAGE2(void);
bool VideoGetSWTEXT(void);
bool VideoGetSWAltCharSet(void);
void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode);
void VideoSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void VideoLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);

View file

@ -0,0 +1,651 @@
// Sync'd with 1.25.0.4 source
#include "StdAfx.h"
#include "Frame.h"
#include "Memory.h" // MemGetMainPtr() MemGetAuxPtr()
#include "Video.h"
#include "Video_OriginalColorTVMode.h"
const int SRCOFFS_LORES = 0; // 0
const int SRCOFFS_HIRES = (SRCOFFS_LORES + 16); // 16
const int SRCOFFS_DHIRES = (SRCOFFS_HIRES + 512); // 528
const int SRCOFFS_TOTAL = (SRCOFFS_DHIRES + 2560); // 3088
const int MAX_SOURCE_Y = 512;
static LPBYTE g_aSourceStartofLine[ MAX_SOURCE_Y ];
#define SETSOURCEPIXEL(x,y,c) g_aSourceStartofLine[(y)][(x)] = (c)
// TC: Tried to remove HiresToPalIndex[] translation table, so get purple bars when hires data is: 0x80 0x80...
// . V_CreateLookup_HiResHalfPixel_Authentic() uses both ColorMapping (CM_xxx) indices and Color_Palette_Index_e (HGR_xxx)!
#define DO_OPT_PALETTE 0
enum Color_Palette_Index_e
{
// hires (don't change order) - For tv emulation HGR Video Mode
#if DO_OPT_PALETTE
HGR_VIOLET // HCOLOR=2 VIOLET , 2800: 01 00 55 2A
, HGR_BLUE // HCOLOR=6 BLUE , 3000: 81 00 D5 AA
, HGR_GREEN // HCOLOR=1 GREEN , 2400: 02 00 2A 55
, HGR_ORANGE // HCOLOR=5 ORANGE , 2C00: 82 00 AA D5
, HGR_BLACK
, HGR_WHITE
#else
HGR_BLACK
, HGR_WHITE
, HGR_BLUE // HCOLOR=6 BLUE , 3000: 81 00 D5 AA
, HGR_ORANGE // HCOLOR=5 ORANGE , 2C00: 82 00 AA D5
, HGR_GREEN // HCOLOR=1 GREEN , 2400: 02 00 2A 55
, HGR_VIOLET // HCOLOR=2 VIOLET , 2800: 01 00 55 2A
#endif
// TV emu
, HGR_GREY1
, HGR_GREY2
, HGR_YELLOW
, HGR_AQUA
, HGR_PURPLE
, HGR_PINK
// lores & dhires
, BLACK
, DEEP_RED
, DARK_BLUE
, MAGENTA
, DARK_GREEN
, DARK_GRAY
, BLUE
, LIGHT_BLUE
, BROWN
, ORANGE
, LIGHT_GRAY
, PINK
, GREEN
, YELLOW
, AQUA
, WHITE
};
// __ Map HGR color index to Palette index
enum ColorMapping
{
CM_Violet
, CM_Blue
, CM_Green
, CM_Orange
, CM_Black
, CM_White
, NUM_COLOR_MAPPING
};
const BYTE HiresToPalIndex[ NUM_COLOR_MAPPING ] =
{
HGR_VIOLET
, HGR_BLUE
, HGR_GREEN
, HGR_ORANGE
, HGR_BLACK
, HGR_WHITE
};
const BYTE LoresResColors[16] = {
BLACK, DEEP_RED, DARK_BLUE, MAGENTA,
DARK_GREEN,DARK_GRAY,BLUE, LIGHT_BLUE,
BROWN, ORANGE, LIGHT_GRAY,PINK,
GREEN, YELLOW, AQUA, WHITE
};
const BYTE DoubleHiresPalIndex[16] = {
BLACK, DARK_BLUE, DARK_GREEN,BLUE,
BROWN, LIGHT_GRAY,GREEN, AQUA,
DEEP_RED,MAGENTA, DARK_GRAY, LIGHT_BLUE,
ORANGE, PINK, YELLOW, WHITE
};
#define SETRGBCOLOR(r,g,b) {b,g,r,0}
static RGBQUAD PalIndex2RGB[] =
{
// hires
#if DO_OPT_PALETTE
SETRGBCOLOR(/*MAGENTA, */ 0xC7,0x34,0xFF), // FD Linards Tweaked 0xFF,0x00,0xFF -> 0xC7,0x34,0xFF
SETRGBCOLOR(/*BLUE, */ 0x0D,0xA1,0xFF), // FC Linards Tweaked 0x00,0x00,0xFF -> 0x0D,0xA1,0xFF
SETRGBCOLOR(/*GREEN, */ 0x38,0xCB,0x00), // FA Linards Tweaked 0x00,0xFF,0x00 -> 0x38,0xCB,0x00
SETRGBCOLOR(/*ORANGE, */ 0xF2,0x5E,0x00), // 0xFF,0x80,0x00 -> Linards Tweaked 0xF2,0x5E,0x00
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00), // For TV emulation HGR Video Mode
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
#else
SETRGBCOLOR(/*HGR_BLACK, */ 0x00,0x00,0x00), // For TV emulation HGR Video Mode
SETRGBCOLOR(/*HGR_WHITE, */ 0xFF,0xFF,0xFF),
SETRGBCOLOR(/*BLUE, */ 0x0D,0xA1,0xFF), // FC Linards Tweaked 0x00,0x00,0xFF -> 0x0D,0xA1,0xFF
SETRGBCOLOR(/*ORANGE, */ 0xF2,0x5E,0x00), // 0xFF,0x80,0x00 -> Linards Tweaked 0xF2,0x5E,0x00
SETRGBCOLOR(/*GREEN, */ 0x38,0xCB,0x00), // FA Linards Tweaked 0x00,0xFF,0x00 -> 0x38,0xCB,0x00
SETRGBCOLOR(/*MAGENTA, */ 0xC7,0x34,0xFF), // FD Linards Tweaked 0xFF,0x00,0xFF -> 0xC7,0x34,0xFF
#endif
// TV emu
SETRGBCOLOR(/*HGR_GREY1, */ 0x80,0x80,0x80),
SETRGBCOLOR(/*HGR_GREY2, */ 0x80,0x80,0x80),
SETRGBCOLOR(/*HGR_YELLOW,*/ 0x9E,0x9E,0x00), // 0xD0,0xB0,0x10 -> 0x9E,0x9E,0x00
SETRGBCOLOR(/*HGR_AQUA, */ 0x00,0xCD,0x4A), // 0x20,0xB0,0xB0 -> 0x00,0xCD,0x4A
SETRGBCOLOR(/*HGR_PURPLE,*/ 0x61,0x61,0xFF), // 0x60,0x50,0xE0 -> 0x61,0x61,0xFF
SETRGBCOLOR(/*HGR_PINK, */ 0xFF,0x32,0xB5), // 0xD0,0x40,0xA0 -> 0xFF,0x32,0xB5
// lores & dhires
SETRGBCOLOR(/*BLACK,*/ 0x00,0x00,0x00), // 0
SETRGBCOLOR(/*DEEP_RED,*/ 0x9D,0x09,0x66), // 0xD0,0x00,0x30 -> Linards Tweaked 0x9D,0x09,0x66
SETRGBCOLOR(/*DARK_BLUE,*/ 0x2A,0x2A,0xE5), // 4 // Linards Tweaked 0x00,0x00,0x80 -> 0x2A,0x2A,0xE5
SETRGBCOLOR(/*MAGENTA,*/ 0xC7,0x34,0xFF), // FD Linards Tweaked 0xFF,0x00,0xFF -> 0xC7,0x34,0xFF
SETRGBCOLOR(/*DARK_GREEN,*/ 0x00,0x80,0x00), // 2 // not used
SETRGBCOLOR(/*DARK_GRAY,*/ 0x80,0x80,0x80), // F8
SETRGBCOLOR(/*BLUE,*/ 0x0D,0xA1,0xFF), // FC Linards Tweaked 0x00,0x00,0xFF -> 0x0D,0xA1,0xFF
SETRGBCOLOR(/*LIGHT_BLUE,*/ 0xAA,0xAA,0xFF), // 0x60,0xA0,0xFF -> Linards Tweaked 0xAA,0xAA,0xFF
SETRGBCOLOR(/*BROWN,*/ 0x55,0x55,0x00), // 0x80,0x50,0x00 -> Linards Tweaked 0x55,0x55,0x00
SETRGBCOLOR(/*ORANGE,*/ 0xF2,0x5E,0x00), // 0xFF,0x80,0x00 -> Linards Tweaked 0xF2,0x5E,0x00
SETRGBCOLOR(/*LIGHT_GRAY,*/ 0xC0,0xC0,0xC0), // 7 // GR: COLOR=10
SETRGBCOLOR(/*PINK,*/ 0xFF,0x89,0xE5), // 0xFF,0x90,0x80 -> Linards Tweaked 0xFF,0x89,0xE5
SETRGBCOLOR(/*GREEN,*/ 0x38,0xCB,0x00), // FA Linards Tweaked 0x00,0xFF,0x00 -> 0x38,0xCB,0x00
SETRGBCOLOR(/*YELLOW,*/ 0xD5,0xD5,0x1A), // FB Linards Tweaked 0xFF,0xFF,0x00 -> 0xD5,0xD5,0x1A
SETRGBCOLOR(/*AQUA,*/ 0x62,0xF6,0x99), // 0x40,0xFF,0x90 -> Linards Tweaked 0x62,0xF6,0x99
SETRGBCOLOR(/*WHITE,*/ 0xFF,0xFF,0xFF),
};
//===========================================================================
static void V_CreateLookup_DoubleHires ()
{
#define OFFSET 3
#define SIZE 10
for (int column = 0; column < 256; column++) {
int coloffs = SIZE * column;
for (unsigned byteval = 0; byteval < 256; byteval++) {
int color[SIZE];
ZeroMemory(color,sizeof(color));
unsigned pattern = MAKEWORD(byteval,column);
int pixel;
for (pixel = 1; pixel < 15; pixel++) {
if (pattern & (1 << pixel)) {
int pixelcolor = 1 << ((pixel-OFFSET) & 3);
if ((pixel >= OFFSET+2) && (pixel < SIZE+OFFSET+2) && (pattern & (0x7 << (pixel-4))))
color[pixel-(OFFSET+2)] |= pixelcolor;
if ((pixel >= OFFSET+1) && (pixel < SIZE+OFFSET+1) && (pattern & (0xF << (pixel-4))))
color[pixel-(OFFSET+1)] |= pixelcolor;
if ((pixel >= OFFSET+0) && (pixel < SIZE+OFFSET+0))
color[pixel-(OFFSET+0)] |= pixelcolor;
if ((pixel >= OFFSET-1) && (pixel < SIZE+OFFSET-1) && (pattern & (0xF << (pixel+1))))
color[pixel-(OFFSET-1)] |= pixelcolor;
if ((pixel >= OFFSET-2) && (pixel < SIZE+OFFSET-2) && (pattern & (0x7 << (pixel+2))))
color[pixel-(OFFSET-2)] |= pixelcolor;
}
}
#if 0
if (g_eVideoType == VT_COLOR_TEXT_OPTIMIZED)
{
// Activate for fringe reduction on white HGR text - drawback: loss of color mix patterns in HGR Video Mode.
for (pixel = 0; pixel < 13; pixel++)
{
if ((pattern & (0xF << pixel)) == (unsigned)(0xF << pixel))
for (int pos = pixel; pos < pixel + 4; pos++)
if (pos >= OFFSET && pos < SIZE+OFFSET)
color[pos-OFFSET] = 15;
}
}
#endif
int y = byteval << 1;
for (int x = 0; x < SIZE; x++) {
SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y ,DoubleHiresPalIndex[ color[x] ]);
SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y+1,DoubleHiresPalIndex[ color[x] ]);
}
}
}
#undef SIZE
#undef OFFSET
}
//===========================================================================
#if 0
static void V_CreateLookup_Hires()
{
// int iMonochrome = GetMonochromeIndex();
// BYTE colorval[6] = {MAGENTA,BLUE,GREEN,ORANGE,BLACK,WHITE};
// BYTE colorval[6] = {HGR_MAGENTA,HGR_BLUE,HGR_GREEN,HGR_RED,HGR_BLACK,HGR_WHITE};
for (int iColumn = 0; iColumn < 16; iColumn++)
{
int coloffs = iColumn << 5;
for (unsigned iByte = 0; iByte < 256; iByte++)
{
int aPixels[11];
aPixels[ 0] = iColumn & 4;
aPixels[ 1] = iColumn & 8;
aPixels[ 9] = iColumn & 1;
aPixels[10] = iColumn & 2;
int nBitMask = 1;
int iPixel;
for (iPixel = 2; iPixel < 9; iPixel++) {
aPixels[iPixel] = ((iByte & nBitMask) != 0);
nBitMask <<= 1;
}
int hibit = ((iByte & 0x80) != 0);
int x = 0;
int y = iByte << 1;
while (x < 28)
{
int adj = (x >= 14) << 1;
int odd = (x >= 14);
for (iPixel = 2; iPixel < 9; iPixel++)
{
int color = CM_Black;
if (aPixels[iPixel])
{
if (aPixels[iPixel-1] || aPixels[iPixel+1])
color = CM_White;
else
color = ((odd ^ (iPixel&1)) << 1) | hibit;
}
else if (aPixels[iPixel-1] && aPixels[iPixel+1])
{
// Activate fringe reduction on white HGR text - drawback: loss of color mix patterns in HGR video mode.
// VT_COLOR_MONITOR_RGB = Fill in colors in between white pixels
// VT_COLOR_TVEMU = Fill in colors in between white pixels (Post Processing will mix/merge colors)
// VT_COLOR_TEXT_OPTIMIZED --> !(aPixels[iPixel-2] && aPixels[iPixel+2]) = Don't fill in colors in between white
if ((g_eVideoType == VT_COLOR_TVEMU) || !(aPixels[iPixel-2] && aPixels[iPixel+2]) )
color = ((odd ^ !(iPixel&1)) << 1) | hibit; // No white HGR text optimization
}
//if (g_eVideoType == VT_MONO_AUTHENTIC) {
// int nMonoColor = (color != CM_Black) ? iMonochrome : BLACK;
// SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , nMonoColor); // buggy
// SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , nMonoColor); // buggy
// SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1,BLACK); // BL
// SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1,BLACK); // BR
//} else
{
// Colors - Top/Bottom Left/Right
// cTL cTR
// cBL cBR
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y ,HiresToPalIndex[color]); // cTL
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y ,HiresToPalIndex[color]); // cTR
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1,HiresToPalIndex[color]); // cBL
SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1,HiresToPalIndex[color]); // cBR
}
x += 2;
}
}
}
}
}
#endif
//===========================================================================
void V_CreateLookup_Lores()
{
for (int color = 0; color < 16; color++)
for (int x = 0; x < 16; x++)
for (int y = 0; y < 16; y++)
SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,LoresResColors[color]);
}
//===========================================================================
#define HALF_PIXEL_SOLID 1
#define HALF_PIXEL_BLEED 0
void V_CreateLookup_HiResHalfPixel_Authentic(VideoType_e videoType) // Colors are solid (100% coverage)
{
// 2-bits from previous byte, 2-bits from next byte = 2^4 = 16 total permutations
for (int iColumn = 0; iColumn < 16; iColumn++)
{
int offsetx = iColumn << 5; // every column is 32 bytes wide -- 7 apple pixels = 14 pixels + 2 pad + 14 pixels + 2 pad
for (unsigned iByte = 0; iByte < 256; iByte++)
{
int aPixels[11]; // c2 c1 b7 b6 b5 b4 b3 b2 b1 b0 c8 c4
/*
aPixel[i]
A 9|8 7 6 5 4 3 2|1 0
Z W|b b b b b b b|X Y
----+-------------+----
prev| existing |next
bits| hi-res byte |bits
Legend:
XYZW = iColumn in binary
b = Bytes in binary
*/
// aPixel[] = 48bbbbbbbb12, where b = iByte in binary, # is bit-n of column
aPixels[ 0] = iColumn & 4; // previous byte, 2nd last pixel
aPixels[ 1] = iColumn & 8; // previous byte, last pixel
aPixels[ 9] = iColumn & 1; // next byte, first pixel
aPixels[10] = iColumn & 2; // next byte, second pixel
// Convert raw pixel Byte value to binary and stuff into bit array of pixels on off
int nBitMask = 1;
int iPixel;
for (iPixel = 2; iPixel < 9; iPixel++)
{
aPixels[iPixel] = ((iByte & nBitMask) != 0);
nBitMask <<= 1;
}
int hibit = (iByte >> 7) & 1; // ((iByte & 0x80) != 0);
int x = 0;
int y = iByte << 1;
/* Test cases
81 blue
2000:D5 AA D5 AA
82 orange
2800:AA D5 AA D5
FF white bleed "thru"
3000:7F 80 7F 80
3800:FF 80 FF 80
2028:80 7F 80 7F
2828:80 FF 80 FF
Edge Case for Half Luminance !
2000:C4 00 // Green HalfLumBlue
2400:C4 80 // Green Green
Edge Case for Color Bleed !
2000:40 00
2400:40 80
*/
// Fixup missing pixels that normally have been scan-line shifted -- Apple "half-pixel" -- but cross 14-pixel boundaries.
if( hibit )
{
if ( aPixels[1] ) // preceeding pixel on?
#if 0 // Optimization: Doesn't seem to matter if we ignore the 2 pixels of the next byte
for (iPixel = 0; iPixel < 9; iPixel++) // NOTE: You MUST start with the preceding 2 pixels !!!
if (aPixels[iPixel]) // pixel on
#endif
{
if (aPixels[2] || aPixels[0]) // White if pixel from previous byte and first pixel of this byte is on
{
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_WHITE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_WHITE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_WHITE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_WHITE );
} else { // Optimization: odd = (iPixel & 1); if (!odd) case is same as if(odd) !!! // Reference: Gumball - Gumball Machine
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_ORANGE ); // left half of orange pixels
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_ORANGE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_BLUE ); // right half of blue pixels 4, 11, 18, ...
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_BLUE );
}
}
#if HALF_PIXEL_SOLID
// Test Patterns
// 81 blue
// 2000:D5 AA D5 AA -> 2001:AA D5 should not have black gap, should be blue
// 82 orange
// 2800:AA D5 AA D5
// Game: Elite -- Loading Logo
// 2444:BB F7 -> 2000:BB F7 // Should not have orange in-between gap -- Elite "Firebird" Logo
// -> 2400:00 BB F7 // Should not have blue in-between gap )
// 21D0:C0 00 -> HalfLumBlue
// 25D0:C0 D0 88 -> Blue black orange black orange
// 29D0:C0 90 88 -> Blue black orange
// Game: Ultima 4 -- Ultima 4 Logo - bottom half of screen has a "mini-game" / demo -- far right has tree and blue border
// 2176:2A AB green black_gap white blue_border // Should have black gap between green and white
else if ( aPixels[0] ) // prev prev pixel on
{
// Game: Gumball
// 218E:AA 97 => 2000: A9 87 orange_white // Should have no gap between orange and white
// 229A:AB A9 87 -> 2000: 00 A9 87 white orange black blue_white // Should have no gap between blue and white
// 2001:BB F7 white blue white (Gumball Intermission)
// Torture Half-Pixel HGR Tests: This is a real bitch to solve -- we really need to check:
// if (hibit_prev_byte && !aPixels[iPixel-3] && aPixels[iPixel-2] && !aPixels[iPixel] && hibit_this_byte) then set first half-pixel of this byte to either blue or orange
// 2000:A9 87 halfblack blue black black orange black orange black
// 2400:BB F7 halfblack white white black white white white halfblack
// or
// 2000:A0 83 orange should "bleed" thru
// 2400:B0 83 should have black gap
if ( aPixels[2] )
#if HALF_PIXEL_BLEED // No Half-Pixel Bleed
if ( aPixels[3] ) {
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , DARK_BLUE ); // Gumball: 229A: AB A9 87
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, DARK_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , BROWN ); // half luminance red Elite: 2444: BB F7
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, BROWN ); // half luminance red Gumball: 218E: AA 97
} else {
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_ORANGE );
}
#else
if ((videoType == VT_COLOR_MONITOR_RGB) || ( !aPixels[3] ))
{ // "Text optimized" IF this pixel on, and adjacent right pixel off, then colorize first half-pixel of this byte
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y , HGR_BLUE ); // 2000:D5 AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+0 ,y+1, HGR_BLUE );
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y , HGR_ORANGE ); // 2000: AA D5
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+16,y+1, HGR_ORANGE );
}
#endif // HALF_PIXEL_BLEED
}
#endif // HALF_PIXEL_SOLID
}
x += hibit;
while (x < 28)
{
int adj = (x >= 14) << 1; // Adjust start of 7 last pixels to be 16-byte aligned!
int odd = (x >= 14);
for (iPixel = 2; iPixel < 9; iPixel++)
{
int color = CM_Black;
if (aPixels[iPixel]) // pixel on
{
color = CM_White;
if (aPixels[iPixel-1] || aPixels[iPixel+1]) // adjacent pixels are always white
color = CM_White;
else
color = ((odd ^ (iPixel&1)) << 1) | hibit; // map raw color to our hi-res colors
}
#if HALF_PIXEL_SOLID
else if (aPixels[iPixel-1] && aPixels[iPixel+1]) // IF prev_pixel && next_pixel THEN
{
// Activate fringe reduction on white HGR text - drawback: loss of color mix patterns in HGR video mode.
if (
(videoType == VT_COLOR_MONITOR_RGB) // Fill in colors in between white pixels
// || (videoType == VT_COLOR_TVEMU) // Fill in colors in between white pixels (Post Processing will mix/merge colors)
|| !(aPixels[iPixel-2] && aPixels[iPixel+2]) ) // VT_COLOR_TEXT_OPTIMIZED -> Don't fill in colors in between white
{
// Test Pattern: Ultima 4 Logo - Castle
// 3AC8: 36 5B 6D 36
color = ((odd ^ !(iPixel&1)) << 1) | hibit; // No white HGR text optimization
}
}
#endif
// Colors - Top/Bottom Left/Right
// cTL cTR
// cBL cBR
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj ,y ,HiresToPalIndex[color]); // cTL
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj+1,y ,HiresToPalIndex[color]); // cTR
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj ,y+1,HiresToPalIndex[color]); // cBL
SETSOURCEPIXEL(SRCOFFS_HIRES+offsetx+x+adj+1,y+1,HiresToPalIndex[color]); // cBR
x += 2;
}
}
}
}
}
//===========================================================================
static void CopySource(int w, int h, int sx, int sy, bgra_t *pVideoAddress)
{
UINT32* pDst = (UINT32*) pVideoAddress;
LPBYTE pSrc = g_aSourceStartofLine[ sy ] + sx;
int nBytes;
while (h--)
{
nBytes = w;
while (nBytes)
{
--nBytes;
if (g_uHalfScanLines && !(h & 1))
{
// 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows)
*(pDst+nBytes) = 0;
}
else
{
_ASSERT( *(pSrc+nBytes) < (sizeof(PalIndex2RGB)/sizeof(PalIndex2RGB[0])) );
const RGBQUAD& rRGB = PalIndex2RGB[ *(pSrc+nBytes) ];
const UINT32 rgb = (((UINT32)rRGB.rgbRed)<<16) | (((UINT32)rRGB.rgbGreen)<<8) | ((UINT32)rRGB.rgbBlue);
*(pDst+nBytes) = rgb;
}
}
pDst -= GetFrameBufferWidth();
pSrc -= SRCOFFS_TOTAL;
}
}
//===========================================================================
void UpdateHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
{
uint8_t *pMain = MemGetMainPtr(addr);
BYTE byteval1 = (x > 0) ? *(pMain-1) : 0;
BYTE byteval2 = *(pMain);
BYTE byteval3 = (x < 39) ? *(pMain+1) : 0;
#define COLOFFS (((byteval1 & 0x60) << 2) | ((byteval3 & 0x03) << 5))
#if 0
if (g_eVideoType == VT_COLOR_TVEMU)
{
CopyMixedSource(
xpixel >> 1, (ypixel+(yoffset >> 9)) >> 1,
SRCOFFS_HIRES+COLOFFS+((x & 1) << 4), (((int)byteval2) << 1)
);
}
else
#endif
{
CopySource(14,2, SRCOFFS_HIRES+COLOFFS+((x & 1) << 4), (((int)byteval2) << 1), pVideoAddress);
}
#undef COLOFFS
}
//===========================================================================
void UpdateDHiResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
{
const int xpixel = x*14;
uint8_t *pAux = MemGetAuxPtr(addr);
uint8_t *pMain = MemGetMainPtr(addr);
BYTE byteval1 = (x > 0) ? *(pMain-1) : 0;
BYTE byteval2 = *pAux;
BYTE byteval3 = *pMain;
BYTE byteval4 = (x < 39) ? *(pAux+1) : 0;
DWORD dwordval = (byteval1 & 0x70) | ((byteval2 & 0x7F) << 7) |
((byteval3 & 0x7F) << 14) | ((byteval4 & 0x07) << 21);
#define PIXEL 0
#define COLOR ((xpixel + PIXEL) & 3)
#define VALUE (dwordval >> (4 + PIXEL - COLOR))
CopySource(7,2, SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR, LOBYTE(VALUE)<<1, pVideoAddress);
#undef PIXEL
#define PIXEL 7
CopySource(7,2, SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR, LOBYTE(VALUE)<<1, pVideoAddress+7);
#undef PIXEL
#undef COLOR
#undef VALUE
}
//===========================================================================
// Tested with Deater's Cycle-Counting Megademo
void UpdateLoResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
{
const BYTE val = *MemGetMainPtr(addr);
if ((y & 4) == 0)
{
CopySource(14,2, SRCOFFS_LORES+((x & 1) << 1), ((val & 0xF) << 4), pVideoAddress);
}
else
{
CopySource(14,2, SRCOFFS_LORES+((x & 1) << 1), (val & 0xF0), pVideoAddress);
}
}
//===========================================================================
#define ROL_NIB(x) ( (((x)<<1)&0xF) | (((x)>>3)&1) )
// Tested with FT's Ansi Story
void UpdateDLoResCell (int x, int y, uint16_t addr, bgra_t *pVideoAddress)
{
BYTE auxval = *MemGetAuxPtr(addr);
const BYTE mainval = *MemGetMainPtr(addr);
const BYTE auxval_h = auxval >> 4;
const BYTE auxval_l = auxval & 0xF;
auxval = (ROL_NIB(auxval_h)<<4) | ROL_NIB(auxval_l);
if ((y & 4) == 0)
{
CopySource(7,2, SRCOFFS_LORES+((x & 1) << 1), ((auxval & 0xF) << 4), pVideoAddress);
CopySource(7,2, SRCOFFS_LORES+((x & 1) << 1), ((mainval & 0xF) << 4), pVideoAddress+7);
}
else
{
CopySource(7,2, SRCOFFS_LORES+((x & 1) << 1), (auxval & 0xF0), pVideoAddress);
CopySource(7,2, SRCOFFS_LORES+((x & 1) << 1), (mainval & 0xF0), pVideoAddress+7);
}
}
//===========================================================================
static LPBYTE g_pSourcePixels = NULL;
static void V_CreateDIBSections(void)
{
g_pSourcePixels = new BYTE[SRCOFFS_TOTAL * MAX_SOURCE_Y];
// CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE SOURCE IMAGE
for (int y = 0; y < MAX_SOURCE_Y; y++)
g_aSourceStartofLine[ y ] = g_pSourcePixels + SRCOFFS_TOTAL*((MAX_SOURCE_Y-1) - y);
// DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER
ZeroMemory(g_pSourcePixels, SRCOFFS_TOTAL*MAX_SOURCE_Y); // 32 bytes/pixel * 16 colors = 512 bytes/row
V_CreateLookup_Lores();
// if ( g_eVideoType == VT_COLOR_TVEMU )
// V_CreateLookup_Hires();
// else
V_CreateLookup_HiResHalfPixel_Authentic(VT_COLOR_MONITOR_RGB);
V_CreateLookup_DoubleHires();
}
void VideoInitializeOriginal(baseColors_t pBaseNtscColors)
{
// CREATE THE SOURCE IMAGE AND DRAW INTO THE SOURCE BIT BUFFER
V_CreateDIBSections();
#if 1
memcpy(&PalIndex2RGB[BLACK], *pBaseNtscColors, sizeof(RGBQUAD)*kNumBaseColors);
PalIndex2RGB[HGR_BLUE] = PalIndex2RGB[BLUE];
PalIndex2RGB[HGR_ORANGE] = PalIndex2RGB[ORANGE];
PalIndex2RGB[HGR_GREEN] = PalIndex2RGB[GREEN];
PalIndex2RGB[HGR_VIOLET] = PalIndex2RGB[MAGENTA];
#endif
}

View file

@ -0,0 +1,8 @@
void UpdateHiResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateDHiResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateLoResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
void UpdateDLoResCell(int x, int y, uint16_t addr, bgra_t *pVideoAddress);
const UINT kNumBaseColors = 16;
typedef bgra_t (*baseColors_t)[kNumBaseColors];
void VideoInitializeOriginal(baseColors_t pBaseNtscColors);