diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj
index 54bad663..ef882893 100644
--- a/AppleWinExpress2013.vcxproj
+++ b/AppleWinExpress2013.vcxproj
@@ -74,6 +74,8 @@
+
+
@@ -154,6 +156,8 @@
+
+
diff --git a/AppleWinExpress2013.vcxproj.filters b/AppleWinExpress2013.vcxproj.filters
index 1655702c..2d24a23e 100644
--- a/AppleWinExpress2013.vcxproj.filters
+++ b/AppleWinExpress2013.vcxproj.filters
@@ -169,6 +169,12 @@
Source Files\Debugger
+
+ Source Files\Video
+
+
+ Source Files\Video
+
Source Files\Model
@@ -423,6 +429,12 @@
Source Files\Disk
+<<<<<<< HEAD
+=======
+
+ Source Files\Video
+
+>>>>>>> NTSC_PreMerge
Source Files\Model
@@ -438,6 +450,12 @@
Source Files\_Headers
+<<<<<<< HEAD
+=======
+
+ Source Files\Video
+
+>>>>>>> NTSC_PreMerge
diff --git a/AppleWinExpress2015.vcxproj b/AppleWinExpress2015.vcxproj
index bcc5e9f7..8b40ce47 100644
--- a/AppleWinExpress2015.vcxproj
+++ b/AppleWinExpress2015.vcxproj
@@ -74,6 +74,8 @@
+
+
@@ -154,6 +156,8 @@
+
+
diff --git a/AppleWinExpress2015.vcxproj.filters b/AppleWinExpress2015.vcxproj.filters
index 1655702c..2d24a23e 100644
--- a/AppleWinExpress2015.vcxproj.filters
+++ b/AppleWinExpress2015.vcxproj.filters
@@ -169,6 +169,12 @@
Source Files\Debugger
+
+ Source Files\Video
+
+
+ Source Files\Video
+
Source Files\Model
@@ -423,6 +429,12 @@
Source Files\Disk
+<<<<<<< HEAD
+=======
+
+ Source Files\Video
+
+>>>>>>> NTSC_PreMerge
Source Files\Model
@@ -438,6 +450,12 @@
Source Files\_Headers
+<<<<<<< HEAD
+=======
+
+ Source Files\Video
+
+>>>>>>> NTSC_PreMerge
diff --git a/ApplewinExpress10.00.vcxproj b/ApplewinExpress10.00.vcxproj
index 93aaeee5..e0346e69 100644
--- a/ApplewinExpress10.00.vcxproj
+++ b/ApplewinExpress10.00.vcxproj
@@ -265,6 +265,7 @@
+
Create
Create
@@ -395,6 +396,7 @@
+
@@ -465,6 +467,14 @@
+
+
+
+
+
+
+
+
diff --git a/ApplewinExpress10.00.vcxproj.filters b/ApplewinExpress10.00.vcxproj.filters
index 29487593..023cd320 100644
--- a/ApplewinExpress10.00.vcxproj.filters
+++ b/ApplewinExpress10.00.vcxproj.filters
@@ -212,6 +212,9 @@
Source
+
+ Source\Video
+
@@ -451,6 +454,9 @@
Source
+
+ Source\Video
+
@@ -606,6 +612,16 @@
Resources
+
+ Resources
+
+
+
+
+
+
+
+
diff --git a/ApplewinExpress9.00.vcproj b/ApplewinExpress9.00.vcproj
index 0e4d70b8..aa4af152 100644
--- a/ApplewinExpress9.00.vcproj
+++ b/ApplewinExpress9.00.vcproj
@@ -870,6 +870,22 @@
RelativePath=".\source\Frame.h"
>
+
+
+
+
+
+
+
+
@@ -1066,6 +1082,10 @@
/>
+
+
@@ -1094,6 +1114,10 @@
RelativePath=".\resource\CHARSET8C.bmp"
>
+
+
diff --git a/assets/ApplewinLogo.xcf b/assets/ApplewinLogo.xcf
new file mode 100644
index 00000000..91c1d427
Binary files /dev/null and b/assets/ApplewinLogo.xcf differ
diff --git a/docs/Debugger_Changelog.txt b/docs/Debugger_Changelog.txt
index 8b8442c9..a9cf55ae 100644
--- a/docs/Debugger_Changelog.txt
+++ b/docs/Debugger_Changelog.txt
@@ -1,4 +1,10 @@
/*
+.1 Fixed: Implemented missing debugger "CD" command
+2.9.0.0 Added: ntsc save [filename], ntsc load [filename], to save/load the NTSC palette.
+ Default filename is "AppleWinNTSC4096x4@32.data"
+ To load this file in GIMP: Open, Select File Type: "Raw image data", Raw image data (*.data), RGB Alpha, Width: 4096, Height: 4
+ to save this file in GIMP: Open, Export To, Select File Type (By Extension) Raw image data, RGB Type: Standard (R,G,B)
+
.12 Fixed: [PVS-Studio] Fixed false positive of buffer overflow with MIP_RANDOM
.11 Fixed: [PVS-Studio] Fixed missing call to sprintf() in ConfigSave_PrepareHeader()
.10 Fixed: [PVS-Studio] Fixed no-op in _6502_GetStackReturnAddress()
@@ -337,7 +343,6 @@
2.6.0.8 Released with AppleWin 1.16.1
->>>>>>> .r619
2.6.0.6 Released with AppleWin 1.15
.6 Added new command '@' to display the search results
.5 Fixed display results of Searching to be colorized
diff --git a/resource/Applewin.rc b/resource/Applewin.rc
index 1bffdb2b..d975644f 100644
--- a/resource/Applewin.rc
+++ b/resource/Applewin.rc
@@ -69,11 +69,11 @@ LED_CAPSON_P8_BITMAP BITMAP "LED_CAPS_ON_P8.BMP"
LED_LATOFF_BITMAP BITMAP "LED_CAPS_OFF_LAT.BMP"
LED_LATON_BITMAP BITMAP "LED_CAPS_ON_LAT.BMP"
CHARSET82 BITMAP "CHARSET82.BMP"
-CHARSET8M BITMAP "CHARSET8C.BMP"
+CHARSET8M BITMAP "CHARSET8M.BMP"
CHARSET8C BITMAP "CHARSET8C.BMP"
HELP_BUTTON BITMAP "HELP.BMP"
DRIVESWAP_BUTTON BITMAP "DRIVESWAP.BMP"
-IDB_APPLEWIN BITMAP "Applewin.bmp"
+IDB_APPLEWIN BITMAP "ApplewinLogo.bmp"
IDB_DEBUG_FONT_7X8 BITMAP "Debug_Font.bmp"
/////////////////////////////////////////////////////////////////////////////
@@ -250,8 +250,8 @@ DISK_ICON ICON "DISK.ICO"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,25,0,4
- PRODUCTVERSION 1,25,0,4
+ FILEVERSION 1,26,0,1
+ PRODUCTVERSION 1,26,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -269,12 +269,12 @@ BEGIN
VALUE "Comments", "https://github.com/AppleWin"
VALUE "CompanyName", "AppleWin"
VALUE "FileDescription", "Apple //e Emulator for Windows"
- VALUE "FileVersion", "1, 25, 0, 4"
+ VALUE "FileVersion", "1, 26, 0, 1"
VALUE "InternalName", "APPLEWIN"
VALUE "LegalCopyright", " 1994-2015 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis"
VALUE "OriginalFilename", "APPLEWIN.EXE"
VALUE "ProductName", "Apple //e Emulator"
- VALUE "ProductVersion", "1, 25, 0, 4"
+ VALUE "ProductVersion", "1, 26, 0, 1"
END
END
BLOCK "VarFileInfo"
diff --git a/resource/ApplewinLogo.bmp b/resource/ApplewinLogo.bmp
new file mode 100644
index 00000000..e81f68a2
Binary files /dev/null and b/resource/ApplewinLogo.bmp differ
diff --git a/resource/CHARSET82.bmp b/resource/CHARSET82.bmp
index 0396611b..808fc2e1 100644
Binary files a/resource/CHARSET82.bmp and b/resource/CHARSET82.bmp differ
diff --git a/resource/CHARSET8C.bmp b/resource/CHARSET8C.bmp
index 1dd12c12..a10c83bf 100644
Binary files a/resource/CHARSET8C.bmp and b/resource/CHARSET8C.bmp differ
diff --git a/resource/CHARSET8M.bmp b/resource/CHARSET8M.bmp
index 53efbb33..91dc9dec 100644
Binary files a/resource/CHARSET8M.bmp and b/resource/CHARSET8M.bmp differ
diff --git a/source/Applewin.cpp b/source/Applewin.cpp
index f93069ea..c95bb52f 100644
--- a/source/Applewin.cpp
+++ b/source/Applewin.cpp
@@ -51,6 +51,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Speech.h"
#endif
#include "Video.h"
+#include "NTSC.h"
#include "Configuration\About.h"
#include "Configuration\PropertySheet.h"
@@ -78,6 +79,7 @@ TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used
TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used
TCHAR g_sCurrentDir[MAX_PATH] = TEXT(""); // Also Starting Dir. Debugger uses this when load/save
BOOL restart = 0;
+bool g_bRestartFullScreen = false;
DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar
double g_fCurrentCLK6502 = CLK_6502; // Affected by Config dialog's speed slider bar
@@ -191,6 +193,7 @@ void ContinueExecution(void)
? g_bScrollLock_FullSpeed
: (GetKeyState(VK_SCROLL) < 0);
+ const bool bWasFullSpeed = g_bFullSpeed;
g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) ||
bScrollLock_FullSpeed ||
(DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) );
@@ -212,6 +215,12 @@ void ContinueExecution(void)
}
else
{
+ if (bWasFullSpeed)
+ {
+ VideoRedrawScreenDuringFullSpeed(0, true); // Invalidate the copies of video memory
+ VideoRedrawScreenAfterFullSpeed(g_dwCyclesThisFrame);
+ }
+
// Don't call Spkr_Demute()
MB_Demute();
SysClk_StartTimerUsec(nExecutionPeriodUsec);
@@ -241,7 +250,13 @@ void ContinueExecution(void)
if (g_dwCyclesThisFrame >= dwClksPerFrame)
{
g_dwCyclesThisFrame -= dwClksPerFrame;
- VideoEndOfVideoFrame();
+
+ if (g_bFullSpeed)
+ {
+ VideoRedrawScreenDuringFullSpeed(g_dwCyclesThisFrame);
+ }
+
+ VideoRefreshScreen(0); // Just copy the output of our Apple framebuffer to the system Back Buffer
MB_EndOfVideoFrame();
}
@@ -389,13 +404,13 @@ void SetCharsetType(void)
{
switch ( GetApple2Type() )
{
- case A2TYPE_APPLE2: g_nCharsetType = 0; break;
- case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break;
- case A2TYPE_APPLE2E: g_nCharsetType = 0; break;
- case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break;
- case A2TYPE_PRAVETS82: g_nCharsetType = 1; break;
- case A2TYPE_PRAVETS8A: g_nCharsetType = 2; break;
- case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems.
+ case A2TYPE_APPLE2: g_nCharsetType = 0; break;
+ case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break;
+ case A2TYPE_APPLE2E: g_nCharsetType = 0; break;
+ case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break;
+ case A2TYPE_PRAVETS82: g_nCharsetType = 1; break;
+ case A2TYPE_PRAVETS8M: g_nCharsetType = 2; break; //This charset has a very small difference with the PRAVETS82 one, and probably has some misplaced characters.
+ case A2TYPE_PRAVETS8A: g_nCharsetType = 3; break;
default:
_ASSERT(0);
g_nCharsetType = 0;
@@ -413,6 +428,10 @@ void LoadConfiguration(void)
if ((dwComputerType >= A2TYPE_MAX) || (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE))
dwComputerType = A2TYPE_APPLE2EENHANCED;
+ // Remap the bad Pravets models (before AppleWin v1.26)
+ if (dwComputerType == A2TYPE_BAD_PRAVETS82) dwComputerType = A2TYPE_PRAVETS82;
+ if (dwComputerType == A2TYPE_BAD_PRAVETS8M) dwComputerType = A2TYPE_PRAVETS8M;
+
apple2Type = (eApple2Type) dwComputerType;
}
else // Support older AppleWin registry entries
@@ -588,7 +607,7 @@ void LoadConfiguration(void)
//===========================================================================
-void SetCurrentImageDir(const char* pszImageDir)
+bool SetCurrentImageDir(const char* pszImageDir)
{
strcpy(g_sCurrentDir, pszImageDir);
@@ -599,7 +618,10 @@ void SetCurrentImageDir(const char* pszImageDir)
g_sCurrentDir[ nLen + 1 ] = 0;
}
- SetCurrentDirectory(g_sCurrentDir);
+ if( SetCurrentDirectory(g_sCurrentDir) )
+ return true;
+
+ return false;
}
//===========================================================================
@@ -1003,9 +1025,6 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
DiskInitialize();
LogFileOutput("Init: DiskInitialize()\n");
- CreateColorMixMap(); // For tv emulation mode
- LogFileOutput("Init: CreateColorMixMap()\n");
-
int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error
if (szImageName_drive1)
{
@@ -1136,6 +1155,12 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
EnterMessageLoop();
LogFileOutput("Main: LeaveMessageLoop()\n");
+ if (restart)
+ {
+ bSetFullScreen = g_bRestartFullScreen;
+ g_bRestartFullScreen = false;
+ }
+
MB_Reset();
LogFileOutput("Main: MB_Reset()\n");
diff --git a/source/Applewin.h b/source/Applewin.h
index cb15246e..43baf895 100644
--- a/source/Applewin.h
+++ b/source/Applewin.h
@@ -4,7 +4,7 @@
#include "Common.h"
void SetCurrentCLK6502();
-void SetCurrentImageDir(const char* pszImageDir);
+bool SetCurrentImageDir(const char* pszImageDir);
void SetCharsetType(void);
extern const UINT16* GetAppleWinVersion(void);
@@ -31,6 +31,7 @@ extern TCHAR g_sProgramDir[MAX_PATH];
extern TCHAR g_sCurrentDir[MAX_PATH];
extern BOOL restart;
+extern bool g_bRestartFullScreen;
extern DWORD g_dwSpeed;
extern double g_fCurrentCLK6502;
diff --git a/source/CPU.cpp b/source/CPU.cpp
index 3c998c14..daacf9fc 100644
--- a/source/CPU.cpp
+++ b/source/CPU.cpp
@@ -96,6 +96,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Speech.h"
#endif
#include "Video.h"
+#include "NTSC.h"
#include "z80emu.h"
#include "Z80VICE\z80.h"
@@ -104,25 +105,27 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Debugger\Debug.h"
#include "YamlHelper.h"
-
-#define AF_SIGN 0x80
-#define AF_OVERFLOW 0x40
-#define AF_RESERVED 0x20
-#define AF_BREAK 0x10
-#define AF_DECIMAL 0x08
-#define AF_INTERRUPT 0x04
-#define AF_ZERO 0x02
-#define AF_CARRY 0x01
+// 6502 Accumulator Bit Flags
+ #define AF_SIGN 0x80
+ #define AF_OVERFLOW 0x40
+ #define AF_RESERVED 0x20
+ #define AF_BREAK 0x10
+ #define AF_DECIMAL 0x08
+ #define AF_INTERRUPT 0x04
+ #define AF_ZERO 0x02
+ #define AF_CARRY 0x01
#define SHORTOPCODES 22
#define BENCHOPCODES 33
-// What is this 6502 code?
-static BYTE benchopcode[BENCHOPCODES] = {0x06,0x16,0x24,0x45,0x48,0x65,0x68,0x76,
- 0x84,0x85,0x86,0x91,0x94,0xA4,0xA5,0xA6,
- 0xB1,0xB4,0xC0,0xC4,0xC5,0xE6,
- 0x19,0x6D,0x8D,0x99,0x9D,0xAD,0xB9,0xBD,
- 0xDD,0xED,0xEE};
+// What is this 6502 code? Compressed 6502 code -- see: CpuSetupBenchmark()
+static BYTE benchopcode[BENCHOPCODES] = {
+ 0x06,0x16,0x24,0x45,0x48,0x65,0x68,0x76,
+ 0x84,0x85,0x86,0x91,0x94,0xA4,0xA5,0xA6,
+ 0xB1,0xB4,0xC0,0xC4,0xC5,0xE6,
+ 0x19,0x6D,0x8D,0x99,0x9D,0xAD,0xB9,0xBD,
+ 0xDD,0xED,0xEE
+};
regsrec regs;
unsigned __int64 g_nCumulativeCycles = 0;
diff --git a/source/CPU/cpu6502.h b/source/CPU/cpu6502.h
index 3b58dd91..14fe7a24 100644
--- a/source/CPU/cpu6502.h
+++ b/source/CPU/cpu6502.h
@@ -43,6 +43,10 @@ static DWORD Cpu6502 (DWORD uTotalCycles)
UINT uExtraCycles = 0;
BYTE iOpcode;
+// NTSC_BEGIN
+ ULONG uPreviousCycles = uExecutedCycles;
+// NTSC_END
+
if (GetActiveCpu() == CPU_Z80)
{
const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles)
@@ -315,6 +319,14 @@ static DWORD Cpu6502 (DWORD uTotalCycles)
#undef $
}
+// NTSC_BEGIN
+ if (!g_bFullSpeed)
+ {
+ ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles;
+ NTSC_VideoUpdateCycles( uElapsedCycles );
+ }
+// NTSC_END
+
CheckInterruptSources(uExecutedCycles);
NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
diff --git a/source/CPU/cpu65C02.h b/source/CPU/cpu65C02.h
index 5d649b05..0a1cec26 100644
--- a/source/CPU/cpu65C02.h
+++ b/source/CPU/cpu65C02.h
@@ -46,6 +46,10 @@ static DWORD Cpu65C02 (DWORD uTotalCycles)
UINT uExtraCycles = 0;
BYTE iOpcode;
+// NTSC_BEGIN
+ ULONG uPreviousCycles = uExecutedCycles;
+// NTSC_END
+
if (GetActiveCpu() == CPU_Z80)
{
const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles)
@@ -318,6 +322,14 @@ static DWORD Cpu65C02 (DWORD uTotalCycles)
#undef $
}
+// NTSC_BEGIN
+ if (!g_bFullSpeed)
+ {
+ ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles;
+ NTSC_VideoUpdateCycles( uElapsedCycles );
+ }
+// NTSC_END
+
CheckInterruptSources(uExecutedCycles);
NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
diff --git a/source/CPU/cpu65d02.h b/source/CPU/cpu65d02.h
index f036c139..8d72bbcd 100644
--- a/source/CPU/cpu65d02.h
+++ b/source/CPU/cpu65d02.h
@@ -120,6 +120,10 @@ static DWORD Cpu65D02 (DWORD uTotalCycles)
UINT uExtraCycles = 0;
BYTE iOpcode;
+// NTSC_BEGIN
+ ULONG uPreviousCycles = uExecutedCycles;
+// NTSC_END
+
if (GetActiveCpu() == CPU_Z80)
{
const UINT uZ80Cycles = z80_mainloop(uTotalCycles, uExecutedCycles); CYC(uZ80Cycles)
@@ -403,6 +407,14 @@ static DWORD Cpu65D02 (DWORD uTotalCycles)
}
#undef $
+// NTSC_BEGIN
+ if (!g_bFullSpeed)
+ {
+ ULONG uElapsedCycles = uExecutedCycles - uPreviousCycles;
+ NTSC_VideoUpdateCycles( uElapsedCycles );
+ }
+// NTSC_END
+
CheckInterruptSources(uExecutedCycles);
NMI(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
IRQ(uExecutedCycles, uExtraCycles, flagc, flagn, flagv, flagz);
diff --git a/source/Common.h b/source/Common.h
index 19be87e0..32c76ef1 100644
--- a/source/Common.h
+++ b/source/Common.h
@@ -8,6 +8,7 @@ const double CLK_6502 = ((_M14 * 65.0) / 912.0); // 65 cycles per 912 14M clocks
// See: http://www.apple2info.net/hardware/softcard/SC-SWHW_a2in.pdf
const double CLK_Z80 = (CLK_6502 * 2);
+// TODO: Clean up from Common.h, Video.cpp, and NTSC.h !!!
const UINT uCyclesPerLine = 65; // 25 cycles of HBL & 40 cycles of HBL'
const UINT uVisibleLinesPerFrame = 64*3; // 192
const UINT uLinesPerFrame = 262; // 64 in each third of the screen & 70 in VBL
@@ -177,10 +178,12 @@ enum eApple2Type {
//
// Clones start here:
A2TYPE_CLONE=APPLECLONE_MASK,
- A2TYPE_PRAVETS=APPLECLONE_MASK|APPLE2E_MASK,
- A2TYPE_PRAVETS82=A2TYPE_PRAVETS,
- A2TYPE_PRAVETS8M,
- A2TYPE_PRAVETS8A,
+ A2TYPE_PRAVETS=APPLECLONE_MASK,
+ A2TYPE_PRAVETS82=A2TYPE_PRAVETS, // Apple ][ clone
+ A2TYPE_PRAVETS8M, // Apple ][ clone
+ A2TYPE_BAD_PRAVETS82=A2TYPE_PRAVETS|APPLE2E_MASK, // Wrongly tagged as Apple //e clone (< AppleWin 1.26)
+ A2TYPE_BAD_PRAVETS8M, // Wrongly tagged as Apple //e clone (< AppleWin 1.26)
+ A2TYPE_PRAVETS8A, // Apple //e clone
A2TYPE_MAX
};
diff --git a/source/Configuration/PageConfig.cpp b/source/Configuration/PageConfig.cpp
index 944420d6..f525fc8c 100644
--- a/source/Configuration/PageConfig.cpp
+++ b/source/Configuration/PageConfig.cpp
@@ -114,7 +114,7 @@ BOOL CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM
break;
case IDC_MONOCOLOR:
- VideoChooseColor();
+ VideoChooseMonochromeColor();
break;
case IDC_CHECK_CONFIRM_REBOOT:
diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp
index 1ade6ab4..11215141 100644
--- a/source/Debugger/Debug.cpp
+++ b/source/Debugger/Debug.cpp
@@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "..\Frame.h"
#include "..\Keyboard.h"
#include "..\Memory.h"
+#include "..\NTSC.h"
#include "..\Video.h"
// #define DEBUG_COMMAND_HELP 1
@@ -47,7 +48,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define ALLOW_INPUT_LOWERCASE 1
// See /docs/Debugger_Changelog.txt for full details
- const int DEBUGGER_VERSION = MAKE_VERSION(2,8,0,12);
+ const int DEBUGGER_VERSION = MAKE_VERSION(2,9,0,1);
// Public _________________________________________________________________________________________
@@ -310,7 +311,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
bool g_bTraceHeader = false; // semaphore, flag header to be printed
DWORD extbench = 0;
- bool g_bDebuggerViewingAppleOutput = false;
+ int g_bDebuggerViewingAppleOutput = false; // NOTE: alias for bVideoModeFlags!
bool g_bIgnoreNextKey = false;
@@ -379,6 +380,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
WORD DisasmCalcAddressFromLines( WORD iAddress, int nLines );
+// File _______________________________________________________________________
+
+int _GetFileSize( FILE *hFile )
+{
+ fseek( hFile, 0, SEEK_END );
+ int nFileBytes = ftell( hFile );
+ fseek( hFile, 0, SEEK_SET );
+
+ return nFileBytes;
+}
+
+
+
// Bookmarks __________________________________________________________________
@@ -3999,6 +4013,7 @@ Update_t CmdMemoryFill (int nArgs)
static TCHAR g_sMemoryLoadSaveFileName[ MAX_PATH ] = TEXT("");
+// "PWD"
//===========================================================================
Update_t CmdConfigGetDebugDir (int nArgs)
{
@@ -4009,9 +4024,30 @@ Update_t CmdConfigGetDebugDir (int nArgs)
return ConsoleUpdate();
}
+// "CD"
//===========================================================================
Update_t CmdConfigSetDebugDir (int nArgs)
{
+ //if( nArgs > 2 )
+ // return;
+
+ // PWD directory
+#if _WIN32
+ // http://msdn.microsoft.com/en-us/library/aa365530(VS.85).aspx
+ TCHAR sPath[ MAX_PATH + 1 ];
+ _tcscpy( sPath, g_sCurrentDir ); // TODO: debugger dir has no ` CONSOLE_COLOR_ESCAPE_CHAR ?!?!
+ _tcscat( sPath, g_aArgs[ 1 ].sArg );
+
+ if( SetCurrentImageDir( sPath ) )
+ nArgs = 0; // intentional fall into
+#else
+ #error "Need chdir() implemented"
+#endif
+
+ // PWD
+ if( nArgs == 0 )
+ return CmdConfigGetDebugDir(0);
+
return ConsoleUpdate();
}
@@ -4095,9 +4131,7 @@ Update_t CmdMemoryLoad (int nArgs)
FILE *hFile = fopen( sLoadSaveFilePath, "rb" );
if (hFile)
{
- fseek( hFile, 0, SEEK_END );
- int nFileBytes = ftell( hFile );
- fseek( hFile, 0, SEEK_SET );
+ int nFileBytes = _GetFileSize( hFile );
if (nFileBytes > _6502_MEM_END)
nFileBytes = _6502_MEM_END + 1; // Bank-switched RAMR/ROM is only 16-bit
@@ -4217,12 +4251,12 @@ Update_t CmdMemoryLoad (int nArgs)
,{ ".hgr2", 0x4000, 0x2000 }
// TODO: extension ".dhgr", ".dhgr2"
};
- const int nFileTypes = sizeof( aFileTypes ) / sizeof( KnownFileType_t );
+ const int nFileTypes = sizeof( aFileTypes ) / sizeof( KnownFileType_t );
const KnownFileType_t *pFileType = NULL;
char *pFileName = g_aArgs[ 1 ].sArg;
int nLen = strlen( pFileName );
- char *pEnd = pFileName + + nLen - 1;
+ char *pEnd = pFileName + nLen - 1;
while( pEnd > pFileName )
{
if( *pEnd == '.' )
@@ -4297,9 +4331,7 @@ Update_t CmdMemoryLoad (int nArgs)
FILE *hFile = fopen( sLoadSaveFilePath, "rb" );
if (hFile)
{
- fseek( hFile, 0, SEEK_END );
- int nFileBytes = ftell( hFile );
- fseek( hFile, 0, SEEK_SET );
+ int nFileBytes = _GetFileSize( hFile );
if (nFileBytes > _6502_MEM_END)
nFileBytes = _6502_MEM_END + 1; // Bank-switched RAM/ROM is only 16-bit
@@ -4401,7 +4433,6 @@ Update_t CmdMemoryMove (int nArgs)
return UPDATE_CONSOLE_DISPLAY;
}
-
//===========================================================================
#if 0 // Original
Update_t CmdMemorySave (int nArgs)
@@ -4652,6 +4683,7 @@ Update_t CmdMemorySave (int nArgs)
{
ConsoleBufferPush( TEXT( "Warning: File already exists. Overwriting." ) );
fclose( hFile );
+ // TODO: BUG: Is this a bug/feature that we can over-write files and the user has no control over that?
}
hFile = fopen( sLoadSaveFilePath, "wb" );
@@ -4842,6 +4874,359 @@ void Util_CopyTextToClipboard ( const size_t nSize, const char *pText )
// GlobalFree() ??
}
+//===========================================================================
+Update_t CmdNTSC (int nArgs)
+{
+ int iParam;
+ int nFound = FindParam( g_aArgs[ 1 ].sArg, MATCH_EXACT, iParam, _PARAM_GENERAL_BEGIN, _PARAM_GENERAL_END );
+
+ struct KnownFileType_t
+ {
+ char *pExtension;
+ };
+
+ enum KnownFileType_e
+ {
+ TYPE_UNKNOWN
+ ,TYPE_BMP
+ ,TYPE_RAW
+ ,NUM_FILE_TYPES
+ };
+
+ const KnownFileType_t aFileTypes[ NUM_FILE_TYPES ] =
+ {
+ { "" } // n/a
+ ,{ ".bmp" }
+ ,{ ".data" }
+// ,{ ".raw" }
+// ,{ ".ntsc" }
+ };
+ const int nFileType = sizeof( aFileTypes ) / sizeof( KnownFileType_t );
+ const KnownFileType_t *pFileType = NULL;
+ /* */ KnownFileType_e iFileType = TYPE_UNKNOWN;
+
+#if _DEBUG
+ assert( (nFileType == NUM_FILE_TYPES) );
+#endif
+
+ char *pFileName = (nArgs > 1) ? g_aArgs[ 2 ].sArg : "";
+ int nLen = strlen( pFileName );
+ char *pEnd = pFileName + nLen - 1;
+ while( pEnd > pFileName )
+ {
+ if( *pEnd == '.' )
+ {
+ for( int i = TYPE_BMP; i < NUM_FILE_TYPES; i++ )
+ {
+ if( strcmp( pEnd, aFileTypes[i].pExtension ) == 0 )
+ {
+ pFileType = &aFileTypes[i];
+ iFileType = (KnownFileType_e) i;
+ break;
+ }
+ }
+ }
+
+ if( pFileType )
+ break;
+
+ pEnd--;
+ }
+
+ if( nLen == 0 )
+ pFileName = "AppleWinNTSC4096x4@32.data";
+
+ static TCHAR sPaletteFilePath[ MAX_PATH ];
+ _tcscpy( sPaletteFilePath, g_sCurrentDir );
+ _tcscat( sPaletteFilePath, pFileName );
+
+ class ConsoleFilename
+ {
+ public:
+ static void update( const char *pPrefixText )
+ {
+ TCHAR text[ CONSOLE_WIDTH ] = TEXT("");
+ sprintf( text, "%s: %s", pPrefixText, sPaletteFilePath );
+ ConsoleBufferPush( text ); // "Saved."
+ }
+ };
+
+ class Swizzle32
+ {
+ public:
+ static void RGBAswapBGRA( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly
+ {
+ const uint8_t* pEnd = pSrc + nSize;
+ while ( pSrc < pEnd )
+ {
+ const uint8_t r = pSrc[2];
+ const uint8_t g = pSrc[1];
+ const uint8_t b = pSrc[0];
+ const uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255
+
+ *pDst++ = r;
+ *pDst++ = g;
+ *pDst++ = b;
+ *pDst++ = a;
+ pSrc += 4;
+ }
+ }
+
+ static void ABGRswizzleBGRA( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly
+ {
+ const uint8_t* pEnd = pSrc + nSize;
+ while ( pSrc < pEnd )
+ {
+ const uint8_t r = pSrc[3];
+ const uint8_t g = pSrc[2];
+ const uint8_t b = pSrc[1];
+ const uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255
+
+ *pDst++ = b;
+ *pDst++ = g;
+ *pDst++ = r;
+ *pDst++ = a;
+ pSrc += 4;
+ }
+ }
+#if 0
+ static void ABGRswizzleRGBA( size_t nSize, const uint8_t *pSrc, uint8_t *pDst ) // Note: pSrc and pDst _may_ alias; code handles this properly
+ {
+ const uint8_t* pEnd = pSrc + nSize;
+ while ( pSrc < pEnd )
+ {
+ const uint8_t r = pSrc[3];
+ const uint8_t g = pSrc[2];
+ const uint8_t b = pSrc[1];
+ const uint8_t a = 255; // Force A=1, 100% opacity; as pSrc[3] might not be 255
+
+ *pDst++ = r;
+ *pDst++ = g;
+ *pDst++ = b;
+ *pDst++ = a;
+ pSrc += 4;
+ }
+ }
+#endif
+ };
+
+ class Transpose4096x4
+ {
+ /*
+ . Source layout = 4096x4 @ 32-bit
+ . +----+----+----+----+----+
+ . |BGRA|BGRA|BGRA|... |BGRA| phase 0
+ . +----+----+----+----+----+
+ . |BGRA|BGRA|BGRA|... |BGRA| phase 1
+ . +----+----+----+----+----|
+ . |BGRA|BGRA|BGRA|... |BGRA| phase 2
+ . +----+----+----+----+----+
+ . |BGRA|BGRA|BGRA|... |BGRA| phase 3
+ . +----+----+----+----+----+
+ . 0 1 2 4095 column
+ .
+ . Destination layout = 64x256 @ 32-bit
+ . | phase 0 | phase 1 | phase 2 | phase 3 |
+ . +----+----+----+----+----+----+----+----+
+ . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 0
+ . +----+----+----+----+----+----+----+----+
+ . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 1
+ . +----+----+----+----+----+----+----+----+
+ . |... |... |... |... |... |... |... |... |
+ . +----+----+----+----+----+----+----+----+
+ . |BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA|BGRA| row 255
+ . +----+----+----+----+----+----+----+----+
+ . \ 16 px / \ 16 px / \ 16 px / \ 16 px / = 64 pixels
+ . 64 byte 64 byte 64 byte 64 byte
+ */
+
+ public:
+ static void transposeTo64x256( size_t nSize, const uint8_t *pSrc, uint8_t *pDst )
+ {
+ /* */ uint8_t *pTmp = pDst;
+ const uint32_t nBPP = 4; // bytes per pixel
+
+ for( int iPhase = 0; iPhase < 4; iPhase++ )
+ {
+ pDst = pTmp + (iPhase * 16 * nBPP); // dst is 16-px column
+
+ for( int x = 0; x < 4096/16; x++ ) // 4096px/16 px = 256 columns
+ {
+ for( int i = 0; i < 16*nBPP; i++ ) // 16 px, 32-bit
+ *pDst++ = *pSrc++;
+
+ pDst -= (16*nBPP);
+ pDst += (64*nBPP); // move to next scan line
+ }
+ }
+ }
+
+ static void transposeFrom64x256( size_t nSize, const uint8_t *pSrc, uint8_t *pDst )
+ {
+ const uint8_t *pTmp = pSrc;
+ const uint32_t nBPP = 4; // bytes per pixel
+
+ for( int iPhase = 0; iPhase < 4; iPhase++ )
+ {
+ pSrc = pTmp + (iPhase * 16 * nBPP); // src is 16-px column
+ for( int y = 0; y < 256; y++ )
+ {
+ for( int i = 0; i < 16*nBPP; i++ ) // 16 px, 32-bit
+ *pDst++ = *pSrc++;
+
+ pSrc -= (16*nBPP);
+ pSrc += (64*nBPP); // move to next scan line
+ }
+ }
+ }
+ };
+
+ bool bColorTV = (g_eVideoType == VT_COLOR_TV);
+
+ uint32_t* pChromaTable = NTSC_VideoGetChromaTable( false, bColorTV );
+ char aStatusText[64] = "Loaded";
+
+//uint8_t* pTmp = (uint8_t*) pChromaTable;
+//*pTmp++ = 0xFF; // b
+//*pTmp++ = 0x00; // g
+//*pTmp++ = 0x00; // r
+//*pTmp++ = 0xFF; // a
+
+ if (nFound)
+ {
+ if (iParam == PARAM_RESET)
+ {
+ NTSC_VideoInitChroma();
+ ConsoleBufferPush( TEXT(" Resetting NTSC palette." ) );
+ }
+ else
+ if (iParam == PARAM_SAVE)
+ {
+ FILE *pFile = fopen( sPaletteFilePath, "w+b" );
+ if( pFile )
+ {
+ size_t nWrote = 0;
+ uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ];
+
+ if( iFileType == TYPE_BMP )
+ {
+ // need to save 32-bit bpp as 24-bit bpp
+ // VideoSaveScreenShot()
+ Transpose4096x4::transposeTo64x256( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled );
+
+ // Write BMP header
+ WinBmpHeader_t bmp, *pBmp = &bmp;
+ Video_SetBitmapHeader( pBmp, 64, 256, 32 );
+ fwrite( pBmp, sizeof( WinBmpHeader_t ), 1, pFile );
+ }
+ else
+ {
+ // RAW has no header
+ Swizzle32::RGBAswapBGRA( g_nChromaSize, (uint8_t*) pChromaTable, pSwizzled );
+ }
+
+ nWrote = fwrite( pSwizzled, g_nChromaSize, 1, pFile );
+ fclose( pFile );
+ delete [] pSwizzled;
+
+ if (nWrote == 1)
+ {
+ ConsoleFilename::update( "Saved" );
+ }
+ else
+ ConsoleBufferPush( TEXT( "Error saving." ) );
+ }
+ else
+ {
+ ConsoleFilename::update( "File" );
+ ConsoleBufferPush( TEXT( "Error couldn't open file for writing." ) );
+ }
+ }
+ else
+ if (iParam == PARAM_LOAD)
+ {
+ FILE *pFile = fopen( sPaletteFilePath, "rb" );
+ if( pFile )
+ {
+ strcpy( aStatusText, "Loaded" );
+
+ // Get File Size
+ size_t nFileSize = _GetFileSize( pFile );
+ uint8_t *pSwizzled = new uint8_t[ g_nChromaSize ];
+ bool bSwizzle = true;
+
+ if( iFileType == TYPE_BMP )
+ {
+ WinBmpHeader4_t bmp, *pBmp = &bmp;
+ fread( pBmp, sizeof( WinBmpHeader4_t ), 1, pFile );
+ fseek( pFile, pBmp->nOffsetData, SEEK_SET );
+
+ if( 0
+ || (pBmp->nWidthPixels != 64 )
+ || (pBmp->nHeightPixels != 256)
+ || (pBmp->nBitsPerPixel != 32 )
+ || (pBmp->nOffsetData > nFileSize)
+ )
+ {
+ strcpy( aStatusText, "Bitmap not 64x256@32" );
+ goto _error;
+ }
+
+ if(pBmp->nStructSize == 0x28)
+ {
+ if( pBmp->nCompression == 0) // BI_RGB mode
+ bSwizzle = false;
+ }
+ else // 0x7C version4 bitmap
+ {
+ if( pBmp->nCompression == 3 ) // BI_BITFIELDS
+ {
+ if((pBmp->nRedMask == 0xFF000000 ) // Gimp writes in ABGR order
+ && (pBmp->nGreenMask == 0x00FF0000 )
+ && (pBmp->nBlueMask == 0x0000FF00 ))
+ bSwizzle = true;
+ }
+ }
+ }
+ else
+ if( nFileSize != g_nChromaSize )
+ {
+ sprintf( aStatusText, "Raw size != %d", 64*256*4 );
+ goto _error;
+ }
+
+
+ size_t nRead = fread( pSwizzled, g_nChromaSize, 1, pFile );
+
+ if( iFileType == TYPE_BMP )
+ {
+ Transpose4096x4::transposeFrom64x256( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable );
+ if( bSwizzle )
+ Swizzle32::ABGRswizzleBGRA( g_nChromaSize, (uint8_t*) pChromaTable, (uint8_t*) pChromaTable );
+ }
+ else
+ Swizzle32::RGBAswapBGRA( g_nChromaSize, pSwizzled, (uint8_t*) pChromaTable );
+
+_error:
+ fclose( pFile );
+ delete [] pSwizzled;
+ }
+ else
+ {
+ strcpy( aStatusText, "File: " );
+ ConsoleBufferPush( TEXT( "Error couldn't open file for reading." ) );
+ }
+
+ ConsoleFilename::update( aStatusText );
+ }
+ else
+ return HelpLastCommand();
+ }
+// else
+
+ return ConsoleUpdate();
+}
+
//===========================================================================
int CmdTextSave (int nArgs)
@@ -6072,100 +6457,104 @@ enum ViewVideoPage_t
Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate );
-Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate )
+Update_t _ViewOutput( ViewVideoPage_t iPage, int bVideoModeFlags )
{
VideoSetForceFullRedraw();
- _Video_Dirty();
+
switch( iPage )
{
- case VIEW_PAGE_X: _Video_SetupBanks( VideoGetSWPAGE2() ); break; // Page Current
- case VIEW_PAGE_1: _Video_SetupBanks( false ); break; // Page 1
- case VIEW_PAGE_2: _Video_SetupBanks( true ); break; // Page 2 !
+ case VIEW_PAGE_X: bVideoModeFlags |= _Video_SetupBanks( VideoGetSWPAGE2() ); break; // Page Current
+ case VIEW_PAGE_1: bVideoModeFlags |= _Video_SetupBanks( false ); break; // Page 1
+ case VIEW_PAGE_2: bVideoModeFlags |= _Video_SetupBanks( true ); break; // Page 2 !
default:
break;
}
- _Video_RedrawScreen( pfUpdate );
- g_bDebuggerViewingAppleOutput = true;
+#if _DEBUG
+ if (bVideoModeFlags == 0)
+ MessageBoxA( NULL, "bVideoModeFlags = ZERO !?", "Information", MB_OK );
+#endif
+ g_bDebuggerViewingAppleOutput = bVideoModeFlags;
+ VideoRefreshScreen( bVideoModeFlags );
return UPDATE_NOTHING; // intentional
}
// Text 40
Update_t CmdViewOutput_Text4X (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_X, Update40ColCell );
+ return _ViewOutput( VIEW_PAGE_X, VF_TEXT );
}
Update_t CmdViewOutput_Text41 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_1, Update40ColCell );
+ return _ViewOutput( VIEW_PAGE_1, VF_TEXT );
}
Update_t CmdViewOutput_Text42 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_2, Update40ColCell );
+ return _ViewOutput( VIEW_PAGE_2, VF_TEXT );
}
// Text 80
Update_t CmdViewOutput_Text8X (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_X, Update80ColCell );
+ return _ViewOutput( VIEW_PAGE_X, VF_TEXT | VF_80COL );
}
Update_t CmdViewOutput_Text81 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_1, Update80ColCell );
+ return _ViewOutput( VIEW_PAGE_1, VF_TEXT | VF_80COL );
}
Update_t CmdViewOutput_Text82 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_2, Update80ColCell );
+ return _ViewOutput( VIEW_PAGE_2, VF_TEXT | VF_80COL );
}
// Lo-Res
Update_t CmdViewOutput_GRX (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_X, UpdateLoResCell );
+ return _ViewOutput( VIEW_PAGE_X, VF_80STORE ); // NTSC VideoRefresh() Hack: flags != 0
}
Update_t CmdViewOutput_GR1 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_1, UpdateLoResCell );
+ return _ViewOutput( VIEW_PAGE_1, VF_80STORE ); // NTSC VideoRefresh() Hack: flags != 0
}
Update_t CmdViewOutput_GR2 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_2, UpdateLoResCell );
+ return _ViewOutput( VIEW_PAGE_2, VF_80STORE ); // NTSC VideoRefresh() Hack: flags != 0
}
// Double Lo-Res
Update_t CmdViewOutput_DGRX (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_X, UpdateDLoResCell );
+ return _ViewOutput( VIEW_PAGE_X, VF_DHIRES | VF_80COL );
}
Update_t CmdViewOutput_DGR1 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_1, UpdateDLoResCell );
+ return _ViewOutput( VIEW_PAGE_1, VF_DHIRES | VF_80COL );
}
Update_t CmdViewOutput_DGR2 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_2, UpdateDLoResCell );
+ return _ViewOutput( VIEW_PAGE_2, VF_DHIRES | VF_80COL );
}
// Hi-Res
Update_t CmdViewOutput_HGRX (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_X, UpdateHiResCell );
+ return _ViewOutput( VIEW_PAGE_X, VF_HIRES );
}
Update_t CmdViewOutput_HGR1 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_1, UpdateHiResCell );
+ return _ViewOutput( VIEW_PAGE_1, VF_HIRES );
}
Update_t CmdViewOutput_HGR2 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_2, UpdateHiResCell );
+ return _ViewOutput( VIEW_PAGE_2, VF_HIRES );
}
// Double Hi-Res
Update_t CmdViewOutput_DHGRX (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_X, UpdateDHiResCell );
+ return _ViewOutput( VIEW_PAGE_X, VF_HIRES | VF_DHIRES | VF_80COL );
}
Update_t CmdViewOutput_DHGR1 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_1, UpdateDHiResCell );
+ return _ViewOutput( VIEW_PAGE_1, VF_HIRES | VF_DHIRES | VF_80COL);
}
Update_t CmdViewOutput_DHGR2 (int nArgs)
{
- return _ViewOutput( VIEW_PAGE_2, UpdateDHiResCell );
+ return _ViewOutput( VIEW_PAGE_2, VF_HIRES | VF_DHIRES | VF_80COL );
}
// Watches ________________________________________________________________________________________
@@ -7327,6 +7716,9 @@ bool InternalSingleStep ()
//===========================================================================
+
+#define TRACELINE_WITH_VIDEO_SCANNER_POS 0
+
void OutputTraceLine ()
{
DisasmLine_t line;
@@ -7344,8 +7736,13 @@ void OutputTraceLine ()
g_bTraceHeader = false;
fprintf( g_hTraceFile,
+#if TRACELINE_WITH_VIDEO_SCANNER_POS
+// "0000 0000 00 00 00 0000 -------- 0000:90 90 90 NOP"
+ "Vert Horz A: X: Y: SP: Flags Addr:Opcode Mnemonic\n"
+#else
// "00 00 00 0000 -------- 0000:90 90 90 NOP"
"A: X: Y: SP: Flags Addr:Opcode Mnemonic\n"
+#endif
);
}
@@ -7358,6 +7755,21 @@ void OutputTraceLine ()
);
}
+#if TRACELINE_WITH_VIDEO_SCANNER_POS
+ fprintf( g_hTraceFile,
+// "a=%02x x=%02x y=%02x sp=%03x ps=%s %s\n",
+ "%04X %04X %02X %02X %02X %04X %s %s\n",
+ g_nVideoClockVert,
+ g_nVideoClockHorz,
+ (unsigned)regs.a,
+ (unsigned)regs.x,
+ (unsigned)regs.y,
+ (unsigned)regs.sp,
+ (char*) sFlags
+ , sDisassembly
+ //, sTarget // TODO: Show target?
+ );
+#else
fprintf( g_hTraceFile,
// "a=%02x x=%02x y=%02x sp=%03x ps=%s %s\n",
"%02X %02X %02X %04X %s %s\n",
@@ -7369,6 +7781,7 @@ void OutputTraceLine ()
, sDisassembly
//, sTarget // TODO: Show target?
);
+#endif
}
}
@@ -7821,8 +8234,8 @@ void DebugContinueStepping ()
{
if (nStepsTaken == 0x10000) // HACK_MAGIC_NUM
VideoRedrawScreen();
- else
- VideoRefreshScreen();
+// else
+// VideoRefreshScreen();
}
}
else
diff --git a/source/Debugger/Debug.h b/source/Debugger/Debug.h
index 5c69c604..add6cca5 100644
--- a/source/Debugger/Debug.h
+++ b/source/Debugger/Debug.h
@@ -105,7 +105,7 @@
extern int g_aDisasmTargets[ MAX_DISPLAY_LINES ];
// Display
- extern bool g_bDebuggerViewingAppleOutput;
+ extern int g_bDebuggerViewingAppleOutput;
// Font
extern int g_nFontHeight;
diff --git a/source/Debugger/Debugger_Assembler.cpp b/source/Debugger/Debugger_Assembler.cpp
index 4c2730cd..3acc73bd 100644
--- a/source/Debugger/Debugger_Assembler.cpp
+++ b/source/Debugger/Debugger_Assembler.cpp
@@ -470,6 +470,10 @@ int _6502_GetOpmodeOpbyte ( const int nBaseAddress, int & iOpmode_, int & nOpby
if (! g_aOpcodes)
{
MessageBox( g_hFrameWindow, "Debugger not properly initialized", "ERROR", MB_OK );
+
+ g_aOpcodes = & g_aOpcodes65C02[ 0 ]; // Enhanced Apple //e
+ g_aOpmodes[ AM_2 ].m_nBytes = 2;
+ g_aOpmodes[ AM_3 ].m_nBytes = 3;
}
#endif
diff --git a/source/Debugger/Debugger_Color.cpp b/source/Debugger/Debugger_Color.cpp
index b4cf421c..dc737b09 100644
--- a/source/Debugger/Debugger_Color.cpp
+++ b/source/Debugger/Debugger_Color.cpp
@@ -42,7 +42,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
RGB(255,255, 0), RGB(223,223, 0), RGB(191,191, 0), RGB(159,159, 0), RGB(127,127, 0), RGB( 95, 95, 0), RGB( 63, 63, 0), RGB( 31, 31, 0), // 011 // Yellow
RGB( 0, 0,255), RGB( 0, 0,223), RGB( 0, 0,191), RGB( 0, 0,159), RGB( 0, 0,127), RGB( 0, 0, 95), RGB( 0, 0, 63), RGB( 0, 0, 31), // 100 // Blue
RGB(255, 0,255), RGB(223, 0,223), RGB(191, 0,191), RGB(159, 0,159), RGB(127, 0,127), RGB( 95, 0, 95), RGB( 63, 0, 63), RGB( 31, 0, 31), // 101 // Magenta
- RGB( 0,255,255), RGB( 0,223,223), RGB( 0,191,191), RGB( 0,159,159), RGB( 0,127,127), RGB( 0, 95, 95), RGB( 0, 63, 63), RGB( 0, 31, 31), // 110 // Cyan
+ RGB( 0,255,255), RGB( 0,223,223), RGB( 0,191,191), RGB( 0,159,159), RGB( 0,127,127), RGB( 0, 95, 95), RGB( 0, 63, 63), RGB( 0, 31, 31), // 110 // Cyan
RGB(255,255,255), RGB(223,223,223), RGB(191,191,191), RGB(159,159,159), RGB(127,127,127), RGB( 95, 95, 95), RGB( 63, 63, 63), RGB( 31, 31, 31), // 111 // White/Gray
// Custom Colors
diff --git a/source/Debugger/Debugger_Commands.cpp b/source/Debugger/Debugger_Commands.cpp
index 72fe701d..970ec3d1 100644
--- a/source/Debugger/Debugger_Commands.cpp
+++ b/source/Debugger/Debugger_Commands.cpp
@@ -40,11 +40,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Command_t g_aCommands[] =
{
// Assembler
+// {TEXT("!") , CmdAssemberMini , CMD_ASSEMBLER_MINI , "Mini assembler" },
{TEXT("A") , CmdAssemble , CMD_ASSEMBLE , "Assemble instructions" },
// CPU (Main)
{TEXT(".") , CmdCursorJumpPC , CMD_CURSOR_JUMP_PC , "Locate the cursor in the disasm window" }, // centered
{TEXT("=") , CmdCursorSetPC , CMD_CURSOR_SET_PC , "Sets the PC to the current instruction" },
- {TEXT("G") , CmdGo , CMD_GO , "Run [until PC = address]" },
+// {TEXT("g") , CmdGoNormalSpeed , CMD_GO_NORMAL , "Run @ normal speed [until PC == address]" },
+// {TEXT("G") , CmdGoFullSpeed , CMD_GO_FULL , "Run @ full speed [until PC == address]" },
+ {TEXT("G") , CmdGo , CMD_GO , "Run @ full speed [until PC == address]" },
{TEXT("IN") , CmdIn , CMD_IN , "Input byte from IO $C0xx" },
{TEXT("KEY") , CmdKey , CMD_INPUT_KEY , "Feed key into emulator" },
{TEXT("JSR") , CmdJSR , CMD_JSR , "Call sub-routine" },
@@ -201,6 +204,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{TEXT("SH") , CmdMemorySearchHex , CMD_MEMORY_SEARCH_HEX , "Search memory for hex values" },
{TEXT("F") , CmdMemoryFill , CMD_MEMORY_FILL , "Memory fill" },
+ {TEXT("NTSC") , CmdNTSC , CMD_NTSC , "Save/Load the NTSC palette" },
{TEXT("TSAVE") , CmdTextSave , CMD_TEXT_SAVE , "Save text screen" },
// Output / Scripts
{TEXT("CALC") , CmdOutputCalc , CMD_OUTPUT_CALC , "Display mini calc result" },
diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp
index 9b854941..7bb24bfd 100644
--- a/source/Debugger/Debugger_Display.cpp
+++ b/source/Debugger/Debugger_Display.cpp
@@ -562,13 +562,18 @@ void StretchBltMemToFrameDC(void)
int nViewportCX, nViewportCY;
GetViewportCXCY(nViewportCX, nViewportCY);
+ int xdest = GetFullScreenOffsetX();
+ int ydest = GetFullScreenOffsetY();
+ int wdest = nViewportCX;
+ int hdest = nViewportCY;
+
BOOL bRes = StretchBlt(
FrameGetDC(), // HDC hdcDest,
- 0, 0, // int nXOriginDest, int nYOriginDest,
- nViewportCX, nViewportCY, // int nWidthDest, int nHeightDest,
+ xdest, ydest, // int nXOriginDest, int nYOriginDest,
+ wdest, hdest, // int nWidthDest, int nHeightDest,
GetDebuggerMemDC(), // HDC hdcSrc,
0, 0, // int nXOriginSrc, int nYOriginSrc,
- FRAMEBUFFER_W, FRAMEBUFFER_H, // int nWidthSrc, int nHeightSrc,
+ FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H, // int nWidthSrc, int nHeightSrc,
SRCCOPY // DWORD dwRop
);
}
diff --git a/source/Debugger/Debugger_Types.h b/source/Debugger/Debugger_Types.h
index b96d4b88..a59259cb 100644
--- a/source/Debugger/Debugger_Types.h
+++ b/source/Debugger/Debugger_Types.h
@@ -442,6 +442,7 @@
// , CMD_MEMORY_SEARCH_APPLE // Flashing Chars, Hi-Bit Set
, CMD_MEMORY_SEARCH_HEX
, CMD_MEMORY_FILL
+ , CMD_NTSC
, CMD_TEXT_SAVE
// Output
, CMD_OUTPUT_CALC
@@ -555,7 +556,7 @@
};
// Assembler
- Update_t CmdAssemble (int nArgs);
+ Update_t CmdAssemble (int nArgs);
// Disassembler Data
Update_t CmdDisasmDataDefCode (int nArgs);
@@ -577,89 +578,89 @@
Update_t CmdDisasmDataDefAddress16(int nArgs);
// CPU
- Update_t CmdCursorJumpPC(int nArgs);
- Update_t CmdCursorSetPC (int nArgs);
- Update_t CmdBreakInvalid(int nArgs); // Breakpoint IFF Full-speed!
- Update_t CmdBreakOpcode (int nArgs); // Breakpoint IFF Full-speed!
- Update_t CmdGo (int nArgs);
- Update_t CmdIn (int nArgs);
- Update_t CmdKey (int nArgs);
- Update_t CmdJSR (int nArgs);
- Update_t CmdNOP (int nArgs);
- Update_t CmdOut (int nArgs);
- Update_t CmdStepOver (int nArgs);
- Update_t CmdStepOut (int nArgs);
- Update_t CmdTrace (int nArgs); // alias for CmdStepIn
- Update_t CmdTraceFile (int nArgs);
- Update_t CmdTraceLine (int nArgs);
- Update_t CmdUnassemble (int nArgs); // code dump, aka, Unassemble
+ Update_t CmdCursorJumpPC (int nArgs);
+ Update_t CmdCursorSetPC (int nArgs);
+ Update_t CmdBreakInvalid (int nArgs); // Breakpoint IFF Full-speed!
+ Update_t CmdBreakOpcode (int nArgs); // Breakpoint IFF Full-speed!
+ Update_t CmdGo (int nArgs);
+ Update_t CmdIn (int nArgs);
+ Update_t CmdKey (int nArgs);
+ Update_t CmdJSR (int nArgs);
+ Update_t CmdNOP (int nArgs);
+ Update_t CmdOut (int nArgs);
+ Update_t CmdStepOver (int nArgs);
+ Update_t CmdStepOut (int nArgs);
+ Update_t CmdTrace (int nArgs); // alias for CmdStepIn
+ Update_t CmdTraceFile (int nArgs);
+ Update_t CmdTraceLine (int nArgs);
+ Update_t CmdUnassemble (int nArgs); // code dump, aka, Unassemble
// Bookmarks
- Update_t CmdBookmark (int nArgs);
- Update_t CmdBookmarkAdd (int nArgs);
- Update_t CmdBookmarkClear (int nArgs);
- Update_t CmdBookmarkList (int nArgs);
- Update_t CmdBookmarkGoto (int nArgs);
-// Update_t CmdBookmarkLoad (int nArgs);
- Update_t CmdBookmarkSave (int nArgs);
+ Update_t CmdBookmark (int nArgs);
+ Update_t CmdBookmarkAdd (int nArgs);
+ Update_t CmdBookmarkClear (int nArgs);
+ Update_t CmdBookmarkList (int nArgs);
+ Update_t CmdBookmarkGoto (int nArgs);
+// Update_t CmdBookmarkLoad (int nArgs);
+ Update_t CmdBookmarkSave (int nArgs);
// Breakpoints
- Update_t CmdBreakpoint (int nArgs);
- Update_t CmdBreakpointAddSmart(int nArgs);
- Update_t CmdBreakpointAddReg (int nArgs);
- Update_t CmdBreakpointAddPC (int nArgs);
- Update_t CmdBreakpointAddIO (int nArgs);
- Update_t CmdBreakpointAddMem (int nArgs);
- Update_t CmdBreakpointClear (int nArgs);
- Update_t CmdBreakpointDisable (int nArgs);
- Update_t CmdBreakpointEdit (int nArgs);
- Update_t CmdBreakpointEnable (int nArgs);
- Update_t CmdBreakpointList (int nArgs);
-// Update_t CmdBreakpointLoad (int nArgs);
- Update_t CmdBreakpointSave (int nArgs);
+ Update_t CmdBreakpoint (int nArgs);
+ Update_t CmdBreakpointAddSmart (int nArgs);
+ Update_t CmdBreakpointAddReg (int nArgs);
+ Update_t CmdBreakpointAddPC (int nArgs);
+ Update_t CmdBreakpointAddIO (int nArgs);
+ Update_t CmdBreakpointAddMem (int nArgs);
+ Update_t CmdBreakpointClear (int nArgs);
+ Update_t CmdBreakpointDisable (int nArgs);
+ Update_t CmdBreakpointEdit (int nArgs);
+ Update_t CmdBreakpointEnable (int nArgs);
+ Update_t CmdBreakpointList (int nArgs);
+// Update_t CmdBreakpointLoad (int nArgs);
+ Update_t CmdBreakpointSave (int nArgs);
// Benchmark
- Update_t CmdBenchmark (int nArgs);
- Update_t CmdBenchmarkStart (int nArgs); //Update_t CmdSetupBenchmark (int nArgs);
- Update_t CmdBenchmarkStop (int nArgs); //Update_t CmdExtBenchmark (int nArgs);
- Update_t CmdProfile (int nArgs);
- Update_t CmdProfileStart (int nArgs);
- Update_t CmdProfileStop (int nArgs);
+ Update_t CmdBenchmark (int nArgs);
+ Update_t CmdBenchmarkStart (int nArgs); //Update_t CmdSetupBenchmark (int nArgs);
+ Update_t CmdBenchmarkStop (int nArgs); //Update_t CmdExtBenchmark (int nArgs);
+ Update_t CmdProfile (int nArgs);
+ Update_t CmdProfileStart (int nArgs);
+ Update_t CmdProfileStop (int nArgs);
// Config
-// Update_t CmdConfigMenu (int nArgs);
-// Update_t CmdConfigBase (int nArgs);
-// Update_t CmdConfigBaseHex (int nArgs);
-// Update_t CmdConfigBaseDec (int nArgs);
- Update_t CmdConfigColorMono (int nArgs);
- Update_t CmdConfigDisasm (int nArgs);
- Update_t CmdConfigFont (int nArgs);
- Update_t CmdConfigHColor (int nArgs);
- Update_t CmdConfigLoad (int nArgs);
- Update_t CmdConfigSave (int nArgs);
- Update_t CmdConfigSetFont (int nArgs);
- Update_t CmdConfigGetFont (int nArgs);
- Update_t CmdConfigGetDebugDir (int nArgs);
- Update_t CmdConfigSetDebugDir (int nArgs);
+// Update_t CmdConfigMenu (int nArgs);
+// Update_t CmdConfigBase (int nArgs);
+// Update_t CmdConfigBaseHex (int nArgs);
+// Update_t CmdConfigBaseDec (int nArgs);
+ Update_t CmdConfigColorMono (int nArgs);
+ Update_t CmdConfigDisasm (int nArgs);
+ Update_t CmdConfigFont (int nArgs);
+ Update_t CmdConfigHColor (int nArgs);
+ Update_t CmdConfigLoad (int nArgs);
+ Update_t CmdConfigSave (int nArgs);
+ Update_t CmdConfigSetFont (int nArgs);
+ Update_t CmdConfigGetFont (int nArgs);
+ Update_t CmdConfigGetDebugDir (int nArgs);
+ Update_t CmdConfigSetDebugDir (int nArgs);
// Cursor
- Update_t CmdCursorFollowTarget(int nArgs);
- Update_t CmdCursorLineDown (int nArgs);
- Update_t CmdCursorLineUp (int nArgs);
- Update_t CmdCursorJumpRetAddr (int nArgs);
- Update_t CmdCursorRunUntil (int nArgs);
- Update_t CmdCursorPageDown (int nArgs);
- Update_t CmdCursorPageDown256 (int nArgs);
- Update_t CmdCursorPageDown4K (int nArgs);
- Update_t CmdCursorPageUp (int nArgs);
- Update_t CmdCursorPageUp256 (int nArgs);
- Update_t CmdCursorPageUp4K (int nArgs);
+ Update_t CmdCursorFollowTarget (int nArgs);
+ Update_t CmdCursorLineDown (int nArgs);
+ Update_t CmdCursorLineUp (int nArgs);
+ Update_t CmdCursorJumpRetAddr (int nArgs);
+ Update_t CmdCursorRunUntil (int nArgs);
+ Update_t CmdCursorPageDown (int nArgs);
+ Update_t CmdCursorPageDown256 (int nArgs);
+ Update_t CmdCursorPageDown4K (int nArgs);
+ Update_t CmdCursorPageUp (int nArgs);
+ Update_t CmdCursorPageUp256 (int nArgs);
+ Update_t CmdCursorPageUp4K (int nArgs);
// Disk
- Update_t CmdDisk (int nArgs);
+ Update_t CmdDisk (int nArgs);
// Help
- Update_t CmdHelpList (int nArgs);
- Update_t CmdHelpSpecific (int Argss);
- Update_t CmdVersion (int nArgs);
- Update_t CmdMOTD (int nArgs);
+ Update_t CmdHelpList (int nArgs);
+ Update_t CmdHelpSpecific (int Argss);
+ Update_t CmdVersion (int nArgs);
+ Update_t CmdMOTD (int nArgs);
// Flags
- Update_t CmdFlag (int nArgs);
- Update_t CmdFlagClear (int nArgs);
- Update_t CmdFlagSet (int nArgs);
+ Update_t CmdFlag (int nArgs);
+ Update_t CmdFlagClear (int nArgs);
+ Update_t CmdFlagSet (int nArgs);
// Memory (Data)
Update_t CmdMemoryCompare (int nArgs);
Update_t CmdMemoryMiniDumpHex (int nArgs);
@@ -672,13 +673,14 @@
Update_t CmdMemoryEnterByte (int nArgs);
Update_t CmdMemoryEnterWord (int nArgs);
Update_t CmdMemoryFill (int nArgs);
+ Update_t CmdNTSC (int nArgs);
Update_t CmdTextSave (int nArgs);
Update_t CmdMemoryLoad (int nArgs);
Update_t CmdMemoryMove (int nArgs);
Update_t CmdMemorySave (int nArgs);
Update_t CmdMemorySearch (int nArgs);
- Update_t _SearchMemoryDisplay (int nArgs=0);
+ Update_t _SearchMemoryDisplay (int nArgs=0); // TODO: CLEANUP
// Update_t CmdMemorySearchLowBit (int nArgs);
// Update_t CmdMemorySearchHiBit (int nArgs);
Update_t CmdMemorySearchAscii (int nArgs);
@@ -691,101 +693,100 @@
Update_t CmdOutputPrintf (int nArgs);
Update_t CmdOutputRun (int nArgs);
// Registers
- Update_t CmdRegisterSet (int nArgs);
+ Update_t CmdRegisterSet (int nArgs);
// Source Level Debugging
- Update_t CmdSource (int nArgs);
- Update_t CmdSync (int nArgs);
+ Update_t CmdSource (int nArgs);
+ Update_t CmdSync (int nArgs);
// Stack
- Update_t CmdStackPush (int nArgs);
- Update_t CmdStackPop (int nArgs);
- Update_t CmdStackPopPseudo (int nArgs);
- Update_t CmdStackReturn (int nArgs);
+ Update_t CmdStackPush (int nArgs);
+ Update_t CmdStackPop (int nArgs);
+ Update_t CmdStackPopPseudo (int nArgs);
+ Update_t CmdStackReturn (int nArgs);
// Symbols
- Update_t CmdSymbols (int nArgs);
- Update_t CmdSymbolsClear (int nArgs);
- Update_t CmdSymbolsList (int nArgs);
- Update_t CmdSymbolsLoad (int nArgs);
- Update_t CmdSymbolsInfo (int nArgs);
- Update_t CmdSymbolsSave (int nArgs);
+ Update_t CmdSymbols (int nArgs);
+ Update_t CmdSymbolsClear (int nArgs);
+ Update_t CmdSymbolsList (int nArgs);
+ Update_t CmdSymbolsLoad (int nArgs);
+ Update_t CmdSymbolsInfo (int nArgs);
+ Update_t CmdSymbolsSave (int nArgs);
- Update_t CmdSymbolsCommand (int nArgs);
-// Update_t CmdSymbolsMain (int nArgs);
-// Update_t CmdSymbolsBasic (int nArgs);
-// Update_t CmdSymbolsUser (int nArgs);
-// Update_t CmdSymbolsAssembly (int nArgs);
-// Update_t CmdSymbolsSource (int nArgs);
+ Update_t CmdSymbolsCommand (int nArgs);
+// Update_t CmdSymbolsMain (int nArgs);
+// Update_t CmdSymbolsBasic (int nArgs);
+// Update_t CmdSymbolsUser (int nArgs);
+// Update_t CmdSymbolsAssembly (int nArgs);
+// Update_t CmdSymbolsSource (int nArgs);
- // View
- Update_t CmdViewOutput_Text4X (int nArgs);
- Update_t CmdViewOutput_Text41 (int nArgs);
- Update_t CmdViewOutput_Text42 (int nArgs);
- Update_t CmdViewOutput_Text8X (int nArgs);
- Update_t CmdViewOutput_Text81 (int nArgs);
- Update_t CmdViewOutput_Text82 (int nArgs);
+// View
+ Update_t CmdViewOutput_Text4X (int nArgs);
+ Update_t CmdViewOutput_Text41 (int nArgs);
+ Update_t CmdViewOutput_Text42 (int nArgs);
+ Update_t CmdViewOutput_Text8X (int nArgs);
+ Update_t CmdViewOutput_Text81 (int nArgs);
+ Update_t CmdViewOutput_Text82 (int nArgs);
- Update_t CmdViewOutput_GRX (int nArgs);
- Update_t CmdViewOutput_GR1 (int nArgs);
- Update_t CmdViewOutput_GR2 (int nArgs);
- Update_t CmdViewOutput_DGRX (int nArgs);
- Update_t CmdViewOutput_DGR1 (int nArgs);
- Update_t CmdViewOutput_DGR2 (int nArgs);
+ Update_t CmdViewOutput_GRX (int nArgs);
+ Update_t CmdViewOutput_GR1 (int nArgs);
+ Update_t CmdViewOutput_GR2 (int nArgs);
+ Update_t CmdViewOutput_DGRX (int nArgs);
+ Update_t CmdViewOutput_DGR1 (int nArgs);
+ Update_t CmdViewOutput_DGR2 (int nArgs);
- Update_t CmdViewOutput_HGRX (int nArgs);
- Update_t CmdViewOutput_HGR1 (int nArgs);
- Update_t CmdViewOutput_HGR2 (int nArgs);
- Update_t CmdViewOutput_DHGRX (int nArgs);
- Update_t CmdViewOutput_DHGR1 (int nArgs);
- Update_t CmdViewOutput_DHGR2 (int nArgs);
+ Update_t CmdViewOutput_HGRX (int nArgs);
+ Update_t CmdViewOutput_HGR1 (int nArgs);
+ Update_t CmdViewOutput_HGR2 (int nArgs);
+ Update_t CmdViewOutput_DHGRX (int nArgs);
+ Update_t CmdViewOutput_DHGR1 (int nArgs);
+ Update_t CmdViewOutput_DHGR2 (int nArgs);
// Watch
- Update_t CmdWatch (int nArgs);
- Update_t CmdWatchAdd (int nArgs);
- Update_t CmdWatchClear (int nArgs);
- Update_t CmdWatchDisable (int nArgs);
- Update_t CmdWatchEnable (int nArgs);
- Update_t CmdWatchList (int nArgs);
-// Update_t CmdWatchLoad (int nArgs);
- Update_t CmdWatchSave (int nArgs);
+ Update_t CmdWatch (int nArgs);
+ Update_t CmdWatchAdd (int nArgs);
+ Update_t CmdWatchClear (int nArgs);
+ Update_t CmdWatchDisable (int nArgs);
+ Update_t CmdWatchEnable (int nArgs);
+ Update_t CmdWatchList (int nArgs);
+// Update_t CmdWatchLoad (int nArgs);
+ Update_t CmdWatchSave (int nArgs);
// Window
- Update_t CmdWindow (int nArgs);
- Update_t CmdWindowCycleNext (int nArgs);
- Update_t CmdWindowCyclePrev (int nArgs);
- Update_t CmdWindowLast (int nArgs);
+ Update_t CmdWindow (int nArgs);
+ Update_t CmdWindowCycleNext (int nArgs);
+ Update_t CmdWindowCyclePrev (int nArgs);
+ Update_t CmdWindowLast (int nArgs);
- Update_t CmdWindowShowCode (int nArgs);
- Update_t CmdWindowShowCode1 (int nArgs);
- Update_t CmdWindowShowCode2 (int nArgs);
- Update_t CmdWindowShowData (int nArgs);
- Update_t CmdWindowShowData1 (int nArgs);
- Update_t CmdWindowShowData2 (int nArgs);
- Update_t CmdWindowShowSymbols1(int nArgs);
- Update_t CmdWindowShowSymbols2(int nArgs);
- Update_t CmdWindowShowSource (int nArgs);
- Update_t CmdWindowShowSource1 (int nArgs);
- Update_t CmdWindowShowSource2 (int nArgs);
+ Update_t CmdWindowShowCode (int nArgs);
+ Update_t CmdWindowShowCode1 (int nArgs);
+ Update_t CmdWindowShowCode2 (int nArgs);
+ Update_t CmdWindowShowData (int nArgs);
+ Update_t CmdWindowShowData1 (int nArgs);
+ Update_t CmdWindowShowData2 (int nArgs);
+ Update_t CmdWindowShowSymbols1 (int nArgs);
+ Update_t CmdWindowShowSymbols2 (int nArgs);
+ Update_t CmdWindowShowSource (int nArgs);
+ Update_t CmdWindowShowSource1 (int nArgs);
+ Update_t CmdWindowShowSource2 (int nArgs);
- Update_t CmdWindowViewCode (int nArgs);
- Update_t CmdWindowViewConsole (int nArgs);
- Update_t CmdWindowViewData (int nArgs);
- Update_t CmdWindowViewOutput (int nArgs);
- Update_t CmdWindowViewSource (int nArgs);
- Update_t CmdWindowViewSymbols (int nArgs);
+ Update_t CmdWindowViewCode (int nArgs);
+ Update_t CmdWindowViewConsole (int nArgs);
+ Update_t CmdWindowViewData (int nArgs);
+ Update_t CmdWindowViewOutput (int nArgs);
+ Update_t CmdWindowViewSource (int nArgs);
+ Update_t CmdWindowViewSymbols (int nArgs);
- Update_t CmdWindowWidthToggle (int nArgs);
-
-// Update_t CmdZeroPageShow (int nArgs);
-// Update_t CmdZeroPageHide (int nArgs);
-// Update_t CmdZeroPageToggle (int nArgs);
+ Update_t CmdWindowWidthToggle (int nArgs);
// ZeroPage
- Update_t CmdZeroPage (int nArgs);
- Update_t CmdZeroPageAdd (int nArgs);
- Update_t CmdZeroPageClear (int nArgs);
- Update_t CmdZeroPageDisable (int nArgs);
- Update_t CmdZeroPageEnable (int nArgs);
- Update_t CmdZeroPageList (int nArgs);
-// Update_t CmdZeroPageLoad (int nArgs);
- Update_t CmdZeroPageSave (int nArgs);
- Update_t CmdZeroPagePointer (int nArgs);
+// Update_t CmdZeroPageShow (int nArgs);
+// Update_t CmdZeroPageHide (int nArgs);
+// Update_t CmdZeroPageToggle (int nArgs);
+ Update_t CmdZeroPage (int nArgs);
+ Update_t CmdZeroPageAdd (int nArgs);
+ Update_t CmdZeroPageClear (int nArgs);
+ Update_t CmdZeroPageDisable (int nArgs);
+ Update_t CmdZeroPageEnable (int nArgs);
+ Update_t CmdZeroPageList (int nArgs);
+// Update_t CmdZeroPageLoad (int nArgs);
+ Update_t CmdZeroPageSave (int nArgs);
+ Update_t CmdZeroPagePointer (int nArgs);
// Cursor _________________________________________________________________________________________
diff --git a/source/DiskImageHelper.cpp b/source/DiskImageHelper.cpp
index c4e8cb26..40bfa214 100644
--- a/source/DiskImageHelper.cpp
+++ b/source/DiskImageHelper.cpp
@@ -1041,7 +1041,9 @@ eDetectResult C2IMGHelper::DetectHdr(LPBYTE& pImage, DWORD& dwImageSize, DWORD&
if (dwImageSize < sizeof(Header2IMG) || pHdr->FormatID != FormatID_2IMG || pHdr->HeaderSize != sizeof(Header2IMG))
return eMismatch;
- if (pHdr->Version != 1)
+ // https://github.com/AppleWin/AppleWin/issues/317
+ // Work around some lazy implementations of the spec that set this value to 0 instead of the correct 1.
+ if (pHdr->Version > 1)
return eMismatch;
if (dwImageSize < sizeof(Header2IMG)+pHdr->DiskDataLength)
diff --git a/source/Frame.cpp b/source/Frame.cpp
index d4d9a49d..7bca77d9 100644
--- a/source/Frame.cpp
+++ b/source/Frame.cpp
@@ -56,6 +56,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Configuration\PropertySheet.h"
#include "Debugger\Debug.h"
+#define DIRECTX_PAGE_FLIP 1
+
//#define ENABLE_MENU 0
// Magic numbers (used by FrameCreateWindow to calc width/height):
@@ -63,10 +65,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define MAGICY 5 // 3D border between Apple window & Title bar
static const int kDEFAULT_VIEWPORT_SCALE = 2;
-static int g_nViewportCX = FRAMEBUFFER_W * kDEFAULT_VIEWPORT_SCALE;
-static int g_nViewportCY = FRAMEBUFFER_H * kDEFAULT_VIEWPORT_SCALE;
+ int g_nViewportCX = FRAMEBUFFER_BORDERLESS_W * kDEFAULT_VIEWPORT_SCALE;
+ int g_nViewportCY = FRAMEBUFFER_BORDERLESS_H * kDEFAULT_VIEWPORT_SCALE;
static int g_nViewportScale = kDEFAULT_VIEWPORT_SCALE; // saved REGSAVE
-static int g_nMaxViewportScale = kDEFAULT_VIEWPORT_SCALE;
+static int g_nMaxViewportScale = kDEFAULT_VIEWPORT_SCALE; // Max scale in Windowed mode with borders, buttons etc (full-screen may be +1)
#define BUTTONX (g_nViewportCX + VIEWPORTX*2)
#define BUTTONY 0
@@ -142,10 +144,14 @@ static int viewporty = VIEWPORTY; // Default to Normal (non-FullScreen
int g_nCharsetType = 0;
// Direct Draw -- For Full Screen
- LPDIRECTDRAW g_pDD = (LPDIRECTDRAW)0;
- LPDIRECTDRAWSURFACE g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0;
- IDirectDrawPalette* g_pDDPal = (IDirectDrawPalette*)0;
-
+ LPDIRECTDRAW g_pDD = (LPDIRECTDRAW)0;
+ LPDIRECTDRAWSURFACE g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0;
+#if DIRECTX_PAGE_FLIP
+ LPDIRECTDRAWSURFACE g_pDDBackSurface = (LPDIRECTDRAWSURFACE)0;
+#endif
+ HDC g_hDDdc = 0;
+ int g_nDDFullScreenW = 640;
+ int g_nDDFullScreenH = 480;
static bool g_bShowingCursor = true;
static bool g_bLastCursorInAppleViewport = false;
@@ -164,6 +170,19 @@ bool g_bScrollLock_FullSpeed = false;
bool g_bFreshReset = false;
static bool g_bFullScreen32Bit = true;
+#if 0 // enable non-integral full-screen scaling
+#define FULLSCREEN_SCALE_TYPE float
+#else
+#define FULLSCREEN_SCALE_TYPE int
+#endif
+
+static RECT g_main_window_saved_rect;
+static int g_main_window_saved_style;
+static int g_main_window_saved_exstyle;
+static FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale = 1;
+static int g_win_fullscreen_offsetx = 0;
+static int g_win_fullscreen_offsety = 0;
+
// __ Prototypes __________________________________________________________________________________
static void DrawCrosshairs (int x, int y);
static void FrameSetCursorPosByMousePos(int x, int y, int dx, int dy, bool bLeavingAppleScreen);
@@ -439,6 +458,8 @@ static void DrawButton (HDC passdc, int number) {
}
//===========================================================================
+
+// NB. x=y=0 means erase only
static void DrawCrosshairs (int x, int y) {
static int lastx = 0;
static int lasty = 0;
@@ -448,6 +469,7 @@ static void DrawCrosshairs (int x, int y) {
// ERASE THE OLD CROSSHAIRS
if (lastx && lasty)
+#if 0
if (g_bIsFullScreen) {
int loop = 4;
while (loop--) {
@@ -461,7 +483,25 @@ static void DrawCrosshairs (int x, int y) {
FillRect(dc,&rect,(HBRUSH)GetStockObject(BLACK_BRUSH));
}
}
- else {
+ else
+#else
+ if (g_bIsFullScreen)
+ {
+ int loop = 4;
+ while (loop--) {
+ RECT rect = {0,0,5,5};
+ switch (loop) {
+ case 0: OffsetRect(&rect, GetFullScreenOffsetX()+lastx-2, GetFullScreenOffsetY()+viewporty-5); break;
+ case 1: OffsetRect(&rect, GetFullScreenOffsetX()+lastx-2, GetFullScreenOffsetY()+viewporty+g_nViewportCY); break;
+ case 2: OffsetRect(&rect, GetFullScreenOffsetX()+viewportx-5, GetFullScreenOffsetY()+lasty-2); break;
+ case 3: OffsetRect(&rect, GetFullScreenOffsetX()+viewportx+g_nViewportCX, GetFullScreenOffsetY()+lasty-2); break;
+ }
+ FillRect(dc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ }
+ }
+ else
+#endif
+ {
int loop = 5;
while (loop--) {
switch (loop) {
@@ -486,21 +526,42 @@ static void DrawCrosshairs (int x, int y) {
// DRAW THE NEW CROSSHAIRS
if (x && y) {
- int loop = 4;
- while (loop--) {
- if ((loop == 1) || (loop == 2))
- SelectObject(dc,GetStockObject(WHITE_PEN));
- else
- SelectObject(dc,GetStockObject(BLACK_PEN));
- LINE(x+loop-2,viewporty-5,
- x+loop-2,viewporty);
- LINE(x+loop-2,viewporty+g_nViewportCY+4,
- x+loop-2,viewporty+g_nViewportCY-1);
- LINE(viewportx-5, y+loop-2,
- viewportx, y+loop-2);
- LINE(viewportx+g_nViewportCX+4,y+loop-2,
- viewportx+g_nViewportCX-1,y+loop-2);
- }
+ if (g_bIsFullScreen)
+ {
+ int loop = 4;
+ while (loop--) {
+ if ((loop == 1) || (loop == 2))
+ SelectObject(dc,GetStockObject(WHITE_PEN));
+ else
+ SelectObject(dc,GetStockObject(BLACK_PEN));
+ LINE(GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty-5,
+ GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty);
+ LINE(GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty+g_nViewportCY+4,
+ GetFullScreenOffsetX()+x+loop-2, GetFullScreenOffsetY()+viewporty+g_nViewportCY-1);
+ LINE(GetFullScreenOffsetX()+viewportx-5, GetFullScreenOffsetY()+y+loop-2,
+ GetFullScreenOffsetX()+viewportx, GetFullScreenOffsetY()+y+loop-2);
+ LINE(GetFullScreenOffsetX()+viewportx+g_nViewportCX+4, GetFullScreenOffsetY()+y+loop-2,
+ GetFullScreenOffsetX()+viewportx+g_nViewportCX-1, GetFullScreenOffsetY()+y+loop-2);
+ }
+ }
+ else
+ {
+ int loop = 4;
+ while (loop--) {
+ if ((loop == 1) || (loop == 2))
+ SelectObject(dc,GetStockObject(WHITE_PEN));
+ else
+ SelectObject(dc,GetStockObject(BLACK_PEN));
+ LINE(x+loop-2,viewporty-5,
+ x+loop-2,viewporty);
+ LINE(x+loop-2,viewporty+g_nViewportCY+4,
+ x+loop-2,viewporty+g_nViewportCY-1);
+ LINE(viewportx-5, y+loop-2,
+ viewportx, y+loop-2);
+ LINE(viewportx+g_nViewportCX+4,y+loop-2,
+ viewportx+g_nViewportCX-1,y+loop-2);
+ }
+ }
}
#undef LINE
lastx = x;
@@ -517,8 +578,6 @@ static void DrawFrameWindow ()
? BeginPaint(g_hFrameWindow,&ps)
: GetDC(g_hFrameWindow));
- VideoRealizePalette(dc);
-
if (!g_bIsFullScreen)
{
// DRAW THE 3D BORDER AROUND THE EMULATED SCREEN
@@ -564,11 +623,9 @@ static void DrawFrameWindow ()
else if (g_nAppMode == MODE_DEBUG)
DebugDisplay(1);
else
- // Win7: In fullscreen mode with 1 redraw, the screen doesn't get redraw.
- // TC: 07/01/2015: Tryed with MP's double-buffered DX full-screen code, but still the same.
- VideoRedrawScreen(g_bIsFullScreen ? 2 : 1); // TC: 22/06/2014: Why 2 redraws in full-screen mode (32-bit only)? (8-bit doesn't need this nor does Win8, just Win7 or older OS's)
+ VideoRedrawScreen(0); // TODO: Presume this is correct with new fullscreen window mode
+ //VideoRedrawScreen(g_bIsFullScreen ? 1 : 0); // On WM_PAINT: delay 1 refresh before rendering full-screen
- // DD Full-Screen Palette: BUGFIX: needs to come _after_ all drawing...
if (g_bPaintingWindow)
EndPaint(g_hFrameWindow,&ps);
else
@@ -907,9 +964,6 @@ static void EraseButton (int number) {
rect.top = buttony+number*BUTTONCY;
rect.bottom = rect.top+BUTTONCY;
- // TODO: DD Full-Screen Palette
- // if( !g_bIsFullScreen )
-
InvalidateRect(g_hFrameWindow,&rect,1);
}
@@ -937,6 +991,8 @@ LRESULT CALLBACK FrameWndProc (
case WM_CLOSE:
LogFileOutput("WM_CLOSE\n");
+ if (g_bIsFullScreen && restart)
+ g_bRestartFullScreen = true;
if (g_bIsFullScreen)
SetNormalMode();
if (!IsIconic(window))
@@ -1183,10 +1239,9 @@ LRESULT CALLBACK FrameWndProc (
DrawStatusArea( (HDC)0, DRAW_TITLE );
VideoReinitialize();
- if ((g_nAppMode != MODE_LOGO) || ((g_nAppMode == MODE_DEBUG) && (g_bDebuggerViewingAppleOutput)))
+ if (g_nAppMode != MODE_LOGO)
{
- VideoRedrawScreen();
- g_bDebuggerViewingAppleOutput = true;
+ VideoRefreshScreen( g_nAppMode == MODE_DEBUG ? g_bDebuggerViewingAppleOutput : 0);
}
Config_Save_Video();
@@ -1490,26 +1545,10 @@ LRESULT CALLBACK FrameWndProc (
// message must not realize its palette, unless it determines that
// wParam does not contain its own window handle.
if ((HWND)wparam == window)
- {
-#if DEBUG_DD_PALETTE
- if( g_bIsFullScreen )
- OutputDebugString( "WM_PALETTECHANGED: Full Screen\n" );
- else
- OutputDebugString( "WM_PALETTECHANGED: Windowed\n" );
-#endif
- break;
- }
+ break;
// else fall through
case WM_QUERYNEWPALETTE:
-#if DEBUG_DD_PALETTE
- if( g_bIsFullScreen )
- OutputDebugString( "WM_QUERYNEWPALETTE: Full Screen\n" );
- else
- OutputDebugString( "WM_QUERYNEWPALETTE: Windowed\n" );
-#endif
-
- // TODO: DD Full-Screen Palette
DrawFrameWindow();
break;
@@ -1578,7 +1617,6 @@ LRESULT CALLBACK FrameWndProc (
OutputDebugString( "WM_SYSCOLORCHANGE: Windowed\n" );
#endif
- // TODO: DD Full-Screen Palette
DeleteGdiObjects();
CreateGdiObjects();
break;
@@ -1738,7 +1776,6 @@ static void ScreenWindowResize(const bool bCtrlKey)
nOldViewportScale = g_nViewportScale;
FrameResizeWindow(1); // reset to 1x
SetFullScreenMode();
- //VideoRedrawScreen(1); // [TC-10/06/2014] Remove this once checked it's not needed by Win8
}
}
@@ -2064,6 +2101,16 @@ void SetFullScreen32Bit(bool b32Bit)
g_bFullScreen32Bit = b32Bit;
}
+int GetFullScreenOffsetX(void)
+{
+ return g_win_fullscreen_offsetx;
+}
+
+int GetFullScreenOffsetY(void)
+{
+ return g_win_fullscreen_offsety;
+}
+
void SetFullScreenMode ()
{
#ifdef NO_DIRECT_X
@@ -2072,31 +2119,78 @@ void SetFullScreenMode ()
#else // NO_DIRECT_X
- g_bIsFullScreen = true;
+ MONITORINFO monitor_info;
+ FULLSCREEN_SCALE_TYPE width, height, scalex, scaley;
+ int top, left;
+
+ const int A2_WINDOW_WIDTH = FRAMEBUFFER_BORDERLESS_W;
+ const int A2_WINDOW_HEIGHT = FRAMEBUFFER_BORDERLESS_H;
+
buttonover = -1;
+#if 0
+ // FS: 640x480
buttonx = FSBUTTONX;
buttony = FSBUTTONY;
viewportx = FSVIEWPORTX;
viewporty = FSVIEWPORTY;
- GetWindowRect(g_hFrameWindow,&framerect);
- SetWindowLong(g_hFrameWindow,GWL_STYLE,WS_POPUP | WS_SYSMENU | WS_VISIBLE);
+#endif
- DDSURFACEDESC ddsd;
- ddsd.dwSize = sizeof(ddsd);
- ddsd.dwFlags = DDSD_CAPS;
- ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
- if (DirectDrawCreate(NULL,&g_pDD,NULL) != DD_OK ||
- g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) != DD_OK ||
- g_pDD->SetDisplayMode(640,480,g_bFullScreen32Bit ? 32 : 8) != DD_OK ||
- g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL) != DD_OK)
- {
- g_pDDPrimarySurface = NULL;
- SetNormalMode();
- return;
- }
+ g_main_window_saved_style = GetWindowLong(g_hFrameWindow, GWL_STYLE);
+ g_main_window_saved_exstyle = GetWindowLong(g_hFrameWindow, GWL_EXSTYLE);
+ GetWindowRect(g_hFrameWindow, &g_main_window_saved_rect);
+ SetWindowLong(g_hFrameWindow, GWL_STYLE, g_main_window_saved_style & ~(WS_CAPTION | WS_THICKFRAME));
+ SetWindowLong(g_hFrameWindow, GWL_EXSTYLE, g_main_window_saved_exstyle & ~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
+
+ monitor_info.cbSize = sizeof(monitor_info);
+ GetMonitorInfo(MonitorFromWindow(g_hFrameWindow, MONITOR_DEFAULTTONEAREST), &monitor_info);
+ left = monitor_info.rcMonitor.left;
+ top = monitor_info.rcMonitor.top;
+ width = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.right - monitor_info.rcMonitor.left);
+ height = (FULLSCREEN_SCALE_TYPE)(monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top);
+ scalex = width / A2_WINDOW_WIDTH;
+ scaley = height / A2_WINDOW_HEIGHT;
+ g_win_fullscreen_scale = (scalex <= scaley) ? scalex : scaley;
+ g_win_fullscreen_offsetx = ((int)width - (int)(g_win_fullscreen_scale * A2_WINDOW_WIDTH)) / 2;
+ g_win_fullscreen_offsety = ((int)height - (int)(g_win_fullscreen_scale * A2_WINDOW_HEIGHT)) / 2;
+ SetWindowPos(g_hFrameWindow, NULL, left, top, (int)width, (int)height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
+ g_bIsFullScreen = true;
- // TODO: DD Full-Screen Palette
- // if( !g_bIsFullScreen )
+#if 1
+ // FS: desktop
+ SetViewportScale(g_win_fullscreen_scale, true);
+
+ buttonx = GetFullScreenOffsetX() + g_nViewportCX + VIEWPORTX*2;
+ buttony = GetFullScreenOffsetY();
+ viewportx = VIEWPORTX;
+ viewporty = VIEWPORTY;
+#endif
+
+ // GetWindowRect(g_hFrameWindow,&framerect);
+// SetWindowLong(g_hFrameWindow,GWL_STYLE,WS_POPUP | WS_SYSMENU | WS_VISIBLE);
+//
+// DDSURFACEDESC ddsd;
+// ddsd.dwSize = sizeof(ddsd);
+// ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
+// ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
+// ddsd.dwBackBufferCount = 1;
+//
+// DDSCAPS ddscaps;
+// ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
+//
+// if ( 0
+// || DD_OK != DirectDrawCreate(NULL,&g_pDD,NULL)
+// || DD_OK != g_pDD->SetCooperativeLevel(g_hFrameWindow,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)
+// || DD_OK != g_pDD->SetDisplayMode(g_nDDFullScreenW,g_nDDFullScreenH,32)
+// || DD_OK != g_pDD->CreateSurface(&ddsd,&g_pDDPrimarySurface,NULL)
+//#if DIRECTX_PAGE_FLIP
+// || DD_OK != g_pDDPrimarySurface->GetAttachedSurface( &ddscaps, &g_pDDBackSurface)
+//#endif
+// )
+// {
+// g_pDDPrimarySurface = NULL;
+// SetNormalMode();
+// return;
+// }
InvalidateRect(g_hFrameWindow,NULL,1);
@@ -2106,39 +2200,44 @@ void SetFullScreenMode ()
//===========================================================================
void SetNormalMode ()
{
- g_bIsFullScreen = false;
+// g_bIsFullScreen = false;
buttonover = -1;
buttonx = BUTTONX;
buttony = BUTTONY;
viewportx = VIEWPORTX;
viewporty = VIEWPORTY;
- g_pDD->RestoreDisplayMode();
- g_pDD->SetCooperativeLevel(NULL,DDSCL_NORMAL);
- SetWindowLong(g_hFrameWindow,GWL_STYLE,
- WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
- WS_VISIBLE);
- SetWindowPos(g_hFrameWindow,0,framerect.left,
- framerect.top,
- framerect.right - framerect.left,
- framerect.bottom - framerect.top,
- SWP_NOZORDER | SWP_FRAMECHANGED);
- // DD Full-Screen Palette: BUGFIX: Re-attach new palette on next new surface
- // Delete Palette
- if (g_pDDPal)
- {
- g_pDDPal->Release();
- g_pDDPal = (LPDIRECTDRAWPALETTE)0;
- }
+ g_win_fullscreen_offsetx = 0;
+ g_win_fullscreen_offsety = 0;
+ g_win_fullscreen_scale = 1;
+ SetWindowLong(g_hFrameWindow, GWL_STYLE, g_main_window_saved_style);
+ SetWindowLong(g_hFrameWindow, GWL_EXSTYLE, g_main_window_saved_exstyle);
+ SetWindowPos(g_hFrameWindow, NULL,
+ g_main_window_saved_rect.left,
+ g_main_window_saved_rect.top,
+ g_main_window_saved_rect.right - g_main_window_saved_rect.left,
+ g_main_window_saved_rect.bottom - g_main_window_saved_rect.top,
+ SWP_SHOWWINDOW);
+ g_bIsFullScreen = false;
- if (g_pDDPrimarySurface)
- {
- g_pDDPrimarySurface->Release();
- g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0;
- }
+ //g_pDD->RestoreDisplayMode();
+ //g_pDD->SetCooperativeLevel(NULL,DDSCL_NORMAL);
+ //SetWindowLong(g_hFrameWindow,GWL_STYLE,
+ // WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
+ // WS_VISIBLE);
+ //SetWindowPos(g_hFrameWindow,0,framerect.left,
+ // framerect.top,
+ // framerect.right - framerect.left,
+ // framerect.bottom - framerect.top,
+ // SWP_NOZORDER | SWP_FRAMECHANGED);
+ //if (g_pDDPrimarySurface)
+ //{
+ // g_pDDPrimarySurface->Release();
+ // g_pDDPrimarySurface = (LPDIRECTDRAWSURFACE)0;
+ //}
- g_pDD->Release();
- g_pDD = (LPDIRECTDRAW)0;
+ //g_pDD->Release();
+ //g_pDD = (LPDIRECTDRAW)0;
}
//===========================================================================
@@ -2178,14 +2277,14 @@ int GetViewportScale(void)
return g_nViewportScale;
}
-int SetViewportScale(int nNewScale)
+int SetViewportScale(int nNewScale, bool bForce /*=false*/)
{
- if (nNewScale > g_nMaxViewportScale)
+ if (!bForce && nNewScale > g_nMaxViewportScale)
nNewScale = g_nMaxViewportScale;
g_nViewportScale = nNewScale;
- g_nViewportCX = g_nViewportScale * FRAMEBUFFER_W;
- g_nViewportCY = g_nViewportScale * FRAMEBUFFER_H;
+ g_nViewportCX = g_nViewportScale * FRAMEBUFFER_BORDERLESS_W;
+ g_nViewportCY = g_nViewportScale * FRAMEBUFFER_BORDERLESS_H;
return nNewScale;
}
@@ -2284,8 +2383,8 @@ void FrameCreateWindow(void)
int nOldViewportCX = g_nViewportCX;
int nOldViewportCY = g_nViewportCY;
- g_nViewportCX = FRAMEBUFFER_W * 2;
- g_nViewportCY = FRAMEBUFFER_H * 2;
+ g_nViewportCX = FRAMEBUFFER_BORDERLESS_W * 2;
+ g_nViewportCY = FRAMEBUFFER_BORDERLESS_H * 2;
GetWidthHeight(nWidth, nHeight); // Probe with 2x dimensions
g_nViewportCX = nOldViewportCX;
@@ -2376,14 +2475,22 @@ HDC FrameGetDC () {
//===========================================================================
HDC FrameGetVideoDC (LPBYTE *pAddr_, LONG *pPitch_)
{
+ HDC hDC = 0;
+
// ASSERT( pAddr_ );
// ASSERT( pPitch_ );
- if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow)
+ if (false) // TODO: ...
+ //if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow)
{
- RECT rect = { FSVIEWPORTX,
- FSVIEWPORTY,
- FSVIEWPORTX+g_nViewportCX,
- FSVIEWPORTY+g_nViewportCY};
+ // Reference: http://archive.gamedev.net/archive/reference/articles/article608.html
+ // NTSC TODO: Are these coordinates correct?? Coordinates don't seem to matter on Win7 fullscreen!?
+ // g_nViewportCX = FRAMEBUFFER_W * kDEFAULT_VIEWPORT_SCALE;
+ RECT rect = {
+ FSVIEWPORTX,
+ FSVIEWPORTY,
+ FSVIEWPORTX+g_nViewportCX,
+ FSVIEWPORTY+g_nViewportCY
+ };
DDSURFACEDESC surfacedesc;
surfacedesc.dwSize = sizeof(surfacedesc);
// TC: Use DDLOCK_WAIT - see Bug #13425
@@ -2391,23 +2498,23 @@ HDC FrameGetVideoDC (LPBYTE *pAddr_, LONG *pPitch_)
{
g_pDDPrimarySurface->Restore();
g_pDDPrimarySurface->Lock(&rect,&surfacedesc,DDLOCK_WAIT,NULL);
-
- // DD Full Screen Palette
-// if (g_pDDPal)
-// {
-// g_pDDPrimarySurface->SetPalette(g_pDDPal); // this sets the palette for the primary surface
-// }
}
*pAddr_ = (LPBYTE)surfacedesc.lpSurface + (g_nViewportCY-1) * surfacedesc.lPitch;
*pPitch_ = -surfacedesc.lPitch;
- return (HDC)0;
+
+ if( g_pDDPrimarySurface->GetDC( &hDC ) == DD_OK )
+ g_hDDdc = hDC; // intentional "null" copy
+ else
+ hDC = 0;
}
else
{
*pAddr_ = g_pFramebufferbits;
*pPitch_ = FRAMEBUFFER_W;
- return FrameGetDC();
+ hDC = FrameGetDC();
}
+
+ return hDC;
}
//===========================================================================
@@ -2449,7 +2556,8 @@ void FrameReleaseDC () {
//===========================================================================
void FrameReleaseVideoDC ()
{
- if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow)
+ if (false) // TODO: ...
+ //if (g_bIsFullScreen && g_bAppActive && !g_bPaintingWindow)
{
// THIS IS CORRECT ACCORDING TO THE DIRECTDRAW DOCS
RECT rect = {
@@ -2458,10 +2566,19 @@ void FrameReleaseVideoDC ()
FSVIEWPORTX+g_nViewportCX,
FSVIEWPORTY+g_nViewportCY
};
+
+ //g_pDDBackSurface->BltFast( 0, 0, g_pDDPrimarySurface, &rcRect,DDBLTFAST_NOCOLORKEY | DDBLTFAST_WAIT);
+#if DIRECTX_PAGE_FLIP
+ g_pDDBackSurface->Flip( g_pDDPrimarySurface, 0 );
+#endif
+
g_pDDPrimarySurface->Unlock(&rect);
// BUT THIS SEEMS TO BE WORKING
g_pDDPrimarySurface->Unlock(NULL);
+
+ g_pDDPrimarySurface->ReleaseDC( g_hDDdc ); // NTSC Full Screen
+ g_hDDdc = 0;
}
}
diff --git a/source/Frame.h b/source/Frame.h
index e9149f78..2c68c879 100644
--- a/source/Frame.h
+++ b/source/Frame.h
@@ -11,27 +11,47 @@
#define VIEWPORTY 5
// 560 = Double Hi-Res
- // 384 = Doule Scan Line
- #define FRAMEBUFFER_W 560
- #define FRAMEBUFFER_H 384
+ // 384 = Double Scan Line
+ #define FRAMEBUFFER_BORDERLESS_W 560
+ #define FRAMEBUFFER_BORDERLESS_H 384
+// NTSC_BEGIN
+#if 0
+ // TC: No good as NTSC render code writes to border area:
+ // . NTSC.cpp: updateVideoScannerHorzEOL(): "NOTE: This writes out-of-bounds for a 560x384 framebuffer"
+ #define BORDER_W 0
+ #define BORDER_H 0
+ #define FRAMEBUFFER_W FRAMEBUFFER_BORDERLESS_W
+ #define FRAMEBUFFER_H FRAMEBUFFER_BORDERLESS_H
+#else
+ #define BORDER_W 20
+ #define BORDER_H 18
+ #define FRAMEBUFFER_W (FRAMEBUFFER_BORDERLESS_W + BORDER_W*2)
+ #define FRAMEBUFFER_H (FRAMEBUFFER_BORDERLESS_H + BORDER_H*2)
+#endif
+// NTSC_END
// Direct Draw -- For Full Screen
extern LPDIRECTDRAW g_pDD;
extern LPDIRECTDRAWSURFACE g_pDDPrimarySurface;
- extern IDirectDrawPalette* g_pDDPal;
+ extern int g_nDDFullScreenW;
+ extern int g_nDDFullScreenH;
// Win32
extern HWND g_hFrameWindow;
extern BOOL g_bIsFullScreen;
+ extern int g_nViewportCX;
+ extern int g_nViewportCY;
extern BOOL g_bConfirmReboot; // saved PageConfig REGSAVE
extern BOOL g_bMultiMon;
+
// Emulator
extern bool g_bFreshReset;
extern std::string PathFilename[2];
extern bool g_bScrollLock_FullSpeed;
extern int g_nCharsetType;
+
// Prototypes
void CtrlReset();
@@ -44,7 +64,7 @@
void FrameReleaseVideoDC ();
void FrameSetCursorPosByMousePos();
int GetViewportScale(void);
- int SetViewportScale(int nNewScale);
+ int SetViewportScale(int nNewScale, bool bForce = false);
void GetViewportCXCY(int& nViewportCX, int& nViewportCY);
bool GetFullScreen32Bit(void);
void SetFullScreen32Bit(bool b32Bit);
@@ -59,3 +79,5 @@
WPARAM wparam,
LPARAM lparam );
+ int GetFullScreenOffsetX(void);
+ int GetFullScreenOffsetY(void);
diff --git a/source/Memory.cpp b/source/Memory.cpp
index 4cf056cf..5d2bcd18 100644
--- a/source/Memory.cpp
+++ b/source/Memory.cpp
@@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Memory.h"
#include "Mockingboard.h"
#include "MouseInterface.h"
+#include "NTSC.h"
#include "NoSlotClock.h"
#include "ParallelPrinter.h"
#include "Registry.h"
@@ -234,7 +235,7 @@ static BYTE __stdcall IORead_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG
case 0x6: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft);
case 0x7: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft);
case 0x8: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft);
- case 0x9: return VideoCheckVbl(pc, addr, bWrite, d, nCyclesLeft);
+ case 0x9: return VideoCheckVbl(nCyclesLeft);
case 0xA: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft);
case 0xB: return VideoCheckMode(pc, addr, bWrite, d, nCyclesLeft);
case 0xC: return MemCheckPaging(pc, addr, bWrite, d, nCyclesLeft);
@@ -1495,13 +1496,35 @@ void MemReset()
BYTE MemReadFloatingBus(const ULONG uExecutedCycles)
{
- return*(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles));
+#if 0
+ // NTSC: It is tempting to replace with
+ // return NTSC_VideoGetScannerAddress( uExecutedCycles );
+ // But that breaks "Rainbow" Bug #254 if NTSC_VideoGetScannerAddress() is not correct.
+ // This is out of sync with VideoGetScannerAddress() due to two reasons:
+ // a) returning a cached copy of g_aHorzClockMemAddress
+ // Fixed by calling: updateVideoScannerAddressTXT or updateVideoScannerAddressHGR()
+ // b) A bug? in APPLE_IIE_HORZ_CLOCK_OFFSET[0][8] containing the incorrect value of 0x006F
+ uint16_t addr1 = NTSC_VideoGetScannerAddress( uExecutedCycles );
+ uint16_t addr2 = VideoGetScannerAddress(NULL, uExecutedCycles);
+ uint8_t byte1 = mem[ addr1 ];
+ uint8_t byte2 = mem[ addr2 ];
+
+ if( byte1 != byte2 )
+ mem[ 0x2000 ] ^= 0xFF;
+#endif
+ // return mem[ VideoGetScannerAddress(NULL, uExecutedCycles) ];
+ uint16_t addr = NTSC_VideoGetScannerAddress( uExecutedCycles );
+ return mem[ addr ] ; // cycles is ignored
}
//===========================================================================
BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles)
{
+ // NTSC: It is tempting to replace with
+ // return NTSC_VideoGetScannerAddress( uExecutedCycles );
+ // But that breaks "Rainbow" Bug #254
+ // BYTE r= NTSC_VideoGetByte( uExecutedCycles );
BYTE r = *(LPBYTE)(mem + VideoGetScannerAddress(NULL, uExecutedCycles));
return (r & ~0x80) | ((highbit) ? 0x80 : 0);
}
diff --git a/source/Mockingboard.cpp b/source/Mockingboard.cpp
index 0143f8e9..8a92e6d1 100644
--- a/source/Mockingboard.cpp
+++ b/source/Mockingboard.cpp
@@ -741,7 +741,7 @@ static void Votrax_Write(BYTE nDevice, BYTE nValue)
static void MB_Update()
{
- char szDbg[200];
+ //char szDbg[200];
if (!MockingboardVoice.bActive)
return;
@@ -828,9 +828,9 @@ static void MB_Update()
if((dwByteOffset > dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor))
{
double fTicksSecs = (double)GetTickCount() / 1000.0;
- sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
- OutputDebugString(szDbg);
- if (g_fh) fprintf(g_fh, "%s", szDbg);
+ //sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
+ //OutputDebugString(szDbg);
+ //if (g_fh) fprintf(g_fh, "%s", szDbg);
dwByteOffset = dwCurrentWriteCursor;
}
@@ -841,9 +841,9 @@ static void MB_Update()
if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor))
{
double fTicksSecs = (double)GetTickCount() / 1000.0;
- sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
- OutputDebugString(szDbg);
- if (g_fh) fprintf(g_fh, "%s", szDbg);
+ //sprintf(szDbg, "%010.3f: [MBUpdt] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
+ //OutputDebugString(szDbg);
+ //if (g_fh) fprintf(g_fh, "%s", szDbg);
dwByteOffset = dwCurrentWriteCursor;
}
diff --git a/source/NTSC.cpp b/source/NTSC.cpp
new file mode 100644
index 00000000..09c19f9d
--- /dev/null
+++ b/source/NTSC.cpp
@@ -0,0 +1,1776 @@
+/*
+AppleWin : An Apple //e emulator for Windows
+
+Copyright (C) 2010-2011, William S Simms
+Copyright (C) 2014-2016, Michael Pohoreski, Tom Charlesworth
+
+AppleWin is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+AppleWin is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with AppleWin; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+// Includes
+ #include "StdAfx.h"
+ #include "AppleWin.h"
+ #include "CPU.h"
+ #include "Frame.h" // FRAMEBUFFER_W FRAMEBUFFER_H
+ #include "Memory.h" // MemGetMainPtr() MemGetBankPtr()
+ #include "Video.h" // g_pFramebufferbits
+
+ #include "NTSC.h"
+ #include "NTSC_CharSet.h"
+
+#define NTSC_REMOVE_WHITE_RINGING 1 // 0 = theoritical dimmed white has chroma, 1 = pure white without chroma tinting
+#define NTSC_REMOVE_BLACK_GHOSTING 1 // 1 = remove black smear/smudges carrying over
+
+#define DEBUG_PHASE_ZERO 0
+
+#define ALT_TABLE 0
+#if ALT_TABLE
+ #include "ntsc_rgb.h"
+#endif
+
+ //LPBYTE MemGetMainPtr(const WORD);
+ //LPBYTE MemGetBankPtr(const UINT nBank);
+
+// Defines
+ #define HGR_TEST_PATTERN 0
+
+#ifdef _MSC_VER
+ #define INLINE __forceinline
+#else
+ #define INLINE inline
+#endif
+
+ #define PI 3.1415926535898f
+ #define DEG_TO_RAD(x) (PI*(x)/180.f) // 2PI=360, PI=180,PI/2=90,PI/4=45
+ #define RAD_45 PI*0.25f
+ #define RAD_90 PI*0.5f
+ #define RAD_360 PI*2.f
+
+ // sadly float64 precision is needed
+ #define real double
+
+ //#define CYCLESTART (PI/4.f) // PI/4 = 45 degrees
+ #define CYCLESTART (DEG_TO_RAD(45))
+
+// Types
+
+ struct ColorSpace_PAL_t // Phase Amplitute Luma
+ {
+ float phase;
+ float amp;
+ float luma;
+ };
+
+ struct ColorSpace_YIQ_t
+ {
+ float y, i, q;
+ };
+
+ struct rgba_t
+ {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+ };
+
+ struct ColorSpace_BGRA_t
+ {
+ union
+ {
+ uint32_t n;
+ bgra_t bgra;
+ rgba_t rgba;
+ };
+ };
+
+
+// Globals (Public) ___________________________________________________
+ uint16_t g_nVideoClockVert = 0; // 9-bit: VC VB VA V5 V4 V3 V2 V1 V0 = 0 .. 262
+ uint16_t g_nVideoClockHorz = 0; // 6-bit: H5 H4 H3 H2 H1 H0 = 0 .. 64, 25 >= visible (NB. final hpos is 2 cycles long, so a line is 65 cycles)
+
+// Globals (Private) __________________________________________________
+ static int g_nVideoCharSet = 0;
+ static int g_nVideoMixed = 0;
+ static int g_nHiresPage = 1;
+ static int g_nTextPage = 1;
+
+ // Understanding the Apple II, Timing Generation and the Video Scanner, Pg 3-11
+ // Vertical Scanning
+ // Horizontal Scanning
+ // "There are exactly 17030 (65 x 262) 6502 cycles in every television scan of an American Apple."
+ #define VIDEO_SCANNER_MAX_HORZ 65 // TODO: use Video.cpp: kHClocks
+ #define VIDEO_SCANNER_MAX_VERT 262 // TODO: use Video.cpp: kNTSCScanLines
+
+ #define VIDEO_SCANNER_HORZ_COLORBURST_BEG 12
+ #define VIDEO_SCANNER_HORZ_COLORBURST_END 16
+
+ #define VIDEO_SCANNER_HORZ_START 25 // first displayable horz scanner index
+ #define VIDEO_SCANNER_Y_MIXED 160 // num scanlins for mixed graphics + text
+ #define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines
+
+ static uint16_t g_aHorzClockMemAddress[VIDEO_SCANNER_MAX_HORZ];
+
+ static bgra_t *g_pVideoAddress = 0;
+ static bgra_t *g_pScanLines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384
+
+ static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0;
+
+ typedef void (*UpdateScreenFunc_t)(long);
+ static UpdateScreenFunc_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY];
+ static UpdateScreenFunc_t g_pFuncUpdateTextScreen = 0; // updateScreenText40;
+ static UpdateScreenFunc_t g_pFuncUpdateGraphicsScreen = 0; // updateScreenText40;
+ static UpdateScreenFunc_t g_pFuncModeSwitchDelayed = 0;
+
+ static UpdateScreenFunc_t g_aFuncUpdateHorz [VIDEO_SCANNER_MAX_HORZ]; // ANSI STORY: DGR80/TEXT80 vert/horz scrolll switches video mode mid-scan line!
+ static uint32_t g_aHorzClockVideoMode [VIDEO_SCANNER_MAX_HORZ]; // ANSI STORY: DGR80/TEXT80 vert/horz scrolll switches video mode mid-scan line!
+
+ typedef void (*UpdatePixelFunc_t)(uint16_t);
+ static UpdatePixelFunc_t g_pFuncUpdateBnWPixel = 0; //updatePixelBnWMonitorSingleScanline;
+ static UpdatePixelFunc_t g_pFuncUpdateHuePixel = 0; //updatePixelHueMonitorSingleScanline;
+
+ static uint8_t g_nTextFlashCounter = 0;
+ static uint16_t g_nTextFlashMask = 0;
+
+ static unsigned g_aPixelMaskGR [ 16];
+ static uint16_t g_aPixelDoubleMaskHGR[128]; // hgrbits -> g_aPixelDoubleMaskHGR: 7-bit mono 280 pixels to 560 pixel doubling
+
+ static int g_nLastColumnPixelNTSC;
+ static int g_nColorBurstPixels;
+
+ #define INITIAL_COLOR_PHASE 0
+ static int g_nColorPhaseNTSC = INITIAL_COLOR_PHASE;
+ static int g_nSignalBitsNTSC = 0;
+
+ #define NTSC_NUM_PHASES 4
+ #define NTSC_NUM_SEQUENCES 4096
+
+ const uint32_t ALPHA32_MASK = 0xFF000000; // Win32: aarrggbb
+
+/*extern*/ uint32_t g_nChromaSize = 0; // for NTSC_VideoGetChromaTable()
+ static bgra_t g_aBnWMonitor [NTSC_NUM_SEQUENCES];
+ static bgra_t g_aHueMonitor[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES];
+ static bgra_t g_aBnwColorTV [NTSC_NUM_SEQUENCES];
+ static bgra_t g_aHueColorTV[NTSC_NUM_PHASES][NTSC_NUM_SEQUENCES];
+
+ // g_aBnWMonitor * g_nMonochromeRGB -> g_aBnWMonitorCustom
+ // g_aBnwColorTV * g_nMonochromeRGB -> g_aBnWColorTVCustom
+ static bgra_t g_aBnWMonitorCustom [NTSC_NUM_SEQUENCES];
+ static bgra_t g_aBnWColorTVCustom [NTSC_NUM_SEQUENCES];
+
+ #define CHROMA_ZEROS 2
+ #define CHROMA_POLES 2
+ #define CHROMA_GAIN 7.438011255f // Should this be 7.15909 MHz ?
+ #define CHROMA_0 -0.7318893645f
+ #define CHROMA_1 1.2336442711f
+
+ //#define LUMGAIN 1.062635655e+01
+ //#define LUMCOEF1 -0.3412038399
+ //#define LUMCOEF2 0.9647813115
+ #define LUMA_ZEROS 2
+ #define LUMA_POLES 2
+ #define LUMA_GAIN 13.71331570f // Should this be 14.318180 MHz ?
+ #define LUMA_0 -0.3961075449f
+ #define LUMA_1 1.1044202472f
+
+ #define SIGNAL_ZEROS 2
+ #define SIGNAL_POLES 2
+ #define SIGNAL_GAIN 7.614490548f // Should this be 7.15909 MHz ?
+ #define SIGNAL_0 -0.2718798058f
+ #define SIGNAL_1 0.7465656072f
+
+// Tables
+ static unsigned g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] =
+ {
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
+ 0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
+ 0x0200,0x0600,0x0A00,0x0E00,0x1200,0x1600,0x1A00,0x1E00,0x0280,0x0680,0x0A80,0x0E80,0x1280,0x1680,0x1A80,0x1E80,
+ 0x0300,0x0700,0x0B00,0x0F00,0x1300,0x1700,0x1B00,0x1F00,0x0380,0x0780,0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80,
+
+ 0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80
+ };
+
+ static unsigned g_aClockVertOffsetsTXT[33] =
+ {
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
+ 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
+
+ 0x380
+ };
+
+ static unsigned APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
+ {
+ {0x1068,0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x1078,0x1079,0x107A,0x107B,0x107C,0x107D,0x107E,0x107F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027},
+
+ {0x1010,0x1010,0x1011,0x1012,0x1013,0x1014,0x1015,0x1016,0x1017,
+ 0x1018,0x1019,0x101A,0x101B,0x101C,0x101D,0x101E,0x101F,
+ 0x1020,0x1021,0x1022,0x1023,0x1024,0x1025,0x1026,0x1027,
+ 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F},
+
+ {0x1038,0x1038,0x1039,0x103A,0x103B,0x103C,0x103D,0x103E,0x103F,
+ 0x1040,0x1041,0x1042,0x1043,0x1044,0x1045,0x1046,0x1047,
+ 0x1048,0x1049,0x104A,0x104B,0x104C,0x104D,0x104E,0x104F,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077},
+
+ {0x1060,0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
+ 0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F},
+
+ {0x1060,0x1060,0x1061,0x1062,0x1063,0x1064,0x1065,0x1066,0x1067,
+ 0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F,
+ 0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}
+ };
+
+ static unsigned APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
+ {
+ {0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F, // bug? 0x106F
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027},
+
+ {0x0010,0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+ 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F},
+
+ {0x0038,0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077},
+
+ {0x0060,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F},
+
+ {0x0060,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}
+ };
+
+ /*
+ http://www.kreativekorp.com/miscpages/a2info/munafo.shtml
+
+ "Primary" lo-res colors
+ Color GR Duty cycle Phase
+ ======================================
+ Red COLOR=1 45 to 135 90
+ Dark-blue COLOR=2 315 to 45 0
+ Dark-green COLOR=4 225 to 315 270
+ Brown COLOR=8 135 to 225 180
+ */
+ ColorSpace_PAL_t aPaletteYIQ[ 16 ] =
+ { // Lo Hi Dh
+ { 0, 0, 0 } // 0 0 Black
+ ,{ 90, 60, 25 } // 1 1 Red
+ ,{ 0, 60, 25 } // 2 8 Dark Blue
+ ,{ 45,100, 50 } // 3 2 9 Purple
+ ,{270, 60, 25 } // 4 Dark Green
+ ,{ 0, 0, 50 } // 5 Grey
+ ,{315,100, 50 } // 6 Medium Blue
+ ,{ 0, 60, 75 } // 7 Light Blue
+ ,{180, 60, 25 } // 8 Brown
+ ,{135,100, 50 } // 9 Orange
+ ,{ 0, 0, 50 } // 10
+ ,{ 90, 60, 75 } // 11 Pink
+ ,{225,100, 50 } // 12 Light Green
+ ,{180, 60, 75 } // 13 Yellow
+ ,{270, 60, 75} // 14 Aqua
+ ,{ 0, 0,100 } // 15 White
+ };
+
+// purple HCOLOR=2 45 100 50 255 68 253
+// orange HCOLOR=5 135 100 50 255 106 60
+// green HCOLOR=1 225 100 50 20 245 60
+// blue HCOLOR=6 315 100 50 20 207 253
+
+ rgba_t aPaletteRGB[ 16 ] =
+ {
+ { 0, 0, 0 } // 0
+ ,{ 227, 30, 96 } // 1
+ ,{ 96, 78, 189 } // 2
+ ,{ 255, 68, 253 } // 3
+ ,{ 0, 163, 96 } // 4
+ ,{ 156, 156, 156 } // 5
+ ,{ 20, 207, 253 } // 6
+ ,{ 208, 195, 255 } // 7
+ ,{ 96, 114, 3 } // 8
+ ,{ 255, 106, 60 } // 9
+ ,{ 156, 156, 156 } // 10
+ ,{ 255, 160, 208 } // 11
+ ,{ 20, 245, 60 } // 12
+ ,{ 208, 221, 141 } // 13
+ ,{ 114, 255, 208 } // 14
+ ,{ 255, 255, 255 } // 15
+ };
+
+ static csbits_t csbits; // charset, optionally followed by alt charset
+
+// Prototypes
+ // prototype from CPU.h
+ //unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles);
+ // prototypes from Memory.h
+ //unsigned char * MemGetAuxPtr (unsigned short);
+ //unsigned char * MemGetMainPtr (unsigned short);
+ INLINE float clampZeroOne( const float & x );
+ INLINE uint8_t getCharSetBits( const int iChar );
+ INLINE uint16_t getLoResBits( uint8_t iByte );
+ INLINE uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable );
+ INLINE uint32_t* getScanlineNext1Address();
+ INLINE uint32_t* getScanlinePrev1Address();
+ INLINE uint32_t* getScanlinePrev2Address();
+ INLINE uint32_t* getScanlineThis0Address();
+ INLINE void updateColorPhase();
+ INLINE void updateFlashRate();
+ INLINE void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable );
+ INLINE void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable );
+ INLINE void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable );
+ INLINE void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable );
+ INLINE void updatePixels( uint16_t bits );
+ INLINE bool updateScanLineModeSwitch( long cycles6502, UpdateScreenFunc_t self );
+ INLINE void updateVideoScannerHorzEOL();
+ INLINE void updateVideoScannerAddress();
+ INLINE uint16_t updateVideoScannerAddressTXT();
+ INLINE uint16_t updateVideoScannerAddressHGR();
+
+ static void initChromaPhaseTables();
+ static real initFilterChroma (real z);
+ static real initFilterLuma0 (real z);
+ static real initFilterLuma1 (real z);
+ static real initFilterSignal(real z);
+ static void initPixelDoubleMasks(void);
+ static void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b );
+
+ static void updatePixelBnWColorTVSingleScanline( uint16_t compositeSignal );
+ static void updatePixelBnWColorTVDoubleScanline( uint16_t compositeSignal );
+ static void updatePixelBnWMonitorSingleScanline( uint16_t compositeSignal );
+ static void updatePixelBnWMonitorDoubleScanline( uint16_t compositeSignal );
+ static void updatePixelHueColorTVSingleScanline( uint16_t compositeSignal );
+ static void updatePixelHueColorTVDoubleScanline( uint16_t compositeSignal );
+ static void updatePixelHueMonitorSingleScanline( uint16_t compositeSignal );
+ static void updatePixelHueMonitorDoubleScanline( uint16_t compositeSignal );
+
+ static void updateScreenDoubleHires40( long cycles6502 );
+ static void updateScreenDoubleHires80( long cycles6502 );
+ static void updateScreenDoubleLores40( long cycles6502 );
+ static void updateScreenDoubleLores80( long cycles6502 );
+ static void updateScreenSingleHires40( long cycles6502 );
+ static void updateScreenSingleLores40( long cycles6502 );
+ static void updateScreenText40 ( long cycles6502 );
+ static void updateScreenText80 ( long cycles6502 );
+
+//===========================================================================
+static void set_csbits()
+{
+ // NB. For models that don't have an alt charset then set /g_nVideoCharSet/ to zero
+ switch ( GetApple2Type() )
+ {
+ 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 = &csbits_enhanced2e[0]; 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
+ default: csbits = &csbits_enhanced2e[0]; break;
+ }
+}
+
+//===========================================================================
+inline float clampZeroOne( const float & x )
+{
+ if (x < 0.f) return 0.f;
+ if (x > 1.f) return 1.f;
+ /* ...... */ return x;
+}
+
+//===========================================================================
+inline uint8_t getCharSetBits(int iChar)
+{
+ return csbits[g_nVideoCharSet][iChar][g_nVideoClockVert & 7];
+}
+
+//===========================================================================
+inline uint16_t getLoResBits( uint8_t iByte )
+{
+ return g_aPixelMaskGR[ (iByte >> (g_nVideoClockVert & 4)) & 0xF ];
+}
+
+//===========================================================================
+inline uint32_t getScanlineColor( const uint16_t signal, const bgra_t *pTable )
+{
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; // 14-bit
+ return *(uint32_t*) &pTable[ g_nSignalBitsNTSC ];
+}
+
+//===========================================================================
+inline uint32_t* getScanlineNext1Address()
+{
+ return (uint32_t*) (g_pVideoAddress - 1*FRAMEBUFFER_W);
+}
+
+//===========================================================================
+inline uint32_t* getScanlinePrev1Address()
+{
+ return (uint32_t*) (g_pVideoAddress + 1*FRAMEBUFFER_W);
+}
+
+//===========================================================================
+inline uint32_t* getScanlinePrev2Address()
+{
+ return (uint32_t*) (g_pVideoAddress + 2*FRAMEBUFFER_W);
+}
+
+//===========================================================================
+inline uint32_t* getScanlineThis0Address()
+{
+ return (uint32_t*) g_pVideoAddress;
+}
+
+//===========================================================================
+inline void updateColorPhase()
+{
+ g_nColorPhaseNTSC++;
+ g_nColorPhaseNTSC &= 3;
+}
+
+//===========================================================================
+inline void updateFlashRate() // TODO: Flash rate should be constant (regardless of CPU speed)
+{
+ // BUG: In unthrottled CPU mode, flash rate should not be affected
+
+ // Flash rate:
+ // . NTSC : 60/16 ~= 4Hz
+ // . PAL : 50/16 ~= 3Hz
+ if ((++g_nTextFlashCounter & 0xF) == 0)
+ g_nTextFlashMask ^= -1; // 16-bits
+
+ // The old way to handle flashing was
+ // if ((SW_TEXT || SW_MIXED) ) // && !SW_80COL) // FIX: FLASH 80-Column
+ // g_nTextFlashMask = true;
+ // The new way is to check the active char set, inlined:
+ // if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) // Flash only if mousetext not active
+}
+
+#if 0
+#define updateFramebufferMonitorSingleScanline(signal,table) \
+ do { \
+ uint32_t *cp, *mp; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ cp = (uint32_t*) &table[g_nSignalBitsNTSC]; \
+ *(uint32_t*)g_pVideoAddress = *cp; \
+ mp = (uint32_t*)(g_pVideoAddress - FRAMEBUFFER_W); \
+ *mp = ((*cp & 0x00fcfcfc) >> 2) | ALPHA32_MASK; \
+ g_pVideoAddress++; \
+ } while(0)
+
+// prevp is never used nor blended with!
+#define updateFramebufferColorTVSingleScanline(signal,table) \
+ do { \
+ uint32_t ntscp, prevp, betwp; \
+ uint32_t *prevlin, *between; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ prevlin = (uint32_t*)(g_pVideoAddress + 2*FRAMEBUFFER_W); \
+ between = (uint32_t*)(g_pVideoAddress + 1*FRAMEBUFFER_W); \
+ ntscp = *(uint32_t*) &table[g_nSignalBitsNTSC]; /* raw current NTSC color */ \
+ prevp = *prevlin; \
+ betwp = ntscp - ((ntscp & 0x00fcfcfc) >> 2); \
+ *between = betwp | ALPHA32_MASK; \
+ *(uint32_t*)g_pVideoAddress = ntscp; \
+ g_pVideoAddress++; \
+ } while(0)
+
+#define updateFramebufferMonitorDoubleScanline(signal,table) \
+ do { \
+ uint32_t *cp, *mp; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ cp = (uint32_t*) &table[g_nSignalBitsNTSC]; \
+ mp = (uint32_t*)(g_pVideoAddress - FRAMEBUFFER_W); \
+ *(uint32_t*)g_pVideoAddress = *mp = *cp; \
+ g_pVideoAddress++; \
+ } while(0)
+
+#define updateFramebufferColorTVDoubleScanline(signal,table) \
+ do { \
+ uint32_t ntscp, prevp, betwp; \
+ uint32_t *prevlin, *between; \
+ g_nSignalBitsNTSC = ((g_nSignalBitsNTSC << 1) | signal) & 0xFFF; \
+ prevlin = (uint32_t*)(g_pVideoAddress + 2*FRAMEBUFFER_W); \
+ between = (uint32_t*)(g_pVideoAddress + 1*FRAMEBUFFER_W); \
+ ntscp = *(uint32_t*) &table[g_nSignalBitsNTSC]; /* raw current NTSC color */ \
+ prevp = *prevlin; \
+ betwp = ((ntscp & 0x00fefefe) >> 1) + ((prevp & 0x00fefefe) >> 1); \
+ *between = betwp | ALPHA32_MASK; \
+ *(uint32_t*)g_pVideoAddress = ntscp; \
+ g_pVideoAddress++; \
+ } while(0)
+#else
+
+//===========================================================================
+inline void updateFramebufferColorTVSingleScanline( uint16_t signal, bgra_t *pTable )
+{
+ /* */ uint32_t *pLine0Address = getScanlineThis0Address();
+ /* */ uint32_t *pLine1Address = getScanlinePrev1Address();
+ /* */ uint32_t *pLine2Address = getScanlinePrev2Address();
+
+ const uint32_t color0 = getScanlineColor( signal, pTable );
+ const uint32_t color2 = *pLine2Address;
+// const uint32_t color1 = color0 - ((color2 & 0x00fcfcfc) >> 2); // BUG? color0 - color0? not color0-color2?
+ // TC: The above operation "color0 - ((color2 & 0x00fcfcfc) >> 2)" causes underflow, so I've recoded to clamp on underflow:
+ uint32_t color1;
+ {
+ int r=(color0>>16)&0xff, g=(color0>>8)&0xff, b=color0&0xff;
+ uint32_t color2_prime = (color2 & 0x00fcfcfc) >> 2;
+ r -= (color2_prime>>16)&0xff; if (r<0) r=0; // clamp to 0 on underflow
+ g -= (color2_prime>>8)&0xff; if (g<0) g=0; // clamp to 0 on underflow
+ b -= (color2_prime)&0xff; if (b<0) b=0; // clamp to 0 on underflow
+ color1 = (r<<16)|(g<<8)|(b);
+ }
+
+ /* */ *pLine1Address = color1 | ALPHA32_MASK;
+ /* */ *pLine0Address = color0;
+ /* */ g_pVideoAddress++;
+}
+
+//===========================================================================
+inline void updateFramebufferColorTVDoubleScanline( uint16_t signal, bgra_t *pTable )
+{
+ /* */ uint32_t *pLine0Address = getScanlineThis0Address();
+ /* */ uint32_t *pLine1Address = getScanlinePrev1Address();
+ const uint32_t *pLine2Address = getScanlinePrev2Address();
+
+ const uint32_t color0 = getScanlineColor( signal, pTable );
+ const uint32_t color2 = *pLine2Address;
+ const uint32_t color1 = ((color0 & 0x00fefefe) >> 1) + ((color2 & 0x00fefefe) >> 1); // 50% Blend
+
+ /* */ *pLine1Address = color1 | ALPHA32_MASK;
+ /* */ *pLine0Address = color0;
+ /* */ g_pVideoAddress++;
+}
+
+//===========================================================================
+inline void updateFramebufferMonitorSingleScanline( uint16_t signal, bgra_t *pTable )
+{
+ /* */ uint32_t *pLine0Address = getScanlineThis0Address();
+ /* */ uint32_t *pLine1Address = getScanlineNext1Address();
+ const uint32_t color0 = getScanlineColor( signal, pTable );
+ const uint32_t color1 = ((color0 & 0x00fcfcfc) >> 2); // 25% Blend (original)
+// const uint32_t color1 = ((color0 & 0x00fefefe) >> 1); // 50% Blend -- looks OK most of the time; Archon looks poor
+
+ /* */ *pLine1Address = color1 | ALPHA32_MASK;
+ /* */ *pLine0Address = color0;
+ /* */ g_pVideoAddress++;
+}
+
+//===========================================================================
+inline void updateFramebufferMonitorDoubleScanline( uint16_t signal, bgra_t *pTable )
+{
+ /* */ uint32_t *pLine0Address = getScanlineThis0Address();
+ /* */ uint32_t *pLine1Address = getScanlineNext1Address();
+ const uint32_t color0 = getScanlineColor( signal, pTable );
+
+ /* */ *pLine1Address = color0;
+ /* */ *pLine0Address = color0;
+ /* */ g_pVideoAddress++;
+}
+#endif
+
+//===========================================================================
+inline void updatePixels( uint16_t bits )
+{
+ if (g_nColorBurstPixels < 2)
+ {
+ /* #1 of 7 */
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ /* #2 of 7 */
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ /* #3 of 7 */
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ /* #4 of 7 */
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ /* #5 of 7 */
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ /* #6 of 7 */
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ /* #7 of 7 */
+ g_pFuncUpdateBnWPixel(bits & 1); bits >>= 1;
+ g_pFuncUpdateBnWPixel(bits & 1);
+ g_nLastColumnPixelNTSC=bits& 1 ; bits >>= 1;
+ }
+ else
+ {
+ /* #1 of 7 */ // abcd efgh ijkl mnop
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0abc defg hijk lmno
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 00ab cdef ghi jklmn
+ /* #2 of 7 */
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 000a bcde fghi jklm
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 abcd efgh ijkl
+ /* #3 of 7 */
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0abc defg hijk
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 00ab cdef ghij
+ /* #4 of 7 */
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 000a bcde fghi
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 abcd efgh
+ /* #5 of 7 */
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 0abc defg
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 00ab cdef
+ /* #6 of 7 */
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 000a bcde
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 0000 abcd
+ /* #7 of 7 */
+ g_pFuncUpdateHuePixel(bits & 1); bits >>= 1; // 0000 0000 0000 0abc
+ g_pFuncUpdateHuePixel(bits & 1);
+ g_nLastColumnPixelNTSC=bits& 1 ; bits >>= 1; // 0000 0000 0000 00ab
+ }
+}
+
+//===========================================================================
+inline bool updateScanLineModeSwitch( long cycles6502, UpdateScreenFunc_t self )
+{
+ bool bBail = false;
+ if( g_aHorzClockVideoMode[ g_nVideoClockHorz ] != g_aHorzClockVideoMode[ g_nVideoClockHorz+1 ] && !g_nVideoMixed ) // !g_nVideoMixed for "Rainbow"
+ {
+ UpdateScreenFunc_t pFunc = g_aFuncUpdateHorz[ g_nVideoClockHorz ];
+ if( pFunc && pFunc != self )
+ {
+ g_pFuncUpdateGraphicsScreen = pFunc;
+// g_pFuncUpdateTextScreen = pFunc; // No, as we can't break mixed mode for "Rainbow"
+ pFunc( cycles6502 );
+ bBail = true;
+ }
+ }
+
+ return bBail;
+}
+
+//===========================================================================
+inline void updateVideoScannerHorzEOL()
+{
+ if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz)
+ {
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ //VIDEO_DRAW_ENDLINE();
+ if (g_nColorBurstPixels < 2)
+ {
+ // NOTE: This writes out-of-bounds for a 560x384 framebuffer
+ g_pFuncUpdateBnWPixel(0);
+ g_pFuncUpdateBnWPixel(0);
+ g_pFuncUpdateBnWPixel(0);
+ g_pFuncUpdateBnWPixel(0);
+ }
+ else
+ {
+ // NOTE: This writes out-of-bounds for a 560x384 framebuffer
+ g_pFuncUpdateHuePixel(0);
+ g_pFuncUpdateHuePixel(0);
+ g_pFuncUpdateHuePixel(0);
+ g_pFuncUpdateHuePixel(g_nLastColumnPixelNTSC); // BUGFIX: ARCHON: green fringe on end of line
+ }
+ }
+
+ g_nVideoClockHorz = 0;
+
+ if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT)
+ {
+ g_nVideoClockVert = 0;
+
+ updateFlashRate();
+ //VideoRefreshScreen(0); // ContinueExecution() calls VideoRefreshScreen(0) every dwClksPerFrame (17030)
+ }
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ updateVideoScannerAddress();
+ }
+ }
+}
+
+//===========================================================================
+inline void updateVideoScannerAddress()
+{
+ g_pVideoAddress = g_nVideoClockVert poles for low pass
+//===========================================================================
+static real initFilterChroma (real z)
+{
+ static real x[CHROMA_ZEROS + 1] = {0,0,0};
+ static real y[CHROMA_POLES + 1] = {0,0,0};
+
+ x[0] = x[1]; x[1] = x[2]; x[2] = z / CHROMA_GAIN;
+ y[0] = y[1]; y[1] = y[2]; y[2] = -x[0] + x[2] + (CHROMA_0*y[0]) + (CHROMA_1*y[1]); // inverted x[0]
+
+ return y[2];
+}
+
+// Butterworth Lowpass digital filter
+// Filter Order: 2 -> poles for low pass
+//===========================================================================
+static real initFilterLuma0 (real z)
+{
+ static real x[LUMA_ZEROS + 1] = { 0,0,0 };
+ static real y[LUMA_POLES + 1] = { 0,0,0 };
+
+ x[0] = x[1]; x[1] = x[2]; x[2] = z / LUMA_GAIN;
+ y[0] = y[1]; y[1] = y[2]; y[2] = x[0] + x[2] + (2.f*x[1]) + (LUMA_0*y[0]) + (LUMA_1*y[1]);
+
+ return y[2];
+}
+
+// Butterworth Lowpass digital filter
+// Filter Order: 2 -> poles for low pass
+//===========================================================================
+static real initFilterLuma1 (real z)
+{
+ static real x[LUMA_ZEROS + 1] = { 0,0,0};
+ static real y[LUMA_POLES + 1] = { 0,0,0};
+
+ x[0] = x[1]; x[1] = x[2]; x[2] = z / LUMA_GAIN;
+ y[0] = y[1]; y[1] = y[2]; y[2] = x[0] + x[2] + (2.f*x[1]) + (LUMA_0*y[0]) + (LUMA_1*y[1]);
+
+ return y[2];
+}
+
+// Butterworth Lowpass digital filter
+// Filter Order: 2 -> poles for low pass
+//===========================================================================
+static real initFilterSignal (real z)
+{
+ static real x[SIGNAL_ZEROS + 1] = { 0,0,0 };
+ static real y[SIGNAL_POLES + 1] = { 0,0,0 };
+
+ x[0] = x[1]; x[1] = x[2]; x[2] = z / SIGNAL_GAIN;
+ y[0] = y[1]; y[1] = y[2]; y[2] = x[0] + x[2] + (2.f*x[1]) + (SIGNAL_0*y[0]) + (SIGNAL_1*y[1]);
+
+ return y[2];
+}
+
+//===========================================================================
+static void initPixelDoubleMasks (void)
+{
+ /*
+ Convert 7-bit monochrome luminance to 14-bit double pixel luminance
+ Chroma will be applied later based on the color phase in updatePixelHueMonitorDoubleScanline( luminanceBit )
+ 0x001 -> 0x0003
+ 0x002 -> 0x000C
+ 0x004 -> 0x0030
+ 0x008 -> 0x00C0
+ : -> :
+ 0x100 -> 0x4000
+ */
+ for (uint8_t byte = 0; byte < 0x80; byte++ ) // Optimization: hgrbits second 128 entries are mirror of first 128
+ for (uint8_t bits = 0; bits < 7; bits++ ) // high bit = half pixel shift; pre-optimization: bits < 8
+ if (byte & (1 << bits)) // pow2 mask
+ g_aPixelDoubleMaskHGR[byte] |= 3 << (bits*2);
+
+ for ( uint16_t color = 0; color < 16; color++ )
+ g_aPixelMaskGR[ color ] = (color << 12) | (color << 8) | (color << 4) | (color << 0);
+}
+
+//===========================================================================
+void updateMonochromeTables( uint16_t r, uint16_t g, uint16_t b )
+{
+ for( int iSample = 0; iSample < NTSC_NUM_SEQUENCES; iSample++ )
+ {
+ g_aBnWMonitorCustom[ iSample ].b = (g_aBnWMonitor[ iSample ].b * b) >> 8;
+ g_aBnWMonitorCustom[ iSample ].g = (g_aBnWMonitor[ iSample ].g * g) >> 8;
+ g_aBnWMonitorCustom[ iSample ].r = (g_aBnWMonitor[ iSample ].r * r) >> 8;
+ g_aBnWMonitorCustom[ iSample ].a = 0xFF;
+
+ g_aBnWColorTVCustom[ iSample ].b = (g_aBnwColorTV[ iSample ].b * b) >> 8;
+ g_aBnWColorTVCustom[ iSample ].g = (g_aBnwColorTV[ iSample ].g * g) >> 8;
+ g_aBnWColorTVCustom[ iSample ].r = (g_aBnwColorTV[ iSample ].r * r) >> 8;
+ g_aBnWColorTVCustom[ iSample ].a = 0xFF;
+ }
+}
+
+//===========================================================================
+static void updatePixelBnWMonitorSingleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferMonitorSingleScanline(compositeSignal, g_aBnWMonitorCustom);
+}
+
+//===========================================================================
+static void updatePixelBnWMonitorDoubleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferMonitorDoubleScanline(compositeSignal, g_aBnWMonitorCustom);
+}
+
+//===========================================================================
+static void updatePixelBnWColorTVSingleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferColorTVSingleScanline(compositeSignal, g_aBnWColorTVCustom);
+}
+
+//===========================================================================
+static void updatePixelBnWColorTVDoubleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferColorTVDoubleScanline(compositeSignal, g_aBnWColorTVCustom);
+}
+
+//===========================================================================
+static void updatePixelHueColorTVSingleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferColorTVSingleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+//===========================================================================
+static void updatePixelHueColorTVDoubleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferColorTVDoubleScanline(compositeSignal, g_aHueColorTV[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+//===========================================================================
+static void updatePixelHueMonitorSingleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferMonitorSingleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+//===========================================================================
+static void updatePixelHueMonitorDoubleScanline (uint16_t compositeSignal)
+{
+ updateFramebufferMonitorDoubleScanline(compositeSignal, g_aHueMonitor[g_nColorPhaseNTSC]);
+ updateColorPhase();
+}
+
+//===========================================================================
+void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0
+{
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pFuncUpdateTextScreen( cycles6502 );
+ return;
+ }
+
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressHGR();
+
+ 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)
+ {
+ if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleHires40 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t m = pMain[0];
+ uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128
+ updatePixels( bits );
+ }
+ }
+ updateVideoScannerHorzEOL();
+ }
+}
+
+//===========================================================================
+void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires
+{
+ uint16_t bits;
+
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pFuncUpdateTextScreen( cycles6502 );
+ return;
+ }
+
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressHGR();
+
+ 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)
+ {
+ if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleHires80 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t *pAux = MemGetAuxPtr (addr);
+
+ uint8_t m = pMain[0];
+ uint8_t a = pAux [0];
+
+ bits = ((m & 0x7f) << 7) | (a & 0x7f);
+ bits = (bits << 1) | g_nLastColumnPixelNTSC;
+ updatePixels( bits );
+ g_nLastColumnPixelNTSC = (bits >> 14) & 3;
+ }
+ }
+ updateVideoScannerHorzEOL();
+ }
+}
+
+//===========================================================================
+void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores
+{
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pFuncUpdateTextScreen( cycles6502 );
+ return;
+ }
+
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressTXT();
+
+ 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)
+ {
+ if ( updateScanLineModeSwitch( cycles6502, updateScreenDoubleLores40 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t m = pMain[0];
+ uint16_t lo = getLoResBits( m );
+ uint16_t bits = g_aPixelDoubleMaskHGR[(0xFF & lo >> ((1 - (g_nVideoClockHorz & 1)) * 2)) & 0x7F]; // Optimization: hgrbits
+ updatePixels( bits );
+ }
+ }
+ updateVideoScannerHorzEOL();
+ }
+}
+
+//===========================================================================
+void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores
+{
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pFuncUpdateTextScreen( cycles6502 );
+ return;
+ }
+
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressTXT();
+
+ 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)
+ {
+ if( updateScanLineModeSwitch( cycles6502, updateScreenDoubleLores80 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t *pAux = MemGetAuxPtr (addr);
+
+ uint8_t m = pMain[0];
+ uint8_t a = pAux [0];
+
+ uint16_t lo = getLoResBits( m );
+ uint16_t hi = getLoResBits( a );
+
+ uint16_t main = lo >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3);
+ uint16_t aux = hi >> (((1 - (g_nVideoClockHorz & 1)) * 2) + 3);
+ uint16_t bits = (main << 7) | (aux & 0x7f);
+ updatePixels( bits );
+ g_nLastColumnPixelNTSC = (bits >> 14) & 3;
+
+ }
+ }
+ updateVideoScannerHorzEOL();
+
+ }
+}
+
+//===========================================================================
+void updateScreenSingleHires40 (long cycles6502)
+{
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pFuncUpdateTextScreen( cycles6502 );
+ return;
+ }
+
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressHGR();
+
+ 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)
+ {
+ if ( updateScanLineModeSwitch( cycles6502, updateScreenSingleHires40 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t m = pMain[0];
+ uint16_t bits = g_aPixelDoubleMaskHGR[m & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128
+ if (m & 0x80)
+ bits = (bits << 1) | g_nLastColumnPixelNTSC;
+ updatePixels( bits );
+ }
+ }
+ updateVideoScannerHorzEOL();
+ }
+}
+
+//===========================================================================
+void updateScreenSingleLores40 (long cycles6502)
+{
+ if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED)
+ {
+ g_pFuncUpdateTextScreen( cycles6502 );
+ return;
+ }
+
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressTXT();
+
+ 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)
+ {
+ if( updateScanLineModeSwitch( cycles6502, updateScreenSingleLores40 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t m = pMain[0];
+ uint16_t lo = getLoResBits( m );
+ uint16_t bits = lo >> ((1 - (g_nVideoClockHorz & 1)) * 2);
+ updatePixels( bits );
+ }
+ }
+ updateVideoScannerHorzEOL();
+ }
+}
+
+//===========================================================================
+void updateScreenText40 (long cycles6502)
+{
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressTXT();
+
+ if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
+ {
+ if (g_nColorBurstPixels > 0)
+ g_nColorBurstPixels -= 1;
+ }
+ else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ if ( updateScanLineModeSwitch( cycles6502, updateScreenText40 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t m = pMain[0];
+ uint8_t c = getCharSetBits(m);
+ uint16_t bits = g_aPixelDoubleMaskHGR[c & 0x7F]; // Optimization: hgrbits second 128 entries are mirror of first 128
+
+ if (0 == g_nVideoCharSet && 0x40 == (m & 0xC0)) // Flash only if mousetext not active
+ bits ^= g_nTextFlashMask;
+
+ updatePixels( bits );
+
+ }
+ }
+ updateVideoScannerHorzEOL();
+ }
+}
+
+//===========================================================================
+void updateScreenText80 (long cycles6502)
+{
+ for (; cycles6502 > 0; --cycles6502)
+ {
+ uint16_t addr = updateVideoScannerAddressTXT();
+
+ if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
+ {
+ if (g_nColorBurstPixels > 0)
+ g_nColorBurstPixels -= 1;
+ }
+ else if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ {
+ if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
+ {
+ if ( updateScanLineModeSwitch( cycles6502, updateScreenText80 ) ) return; // ANSI STORY: vide mode switch mid scan line!
+
+ uint8_t *pMain = MemGetMainPtr(addr);
+ uint8_t *pAux = MemGetAuxPtr (addr);
+
+ uint8_t m = pMain[0];
+ uint8_t a = pAux [0];
+
+ uint16_t main = getCharSetBits( m );
+ uint16_t aux = getCharSetBits( a );
+
+ if ((0 == g_nVideoCharSet) && 0x40 == (m & 0xC0)) // Flash only if mousetext not active
+ main ^= g_nTextFlashMask;
+
+ if ((0 == g_nVideoCharSet) && 0x40 == (a & 0xC0)) // Flash only if mousetext not active
+ aux ^= g_nTextFlashMask;
+
+ uint16_t bits = (main << 7) | aux;
+ updatePixels( bits );
+ }
+ }
+ updateVideoScannerHorzEOL();
+ }
+}
+
+// Functions (Public) _____________________________________________________________________________
+
+//===========================================================================
+uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV )
+{
+ if( bHueTypeMonochrome )
+ {
+ g_nChromaSize = sizeof( g_aBnwColorTV );
+
+ if( bMonitorTypeColorTV )
+ return (uint32_t*) g_aBnwColorTV;
+ else
+ return (uint32_t*) g_aBnWMonitor;
+ } else {
+ g_nChromaSize = sizeof( g_aHueColorTV );
+
+ if( bMonitorTypeColorTV )
+ return (uint32_t*) g_aHueColorTV;
+ else
+#if ALT_TABLE
+ g_nChromaSize = sizeof(T_NTSC);
+ return (uint32_t*)T_NTSC;
+#endif
+ return (uint32_t*) g_aHueMonitor;
+ }
+}
+
+//===========================================================================
+uint16_t NTSC_VideoGetScannerAddress ( unsigned long cycles6502 )
+{
+ (void)cycles6502;
+
+ int nHires = (g_uVideoMode & VF_HIRES) && !(g_uVideoMode & VF_TEXT); // (SW_HIRES && !SW_TEXT) ? 1 : 0;
+ if( nHires )
+ updateVideoScannerAddressHGR();
+ else
+ updateVideoScannerAddressTXT();
+
+ // Required for ANSI STORY vert scrolling mid-scanline mixed mode: DGR80, TEXT80, DGR80
+ uint8_t hclock = (g_nVideoClockHorz + VIDEO_SCANNER_MAX_HORZ - 2) % VIDEO_SCANNER_MAX_HORZ; // Optimization: (h-2)
+ return g_aHorzClockMemAddress[ hclock ];
+}
+
+//===========================================================================
+void NTSC_SetVideoTextMode( int cols )
+{
+ if( cols == 40 )
+ g_pFuncUpdateTextScreen = updateScreenText40;
+ else
+ g_pFuncUpdateTextScreen = updateScreenText80;
+}
+
+//===========================================================================
+void NTSC_SetVideoMode( int bVideoModeFlags )
+{
+ int h = g_nVideoClockHorz;
+
+ g_aHorzClockVideoMode[ h ] = bVideoModeFlags;
+
+ g_nVideoMixed = bVideoModeFlags & VF_MIXED;
+ g_nVideoCharSet = VideoGetSWAltCharSet() ? 1 : 0;
+
+ g_nTextPage = 1;
+ g_nHiresPage = 1;
+ if (bVideoModeFlags & VF_PAGE2) {
+ // Apple IIe, Techical Nodtes, #3: Double High-Resolution Graphics
+ // 80STORE must be OFF to display page 2
+ if (0 == (bVideoModeFlags & VF_80STORE)) {
+ g_nTextPage = 2;
+ g_nHiresPage = 2;
+ }
+ }
+
+ if (bVideoModeFlags & VF_TEXT) {
+ if (bVideoModeFlags & VF_80COL)
+ g_pFuncUpdateGraphicsScreen = updateScreenText80;
+ else
+ g_pFuncUpdateGraphicsScreen = updateScreenText40;
+ }
+ else if (bVideoModeFlags & VF_HIRES) {
+ if (bVideoModeFlags & VF_DHIRES)
+ if (bVideoModeFlags & VF_80COL)
+ g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires80;
+ else
+ g_pFuncUpdateGraphicsScreen = updateScreenDoubleHires40;
+ else
+ g_pFuncUpdateGraphicsScreen = updateScreenSingleHires40;
+ }
+ else {
+ if (bVideoModeFlags & VF_DHIRES)
+ if (bVideoModeFlags & VF_80COL)
+ g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores80;
+ else
+ g_pFuncUpdateGraphicsScreen = updateScreenDoubleLores40;
+ else
+ g_pFuncUpdateGraphicsScreen = updateScreenSingleLores40;
+ }
+
+ g_aFuncUpdateHorz[ h ] = g_pFuncUpdateGraphicsScreen; // NTSC: ANSI STORY
+}
+
+//===========================================================================
+void NTSC_SetVideoStyle() // (int v, int s)
+{
+ int half = g_uHalfScanLines;
+ uint8_t r, g, b;
+
+ switch ( g_eVideoType )
+ {
+ case VT_COLOR_TV:
+ r = 0xFF;
+ g = 0xFF;
+ b = 0xFF;
+ updateMonochromeTables( r, g, b );
+ if (half)
+ {
+ g_pFuncUpdateBnWPixel = updatePixelBnWColorTVSingleScanline;
+ g_pFuncUpdateHuePixel = updatePixelHueColorTVSingleScanline;
+ }
+ else {
+ g_pFuncUpdateBnWPixel = updatePixelBnWColorTVDoubleScanline;
+ g_pFuncUpdateHuePixel = updatePixelHueColorTVDoubleScanline;
+ }
+ break;
+
+ case VT_COLOR_MONITOR:
+ default:
+ r = 0xFF;
+ g = 0xFF;
+ b = 0xFF;
+ updateMonochromeTables( r, g, b );
+ if (half)
+ {
+ g_pFuncUpdateBnWPixel = updatePixelBnWMonitorSingleScanline;
+ g_pFuncUpdateHuePixel = updatePixelHueMonitorSingleScanline;
+ }
+ else {
+ g_pFuncUpdateBnWPixel = updatePixelBnWMonitorDoubleScanline;
+ g_pFuncUpdateHuePixel = updatePixelHueMonitorDoubleScanline;
+ }
+ break;
+
+ case VT_MONO_TV:
+ r = 0xFF;
+ g = 0xFF;
+ b = 0xFF;
+ updateMonochromeTables( r, g, b ); // Custom Monochrome color
+ if (half)
+ {
+ g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVSingleScanline;
+ }
+ else {
+ g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWColorTVDoubleScanline;
+ }
+ break;
+
+// case VT_MONO_WHITE: //VT_MONO_MONITOR: //3:
+ case VT_MONO_AMBER:
+ r = 0xFF;
+ g = 0x80;
+ b = 0x00;
+ goto _mono;
+
+ case VT_MONO_GREEN:
+ r = 0x00;
+ g = 0xC0;
+ b = 0x00;
+ goto _mono;
+
+ case VT_MONO_WHITE:
+ r = 0xFF;
+ g = 0xFF;
+ b = 0xFF;
+ goto _mono;
+
+ case VT_MONO_CUSTOM:
+ // From WinGDI.h
+ // #define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
+ //#define GetRValue(rgb) (LOBYTE(rgb))
+ //#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8))
+ //#define GetBValue(rgb) (LOBYTE((rgb)>>16))
+ r = (g_nMonochromeRGB >> 0) & 0xFF;
+ g = (g_nMonochromeRGB >> 8) & 0xFF;
+ b = (g_nMonochromeRGB >> 16) & 0xFF;
+_mono:
+ updateMonochromeTables( r, g, b ); // Custom Monochrome color
+ if (half)
+ {
+ g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorSingleScanline;
+ }
+ else
+ {
+ g_pFuncUpdateBnWPixel = g_pFuncUpdateHuePixel = updatePixelBnWMonitorDoubleScanline;
+ }
+ break;
+ }
+}
+
+//===========================================================================
+void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit
+{
+ make_csbits();
+ initPixelDoubleMasks();
+ initChromaPhaseTables();
+ updateMonochromeTables( 0xFF, 0xFF, 0xFF );
+
+ for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++)
+ g_pScanLines[y] = (bgra_t*)(g_pFramebufferbits + 4 * FRAMEBUFFER_W * ((FRAMEBUFFER_H - 1) - y - 18) + 80);
+
+ g_pVideoAddress = g_pScanLines[0];
+
+ g_pFuncUpdateTextScreen = updateScreenText40;
+ g_pFuncUpdateGraphicsScreen = updateScreenText40;
+
+ VideoReinitialize(); // Setup g_pFunc_ntsc*Pixel()
+
+#if HGR_TEST_PATTERN
+// Init HGR to almost all-possible-combinations
+// CALL-151
+// C050 C053 C057
+ unsigned char b = 0;
+ unsigned char *main, *aux;
+ uint16_t ad;
+
+ for( unsigned page = 0; page < 2; page++ )
+ {
+// for( unsigned w = 0; w < 2; w++ ) // 16 cols
+ {
+ for( unsigned z = 0; z < 2; z++ ) // 8 cols
+ {
+ b = 0; // 4 columns * 64 rows
+ for( unsigned x = 0; x < 4; x++ ) // 4 cols
+ {
+ for( unsigned y = 0; y < 64; y++ ) // 1 col
+ {
+ unsigned y2 = y*2;
+ ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z; // + 20*w;
+ ad += 0x2000*page;
+ main = MemGetMainPtr(ad);
+ aux = MemGetAuxPtr (ad);
+ main[0] = b; main[1] = z + page*0x80;
+ aux [0] = z; aux [1] = 0;
+
+ if( page == 1 )
+ {
+ // Columns = # of consecutive pixels
+ // x = 0, 1, 2, 3
+ // # = 3, 5, 7, 9
+ // b = 3, 7, 15, 31
+ // = (4 << x) - 1
+ main[0+z] = (0x80*(y/32) + (((4 << x) - 1) << (y/8))); // (3 | 3+x*2)
+ main[1+z] = (0x80*(y/32) + (((4 << x) - 1) << (y/8))) >> 8;
+ }
+
+ y2 = y*2 + 1;
+ ad = 0x2000 + (y2&7)*0x400 + ((y2/8)&7)*0x80 + (y2/64)*0x28 + 2*x + 10*z; // + 20*w;
+ ad += 0x2000*page;
+ main = MemGetMainPtr(ad);
+ aux = MemGetAuxPtr (ad);
+ main[0] = 0; main[1] = z + page*0x80;
+ aux [0] = b; aux [1] = 0;
+
+ b++;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+}
+
+//===========================================================================
+void NTSC_VideoReinitialize( DWORD cyclesThisFrame )
+{
+ _ASSERT(cyclesThisFrame < VIDEO_SCANNER_6502_CYCLES);
+ if (cyclesThisFrame >= VIDEO_SCANNER_6502_CYCLES) cyclesThisFrame = 0; // error
+ g_nVideoClockVert = (uint16_t) (cyclesThisFrame / VIDEO_SCANNER_MAX_HORZ);
+ g_nVideoClockHorz = cyclesThisFrame % VIDEO_SCANNER_MAX_HORZ;
+
+ updateVideoScannerAddress(); // Pre-condition: g_nVideoClockVert
+}
+
+//===========================================================================
+void NTSC_VideoInitAppleType ()
+{
+ int model = GetApple2Type();
+
+ // anything other than low bit set means not II/II+ (TC: include Pravets machines too?)
+ if (model & 0xFFFE)
+ g_pHorzClockOffset = APPLE_IIE_HORZ_CLOCK_OFFSET;
+ else
+ g_pHorzClockOffset = APPLE_IIP_HORZ_CLOCK_OFFSET;
+
+ set_csbits();
+}
+
+//===========================================================================
+void NTSC_VideoInitChroma()
+{
+ initChromaPhaseTables();
+}
+
+//===========================================================================
+bool NTSC_VideoIsVbl ()
+{
+ return (g_nVideoClockVert >= VIDEO_SCANNER_Y_DISPLAY) && (g_nVideoClockVert < VIDEO_SCANNER_MAX_VERT);
+}
+
+// Light-weight Video Clock Update
+//===========================================================================
+void NTSC_VideoUpdateCycles( long cycles6502 )
+{
+ bool bRedraw = cycles6502 >= VIDEO_SCANNER_6502_CYCLES;
+
+// if( !g_bFullSpeed )
+if(true)
+ g_pFuncUpdateGraphicsScreen( cycles6502 );
+ else
+{
+ while( cycles6502 > VIDEO_SCANNER_6502_CYCLES )
+ /* */ cycles6502 -= VIDEO_SCANNER_6502_CYCLES ;
+
+ for( ; cycles6502 > 0; cycles6502-- )
+ {
+ if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz)
+ {
+ g_nVideoClockHorz = 0;
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ g_apFuncVideoUpdateScanline[ g_nVideoClockVert ] = g_pFuncUpdateGraphicsScreen;
+
+ if (++g_nVideoClockVert == VIDEO_SCANNER_MAX_VERT)
+ {
+ g_nVideoClockVert = 0;
+
+ updateFlashRate();
+
+ bRedraw = true;
+ }
+
+ if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
+ updateVideoScannerAddress();
+ }
+ }
+
+ if( bRedraw ) // Force full refresh
+ {
+ for( int y = 0; y < VIDEO_SCANNER_Y_DISPLAY; y++ )
+ g_apFuncVideoUpdateScanline[ y ]( VIDEO_SCANNER_MAX_HORZ );
+
+ int nCyclesVBlank = (VIDEO_SCANNER_MAX_VERT - VIDEO_SCANNER_Y_DISPLAY) * VIDEO_SCANNER_MAX_HORZ;
+ g_pFuncUpdateGraphicsScreen( nCyclesVBlank );
+
+ VideoRefreshScreen(0);
+ }
+}
+}
diff --git a/source/NTSC.h b/source/NTSC.h
new file mode 100644
index 00000000..d01bd250
--- /dev/null
+++ b/source/NTSC.h
@@ -0,0 +1,20 @@
+// Constants
+ const int VIDEO_SCANNER_6502_CYCLES = 17030;
+
+// Globals (Public)
+ extern uint16_t g_nVideoClockVert;
+ extern uint16_t g_nVideoClockHorz;
+ extern uint32_t g_nChromaSize;
+
+// Prototypes (Public) ________________________________________________
+ extern void NTSC_SetVideoMode( int bVideoModeFlags );
+ extern void NTSC_SetVideoStyle();
+ extern void NTSC_SetVideoTextMode( int cols );
+ extern uint32_t*NTSC_VideoGetChromaTable( bool bHueTypeMonochrome, bool bMonitorTypeColorTV );
+ extern uint16_t NTSC_VideoGetScannerAddress( unsigned long cycles6502 );
+ extern void NTSC_VideoInit( uint8_t *pFramebuffer );
+ extern void NTSC_VideoReinitialize( DWORD cyclesThisFrame );
+ extern void NTSC_VideoInitAppleType();
+ extern void NTSC_VideoInitChroma();
+ extern bool NTSC_VideoIsVbl();
+ extern void NTSC_VideoUpdateCycles( long cycles6502 );
diff --git a/source/NTSC_CharSet.cpp b/source/NTSC_CharSet.cpp
new file mode 100644
index 00000000..ce940e51
--- /dev/null
+++ b/source/NTSC_CharSet.cpp
@@ -0,0 +1,102 @@
+/*
+AppleWin : An Apple //e emulator for Windows
+
+Copyright (C) 2010-2011, William S Simms
+Copyright (C) 2016, Tom Charlesworth
+
+AppleWin is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+AppleWin is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with AppleWin; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "StdAfx.h"
+#include "AppleWin.h"
+
+#include "NTSC_CharSet.h"
+
+unsigned char csbits_enhanced2e[2][256][8]; // Enhanced //e
+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
+unsigned char csbits_pravets8M[1][256][8]; // Pravets 8M
+unsigned char csbits_pravets8C[2][256][8]; // Pravets 8A & 8C
+
+//
+
+static const UINT bitmapWidth = 256;
+static const UINT bitmapWidthBytes = bitmapWidth/8;
+static const UINT bitmapHeight = 768;
+
+static const UINT charWidth = 16;
+static const UINT charWidthBytes = 16/8;
+static const UINT charHeight = 16;
+
+static void get_csbits_xy(csbits_t csbits, UINT ch, UINT cx, UINT cy, const BYTE* pBitmap)
+{
+ _ASSERT(ch < 256);
+ _ASSERT((cx < bitmapWidth/charWidth) && (cy < bitmapHeight/charHeight));
+
+ pBitmap += cy*charHeight*bitmapWidthBytes + cx*charWidthBytes;
+
+ for (UINT y=0; y<8; y++)
+ {
+ BYTE n = 0;
+ for (int x=0; x<14; x+=2)
+ {
+ UINT xp = x/8;
+ BYTE d = pBitmap[xp];
+ UINT b = 7 - x%8;
+ if (d & (1<>= 1;
+ }
+
+ csbits[0][ch][y] = n;
+ pBitmap += bitmapWidthBytes*2;
+ }
+}
+
+static void get_csbits(csbits_t csbits, const char* resourceName, const UINT cy0)
+{
+ const UINT bufferSize = bitmapWidthBytes*bitmapHeight;
+ BYTE* pBuffer = new BYTE [bufferSize];
+
+ HBITMAP hCharBitmap = LoadBitmap(g_hInstance, resourceName);
+ GetBitmapBits(hCharBitmap, bufferSize, pBuffer);
+
+ for (UINT cy=cy0, ch=0; cy dwCurrentPlayCursor) && (dwByteOffset < dwCurrentWriteCursor))
{
double fTicksSecs = (double)GetTickCount() / 1000.0;
- sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
- OutputDebugString(szDbg);
- if (g_fh) fprintf(g_fh, szDbg);
+ //sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X xxx\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
+ //OutputDebugString(szDbg);
+ //if (g_fh) fprintf(g_fh, szDbg);
dwByteOffset = dwCurrentWriteCursor;
nNumSamplesError = 0;
@@ -885,9 +885,9 @@ static ULONG Spkr_SubmitWaveBuffer(short* pSpeakerBuffer, ULONG nNumSamples)
if((dwByteOffset > dwCurrentPlayCursor) || (dwByteOffset < dwCurrentWriteCursor))
{
double fTicksSecs = (double)GetTickCount() / 1000.0;
- sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
- OutputDebugString(szDbg);
- if (g_fh) fprintf(g_fh, "%s", szDbg);
+ //sprintf(szDbg, "%010.3f: [Submit] PC=%08X, WC=%08X, Diff=%08X, Off=%08X, NS=%08X XXX\n", fTicksSecs, dwCurrentPlayCursor, dwCurrentWriteCursor, dwCurrentWriteCursor-dwCurrentPlayCursor, dwByteOffset, nNumSamples);
+ //OutputDebugString(szDbg);
+ //if (g_fh) fprintf(g_fh, "%s", szDbg);
dwByteOffset = dwCurrentWriteCursor;
nNumSamplesError = 0;
diff --git a/source/StdAfx.h b/source/StdAfx.h
index 0925ddcf..e4c4f02a 100644
--- a/source/StdAfx.h
+++ b/source/StdAfx.h
@@ -4,6 +4,7 @@
// . See: http://support.embarcadero.com/article/35754
// . "GetOpenFileName() fails under Windows 95/98/NT/ME due to incorrect OPENFILENAME structure size"
#define _WIN32_WINNT 0x0400
+#define WINVER 0x500
// Mouse Wheel is not supported on Win95.
// If we didn't care about supporting Win95 (compile/run-time errors)
@@ -14,7 +15,7 @@
#endif
// Not needed in VC7.1, but needed in VC Express
-#include
+#include
#include
#include
@@ -27,6 +28,9 @@
#if _MSC_VER >= 1600 // supported from VS2010 (cl.exe v16.00)
#include // cleanup WORD DWORD -> uint16_t uint32_t
#else
+typedef UINT8 uint8_t;
+typedef UINT16 uint16_t;
+typedef UINT32 uint32_t;
#endif
#include
diff --git a/source/Video.cpp b/source/Video.cpp
index 0a10fabe..9d22835b 100644
--- a/source/Video.cpp
+++ b/source/Video.cpp
@@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Memory.h"
#include "Registry.h"
#include "Video.h"
+#include "NTSC.h"
#include "..\resource\resource.h"
#include "Configuration\PropertySheet.h"
@@ -119,23 +120,13 @@ enum Color_Palette_Index_e
, HGR_PINK
// MONOCHROME
- // NOTE: 50% is assumed to come after 100% luminance !!! See: V_CreateLookup_MonoHiRes()
- // User customizable
, MONOCHROME_CUSTOM // 100% luminance
, MONOCHROME_CUSTOM_50 // 50% luminance
- // Pre-set "Monochromes"
, MONOCHROME_AMBER
-// , MONOCHROME_AMBER_50 // BUG - something trashing our palette entry !!!
, MONOCHROME_GREEN
-// , MONOCHROME_GREEN_50 // BUG - something trashing our palette entry !!!
-
, DEBUG_COLORS_START
, DEBUG_COLORS_END = DEBUG_COLORS_START + NUM_DEBUG_COLORS
-// DD Full Screen Palette ?!?!
-// , LOGO_COLORS_START
-// , LOGO_COLORS_END = LOGO_COLORS_START + 128
-
, NUM_COLOR_PALETTE
// The last 10 are the DEFAULT Windows colors (as it reserves 20 colors)
@@ -196,17 +187,6 @@ const BYTE DoubleHiresPalIndex[16] = {
const int SRCOFFS_DHIRES = (SRCOFFS_HIRES + 512); // 1168
const int SRCOFFS_TOTAL = (SRCOFFS_DHIRES + 2560); // 3278
- enum VideoFlag_e
- {
- VF_80COL = 0x00000001,
- VF_DHIRES = 0x00000002,
- VF_HIRES = 0x00000004,
- VF_80STORE= 0x00000008,
- VF_MIXED = 0x00000010,
- VF_PAGE2 = 0x00000020,
- VF_TEXT = 0x00000040
- };
-
#define SW_80COL (g_uVideoMode & VF_80COL)
#define SW_DHIRES (g_uVideoMode & VF_DHIRES)
#define SW_HIRES (g_uVideoMode & VF_HIRES)
@@ -224,6 +204,13 @@ const BYTE DoubleHiresPalIndex[16] = {
#define HGR_MATRIX_YOFFSET 2 // For tv emulation HGR Video Mode
+// Globals (Public)
+
+ uint8_t *g_pFramebufferbits = NULL; // last drawn frame
+ int g_nAltCharSetOffset = 0; // alternate character set
+
+// Globals (Private)
+
// video scanner constants
int const kHBurstClock = 53; // clock when Color Burst starts
int const kHBurstClocks = 4; // clocks per Color Burst duration
@@ -241,13 +228,10 @@ int const kVLine0State = 0x100; // V[543210CBA] = 100000000
int const kVPresetLine = 256; // line when V state presets
int const kVSyncLines = 4; // lines per VSync duration
-static BYTE celldirty[40][32]; // [TC: 27/06/2014] NB. No longer used!
-// NUM_COLOR_PALETTE
static COLORREF customcolors[256]; // MONOCHROME is last custom color
static HBITMAP g_hDeviceBitmap;
static HDC g_hDeviceDC;
- LPBYTE g_pFramebufferbits = NULL; // last drawn frame
static LPBITMAPINFO g_pFramebufferinfo = NULL;
static LPBYTE g_aFrameBufferOffset[FRAMEBUFFER_H]; // array of pointers to start of each scanline
@@ -264,75 +248,49 @@ static LPBYTE g_aSourceStartofLine[ MAX_SOURCE_Y ];
static LPBYTE g_pTextBank1; // Aux
static LPBYTE g_pTextBank0; // Main
-// For tv emulation HGR Video Mode
-// 2 extra scan lines on bottom?
-static BYTE hgrpixelmatrix[FRAMEBUFFER_W/2][FRAMEBUFFER_H/2 + 2 * HGR_MATRIX_YOFFSET];
-static BYTE colormixbuffer[6];
-static WORD colormixmap[6][6][6];
-//
-
-static int g_nAltCharSetOffset = 0; // alternate character set
-
static /*bool*/ UINT g_VideoForceFullRedraw = 1;
-static bool g_bVideoUpdatedThisFrame = false;
static LPBYTE framebufferaddr = (LPBYTE)0;
static LONG g_nFrameBufferPitch = 0;
-COLORREF monochrome = RGB(0xC0,0xC0,0xC0);
-static BOOL rebuiltsource = 0;
-static LPBYTE vidlastmem = NULL;
+COLORREF g_nMonochromeRGB = RGB(0xC0,0xC0,0xC0);
+static BOOL rebuiltsource = 0;
+static LPBYTE vidlastmem = NULL;
-static UINT g_uVideoMode = VF_TEXT;
+ 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_TVEMU;
+ DWORD g_eVideoType = VT_COLOR_TV;
DWORD g_uHalfScanLines = 1; // drop 50% scan lines for a more authentic look
-
-static bool g_bTextFlashState = false;
-static bool g_bTextFlashFlag = false;
-
static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL)
//-------------------------------------
// NOTE: KEEP IN SYNC: VideoType_e g_aVideoChoices g_apVideoModeDesc
TCHAR g_aVideoChoices[] =
- TEXT("Monochrome (Custom Luminance)\0")
- TEXT("Color (Standard)\0")
- TEXT("Color (Text Optimized)\0")
- TEXT("Color (TV emulation)\0")
+ TEXT("Monochrome (Custom)\0")
+ TEXT("Color Monitor\0")
+ TEXT("B&W TV\0")
+ TEXT("Color TV\0")
TEXT("Monochrome (Amber)\0")
TEXT("Monochrome (Green)\0")
TEXT("Monochrome (White)\0")
;
- // AppleWin 1.19.4 VT_COLOR_AUTHENTIC -> VT_COLOR_HALFPIXEL -> VT_COLOR_STANDARD "Color Half-Pixel Authentic
// NOTE: KEEP IN SYNC: VideoType_e g_aVideoChoices g_apVideoModeDesc
// The window title will be set to this.
char *g_apVideoModeDesc[ NUM_VIDEO_MODES ] =
{
- "Monochrome (Custom)"
- , "Standard"
- , "Text Optimized"
- , "TV"
- , "Amber"
- , "Green"
- , "White"
+ "Monochrome Monitor (Custom)"
+ , "Color Monitor"
+ , "B&W TV"
+ , "Color TV"
+ , "Amber Monitor"
+ , "Green Monitor"
+ , "White Monitor"
};
// Prototypes (Private) _____________________________________________
- void V_CreateLookup_DoubleHires ();
- void V_CreateLookup_Hires (); // Old "Full-Pixel" support only: STANDARD, TEXT_OPTIMIZED, TVEMU
- void V_CreateLookup_HiResHalfPixel_Authentic (); // New "Half_Pixel" support: STANDARD, TEXT_OPTIMIZED
- void V_CreateLookup_HiresHalfShiftDim();
- void V_CreateLookup_Lores ();
- void V_CreateLookup_Text (HDC dc);
-// Monochrome Full-Pixel Support
- void V_CreateLookup_MonoDoubleHiRes ();
- void V_CreateLookup_MonoHiRes ();
- void V_CreateLookup_MonoLoRes ();
- void V_CreateLookup_MonoText (HDC dc);
// Monochrome Half-Pixel Support
void V_CreateLookup_MonoHiResHalfPixel_Real ();
@@ -348,88 +306,7 @@ static bool bVideoScannerNTSC = true; // NTSC video scanning (or PAL)
int GetMonochromeIndex();
void V_CreateIdentityPalette ();
- void V_CreateDIBSections ();
- HBRUSH V_CreateCustomBrush (COLORREF nColor);
-
-/** Our BitBlit() / VRAM_Copy()
- @param dx Dst X
- @param dy Dst Y
- @param w Width (same for src & dst)
- @param h Height (same for src & dst)
- @param sx Src X
- @param sy Src Y
-// =========================================================================== */
-
-static inline void CopySource8(int dx, int dy, int w, int h, int sx, int sy)
-{
- LPBYTE pDst = g_aFrameBufferOffset[ dy ] + dx;
- LPBYTE pSrc = g_aSourceStartofLine[ sy ] + sx;
- int nBytes;
-
- while (h--)
- {
- nBytes = w;
-
- // If not multiple of 3 bytes, copy first 3 bytes, so the next copy is 4-byte aligned.
- while (nBytes & 3)
- {
- --nBytes;
- if (g_uHalfScanLines && !(h & 1))
- *(pDst+nBytes) = 0; // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows)
- else
- *(pDst+nBytes) = *(pSrc+nBytes);
- }
-
- // Copy 4 bytes at a time
- while (nBytes)
- {
- nBytes -= 4;
- if (g_uHalfScanLines && !(h & 1))
- *(LPDWORD)(pDst+nBytes) = 0; // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows)
- else
- *(LPDWORD)(pDst+nBytes) = *(LPDWORD)(pSrc+nBytes);
- }
-
- pDst -= g_nFrameBufferPitch;
- pSrc -= SRCOFFS_TOTAL;
- }
-}
-
-static void CopySource(int dx, int dy, int w, int h, int sx, int sy)
-{
- if (!g_bIsFullScreen || !GetFullScreen32Bit())
- {
- CopySource8(dx,dy,w,h,sx,sy);
- return;
- }
-
- UINT32* pDst = (UINT32*) (g_aFrameBufferOffset[ dy ] + dx*sizeof(UINT32));
- 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
- {
- const RGBQUAD& rRGB = g_pFramebufferinfo->bmiColors[ *(pSrc+nBytes) ];
- const UINT32 rgb = (((UINT32)rRGB.rgbRed)<<16) | (((UINT32)rRGB.rgbGreen)<<8) | ((UINT32)rRGB.rgbBlue);
- *(pDst+nBytes) = rgb;
- }
- }
-
- pDst -= g_nFrameBufferPitch / sizeof(UINT32);
- pSrc -= SRCOFFS_TOTAL;
- }
-}
+ void videoCreateDIBSection();
//===========================================================================
void CreateFrameOffsetTable (LPBYTE addr, LONG pitch)
@@ -448,12 +325,16 @@ void CreateFrameOffsetTable (LPBYTE addr, LONG pitch)
//===========================================================================
void VideoInitialize ()
{
+ // RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET
+ VideoResetState();
+
// CREATE A BUFFER FOR AN IMAGE OF THE LAST DRAWN MEMORY
vidlastmem = (LPBYTE)VirtualAlloc(NULL,0x10000,MEM_COMMIT,PAGE_READWRITE);
ZeroMemory(vidlastmem,0x10000);
// LOAD THE LOGO
- g_hLogoBitmap = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
+// g_hLogoBitmap = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN), IMAGE_BITMAP, 560, 384, LR_CREATEDIBSECTION);
+ g_hLogoBitmap = LoadBitmap( g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN) );
// CREATE A BITMAPINFO STRUCTURE FOR THE FRAME BUFFER
g_pFramebufferinfo = (LPBITMAPINFO)VirtualAlloc(
@@ -463,74 +344,20 @@ void VideoInitialize ()
PAGE_READWRITE);
ZeroMemory(g_pFramebufferinfo,sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD));
- g_pFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- g_pFramebufferinfo->bmiHeader.biWidth = FRAMEBUFFER_W;
- g_pFramebufferinfo->bmiHeader.biHeight = FRAMEBUFFER_H;
- g_pFramebufferinfo->bmiHeader.biPlanes = 1;
- g_pFramebufferinfo->bmiHeader.biBitCount = 8;
- g_pFramebufferinfo->bmiHeader.biClrUsed = 256;
+ g_pFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ g_pFramebufferinfo->bmiHeader.biWidth = FRAMEBUFFER_W;
+ g_pFramebufferinfo->bmiHeader.biHeight = FRAMEBUFFER_H;
+ g_pFramebufferinfo->bmiHeader.biPlanes = 1;
+ g_pFramebufferinfo->bmiHeader.biBitCount = 32;
+ g_pFramebufferinfo->bmiHeader.biCompression = BI_RGB;
+ g_pFramebufferinfo->bmiHeader.biClrUsed = 0;
- // CREATE A BITMAPINFO STRUCTURE FOR THE SOURCE IMAGE
- g_pSourceHeader = (LPBITMAPINFO)VirtualAlloc(
- NULL,
- sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD),
- MEM_COMMIT,
- PAGE_READWRITE);
-
- ZeroMemory(g_pSourceHeader,sizeof(BITMAPINFOHEADER));
- g_pSourceHeader->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- g_pSourceHeader->bmiHeader.biWidth = SRCOFFS_TOTAL;
- g_pSourceHeader->bmiHeader.biHeight = 512;
- g_pSourceHeader->bmiHeader.biPlanes = 1;
- g_pSourceHeader->bmiHeader.biBitCount = 8;
- g_pSourceHeader->bmiHeader.biClrUsed = 256;
-
- // VideoReinitialize() ... except we set the frame buffer palette....
- V_CreateIdentityPalette();
-
- //RGB() -> none
- //PALETTERGB() -> PC_EXPLICIT
- //??? RGB() -> PC_NOCOLLAPSE
- for( int iColor = 0; iColor < NUM_COLOR_PALETTE; iColor++ )
- customcolors[ iColor ] = ((DWORD)PC_EXPLICIT << 24) | RGB(
- g_pFramebufferinfo->bmiColors[iColor].rgbRed,
- g_pFramebufferinfo->bmiColors[iColor].rgbGreen,
- g_pFramebufferinfo->bmiColors[iColor].rgbBlue
- );
-
- // CREATE THE FRAME BUFFER DIB SECTION AND DEVICE CONTEXT,
- // CREATE THE SOURCE IMAGE DIB SECTION AND DRAW INTO THE SOURCE BIT BUFFER
- V_CreateDIBSections();
-
- // RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET
- VideoResetState();
-}
-
-//===========================================================================
-int GetMonochromeIndex()
-{
- int iMonochrome;
-
- switch (g_eVideoType)
- {
- case VT_MONO_AMBER : iMonochrome = MONOCHROME_AMBER ; break;
- case VT_MONO_GREEN : iMonochrome = MONOCHROME_GREEN ; break;
- case VT_MONO_WHITE : iMonochrome = HGR_WHITE ; break;
- default : iMonochrome = MONOCHROME_CUSTOM; break; // caller will use MONOCHROME_CUSTOM MONOCHROME_CUSTOM_50 !
- }
-
- return iMonochrome;
+ videoCreateDIBSection();
}
//===========================================================================
void V_CreateIdentityPalette ()
{
- if (g_hPalette)
- {
- DeleteObject(g_hPalette);
- }
- g_hPalette = (HPALETTE)0;
-
SETFRAMECOLOR(BLACK, 0x00,0x00,0x00); // 0
SETFRAMECOLOR(DARK_RED, 0x80,0x00,0x00); // 1 // not used
SETFRAMECOLOR(DARK_GREEN, 0x00,0x80,0x00); // 2 // not used
@@ -570,18 +397,17 @@ void V_CreateIdentityPalette ()
SETFRAMECOLOR(HGR_PINK, 0xFF,0x32,0xB5); // 0xD0,0x40,0xA0 -> 0xFF,0x32,0xB5
SETFRAMECOLOR( MONOCHROME_CUSTOM
- , GetRValue(monochrome)
- , GetGValue(monochrome)
- , GetBValue(monochrome)
+ , GetRValue(g_nMonochromeRGB)
+ , GetGValue(g_nMonochromeRGB)
+ , GetBValue(g_nMonochromeRGB)
);
SETFRAMECOLOR( MONOCHROME_CUSTOM_50
- , ((GetRValue(monochrome)/2) & 0xFF)
- , ((GetGValue(monochrome)/2) & 0xFF)
- , ((GetBValue(monochrome)/2) & 0xFF)
+ , ((GetRValue(g_nMonochromeRGB)/2) & 0xFF)
+ , ((GetGValue(g_nMonochromeRGB)/2) & 0xFF)
+ , ((GetBValue(g_nMonochromeRGB)/2) & 0xFF)
);
- // SEE: V_CreateLookup_MonoText
SETFRAMECOLOR( MONOCHROME_AMBER , 0xFF,0x80,0x01); // Used for Monochrome Hi-Res graphics not text!
SETFRAMECOLOR( MONOCHROME_GREEN , 0x00,0xC0,0x01); // Used for Monochrome Hi-Res graphics not text!
// BUG PALETTE COLLAPSE: WTF?? Soon as we set 0xFF,0xFF,0xFF we lose text colors?!?!
@@ -598,434 +424,9 @@ void V_CreateIdentityPalette ()
SETFRAMECOLOR(MAGENTA, 0xC7,0x34,0xFF); // FD Linards Tweaked 0xFF,0x00,0xFF -> 0xC7,0x34,0xFF
SETFRAMECOLOR(CYAN, 0x00,0xFF,0xFF); // FE
SETFRAMECOLOR(WHITE, 0xFF,0xFF,0xFF); // FF
-
- // IF WE ARE IN A PALETTIZED VIDEO MODE, CREATE AN IDENTITY PALETTE
- HWND window = GetDesktopWindow();
- HDC dc = GetDC(window);
-
- // int GetDeviceCaps( HDC, nIndex );
- int colors = GetDeviceCaps(dc,SIZEPALETTE); // 16/24/32bpp = 0
- int system = GetDeviceCaps(dc,NUMCOLORS); // 16/24/32bpp = -1
+}
#if 0
- // DD Full Screen Palette
- // Full Screen Debug Colors
- BYTE *pTmp;
-
- pTmp = ((BYTE*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER);
- pTmp += (DEBUG_COLORS_START * 4);
- Debug_UpdatePalette( pTmp );
-
- // GET THE PALETTE ENTRIES OF THE LOGO
- RGBQUAD aLogoPalette[256];
- ZeroMemory(aLogoPalette,sizeof(aLogoPalette));
- if (g_hLogoBitmap)
- {
- BYTE *pSrc = NULL;
- BITMAP bmp;
- PBITMAPINFO pbmi;
-// WORD cClrBits;
- // Retrieve the bitmap color format, width, and height.
- if (GetObject(g_hLogoBitmap, sizeof(BITMAP), (LPSTR)&bmp))
- {
- pSrc = (BYTE*) pbmi->bmiColors;
-
- // Logo uses 128 colors
- pTmp = ((BYTE*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER);
- pTmp += (LOGO_COLORS_START * 4);
- int iPal = 0;
- for( iPal = 0; iPal < 128; iPal++ )
- {
- *pTmp++ = *pSrc++;
- *pTmp++ = *pSrc++;
- *pTmp++ = *pSrc++;
- *pTmp++ = *pSrc++;
- }
- }
- }
-#endif
-
- int bRasterPalette = (GetDeviceCaps(dc,RASTERCAPS) & RC_PALETTE);
- if (bRasterPalette && (colors <= 256))
- {
- // GET THE PALETTE ENTRIES OF THE LOGO
- RGBQUAD aLogoPalette[256];
- ZeroMemory(aLogoPalette,sizeof(aLogoPalette));
- if (g_hLogoBitmap) {
- HDC memdc = CreateCompatibleDC(dc);
- SelectObject(memdc,g_hLogoBitmap);
- GetDIBColorTable(memdc,0,colors,aLogoPalette);
- DeleteDC(memdc);
- }
-
- // CREATE A PALETTE ENTRY ARRAY
- LOGPALETTE *paldata = (LOGPALETTE *)VirtualAlloc(
- NULL,
- sizeof(LOGPALETTE) + 256*sizeof(PALETTEENTRY),
- MEM_COMMIT,
- PAGE_READWRITE
- );
-
- paldata->palVersion = 0x300;
- paldata->palNumEntries = colors;
- GetSystemPaletteEntries(dc,0,colors,paldata->palPalEntry);
-
- // FILL IN THE PALETTE ENTRIES
- int paletteindex = 0;
- int logoindex = 0;
- int halftoneindex = 0;
-
- // COPY THE SYSTEM PALETTE ENTRIES AT THE BEGINNING OF THE PALETTE
- for (; paletteindex < system/2; paletteindex++)
- paldata->palPalEntry[paletteindex].peFlags = 0;
-
- // FILL IN THE MIDDLE PORTION OF THE PALETTE WITH OUR OWN COLORS
- for (int ourindex = DEEP_RED; ourindex <= NUM_COLOR_PALETTE; ourindex++) {
- paldata->palPalEntry[paletteindex].peRed = g_pFramebufferinfo->bmiColors[ourindex].rgbRed;
- paldata->palPalEntry[paletteindex].peGreen = g_pFramebufferinfo->bmiColors[ourindex].rgbGreen;
- paldata->palPalEntry[paletteindex].peBlue = g_pFramebufferinfo->bmiColors[ourindex].rgbBlue;
- paldata->palPalEntry[paletteindex].peFlags = PC_NOCOLLAPSE;
- paletteindex++;
- }
-
- for (; paletteindex < colors-system/2; paletteindex++) {
-
- // IF THIS PALETTE ENTRY IS NEEDED FOR THE LOGO, COPY IN THE LOGO COLOR
- if (aLogoPalette[logoindex].rgbRed &&
- aLogoPalette[logoindex].rgbGreen &&
- aLogoPalette[logoindex].rgbBlue)
- {
- paldata->palPalEntry[paletteindex].peRed = aLogoPalette[logoindex].rgbRed;
- paldata->palPalEntry[paletteindex].peGreen = aLogoPalette[logoindex].rgbGreen;
- paldata->palPalEntry[paletteindex].peBlue = aLogoPalette[logoindex].rgbBlue;
- }
-
- // OTHERWISE, ADD A HALFTONING COLOR, SO THAT OTHER APPLICATIONS
- // RUNNING IN THE BACKGROUND WILL HAVE SOME REASONABLE COLORS TO USE
- else
- {
- static BYTE halftonetable[6] = {32,64,96,160,192,224};
- paldata->palPalEntry[paletteindex].peRed = halftonetable[halftoneindex % 6];
- paldata->palPalEntry[paletteindex].peGreen = halftonetable[halftoneindex/6 % 6];
- paldata->palPalEntry[paletteindex].peBlue = halftonetable[halftoneindex/36 % 6];
- ++halftoneindex;
- }
-
- ++logoindex;
- paldata->palPalEntry[paletteindex].peFlags = PC_NOCOLLAPSE;
- }
-
- // COPY THE SYSTEM PALETTE ENTRIES AT THE END OF THE PALETTE
- for (; paletteindex < colors; paletteindex++)
- paldata->palPalEntry[paletteindex].peFlags = 0;
-
- // FILL THE FRAME BUFFER TABLE WITH COLORS FROM OUR PALETTE
- for (int iPal = 0; iPal < colors; iPal++) {
- g_pFramebufferinfo->bmiColors[ iPal ].rgbRed = paldata->palPalEntry[ iPal ].peRed;
- g_pFramebufferinfo->bmiColors[ iPal ].rgbGreen = paldata->palPalEntry[ iPal ].peGreen;
- g_pFramebufferinfo->bmiColors[ iPal ].rgbBlue = paldata->palPalEntry[ iPal ].peBlue;
- }
-
- // CREATE THE PALETTE
- g_hPalette = CreatePalette(paldata);
- VirtualFree(paldata,0,MEM_RELEASE);
- }
-
- ReleaseDC(window,dc);
-}
-
-//===========================================================================
-void V_CreateDIBSections ()
-{
- CopyMemory(g_pSourceHeader->bmiColors,g_pFramebufferinfo->bmiColors,256*sizeof(RGBQUAD));
-
- // CREATE THE DEVICE CONTEXT
- HWND window = GetDesktopWindow();
- HDC dc = GetDC(window);
- if (g_hDeviceDC)
- {
- DeleteDC(g_hDeviceDC);
- }
- g_hDeviceDC = CreateCompatibleDC(dc);
-
- // CREATE THE FRAME BUFFER DIB SECTION
- if (g_hDeviceBitmap)
- DeleteObject(g_hDeviceBitmap);
- g_hDeviceBitmap = CreateDIBSection(
- dc,
- g_pFramebufferinfo,
- DIB_RGB_COLORS,
- (LPVOID *)&g_pFramebufferbits,0,0
- );
- SelectObject(g_hDeviceDC,g_hDeviceBitmap);
-
- // CREATE THE SOURCE IMAGE DIB SECTION
- HDC sourcedc = CreateCompatibleDC(dc);
- ReleaseDC(window,dc);
- if (g_hSourceBitmap)
- DeleteObject(g_hSourceBitmap);
-
- g_hSourceBitmap = CreateDIBSection(
- sourcedc,
- g_pSourceHeader,
- DIB_RGB_COLORS,
- (LPVOID *)&g_pSourcePixels,0,0
- );
- SelectObject(sourcedc,g_hSourceBitmap);
-
- // 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*512); // 32 bytes/pixel * 16 colors = 512 bytes/row
-
- // First monochrome mode is seperate from others
- if ((g_eVideoType >= VT_COLOR_STANDARD) && (g_eVideoType < VT_MONO_AMBER))
- {
- V_CreateLookup_Text(sourcedc);
- V_CreateLookup_Lores();
-
- if ( g_eVideoType == VT_COLOR_TVEMU )
- V_CreateLookup_Hires();
- else
-#if HALF_DIM_SUPPORT
- V_CreateLookup_HiresHalfShiftDim();
-#else
- V_CreateLookup_HiResHalfPixel_Authentic();
-#endif
- V_CreateLookup_DoubleHires();
- }
- else
- {
- V_CreateLookup_MonoText(sourcedc);
- V_CreateLookup_MonoLoRes();
-
- switch (g_eVideoType)
- {
- case VT_MONO_AMBER : /* intentional fall-thru */
- case VT_MONO_GREEN : /* intentional fall-thru */
- case VT_MONO_WHITE : /* intentional fall-thru */
- case VT_MONO_HALFPIXEL_REAL : V_CreateLookup_MonoHiResHalfPixel_Real() ; break;
- default: V_CreateLookup_MonoHiRes(); break;
- }
- V_CreateLookup_MonoDoubleHiRes();
- }
- DeleteDC(sourcedc);
-}
-
-//===========================================================================
-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 (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;
- }
- }
-
- 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
-}
-
-//===========================================================================
-void V_CreateLookup_Hires ()
-{
- int iMonochrome = GetMonochromeIndex();
-
- // BYTE colorval[6] = {MAGENTA,BLUE,GREEN,ORANGE,BLACK,WHITE};
- // BYTE colorval[6] = {HGR_VIOLET,HGR_BLUE,HGR_GREEN,HGR_ORANGE,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_STANDARD = 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;
- }
- }
- }
- }
-}
-
-
-//===========================================================================
-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]);
-}
-
-
-//===========================================================================
-void V_CreateLookup_MonoDoubleHiRes ()
-{
- int iMonochrome = GetMonochromeIndex();
-
- for (int column = 0; column < 256; column++)
- {
- int coloffs = 10 * column;
- for (unsigned byteval = 0; byteval < 256; byteval++)
- {
- unsigned pattern = MAKEWORD(byteval,column);
- int y = byteval << 1;
- for (int x = 0; x < 10; x++)
- {
- BYTE colorval = pattern & (1 << (x+3)) ? iMonochrome : BLACK;
-
-#if 0
- if (g_eVideoType == VT_MONO_AUTHENTIC)
- {
- SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y ,colorval);
- SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y+1,BLACK);
- }
- else
-#endif
- {
- SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y ,colorval);
- SETSOURCEPIXEL(SRCOFFS_DHIRES+coloffs+x,y+1,colorval);
- }
- }
- }
- }
-}
-
-//===========================================================================
-void V_CreateLookup_MonoHiRes ()
-{
- const int iMonochrome = GetMonochromeIndex();
-
- for (int column = 0; column < 512; column += 16)
- {
- for (int y = 0; y < 512; y += 2) // optimization: Byte=0..FF, Row=Byte*2
- {
- unsigned val = (y >> 1); // iByte = (y / 2)
- for (int x = 0; x < 16; x += 2) // 8 pixels
- {
- BYTE colorval = (val & 1) ? iMonochrome : BLACK;
- val >>= 1;
- SETSOURCEPIXEL(SRCOFFS_HIRES+column+x ,y ,colorval);
- SETSOURCEPIXEL(SRCOFFS_HIRES+column+x+1,y ,colorval);
- {
- SETSOURCEPIXEL(SRCOFFS_HIRES+column+x ,y+1,colorval);
- SETSOURCEPIXEL(SRCOFFS_HIRES+column+x+1,y+1,colorval);
- }
- }
- }
- }
-}
-
-//===========================================================================
-void V_CreateLookup_HiResHalfPixel_Authentic () // 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
@@ -1057,7 +458,19 @@ Legend:
int x = 0;
int y = iByte << 1;
-/* Test cases
+/*
+Color Reference Tests:
+
+2000:D5 AA D5 AA D5 AA // blue blue blue
+2400:AA D5 2A 55 55 2A //+ red green violet
+// //= grey aqua violet
+
+2C00:AA D5 AA D5 2A 55 // red red green
+3000:2A 55 55 2A 55 2A //+ green violet violet
+// //= yellow pink grey
+
+Test cases
+==========
81 blue
2000:D5 AA D5 AA
82 orange
@@ -1073,31 +486,7 @@ Legend:
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
@@ -1111,8 +500,6 @@ Legend:
// 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
@@ -1124,138 +511,13 @@ Legend:
// 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 ((g_eVideoType == VT_COLOR_STANDARD) || ( !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 (
- (g_eVideoType == VT_COLOR_STANDARD) // Fill in colors in between white pixels
- || (g_eVideoType == 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;
- }
- }
- }
- }
-}
-
-//===========================================================================
-void V_CreateLookup_HiresHalfShiftDim ()
-{
- // 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 for fringe reduction on white hgr text -
- drawback: loss of color mix patterns in HGR mode.
- select g_eVideoType by index exclusion
- */
- if (
- (g_eVideoType == VT_COLOR_STANDARD) // Fill in colors in between white pixels
- || (g_eVideoType == 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
- color = ((odd ^ !(iPixel&1)) << 1) | hibit;
- }
-
- /*
Address Binary -> Displayed
2000:01 0---0001 -> 1 0 0 0 column 1
2400:81 1---0001 -> 1 0 0 0 half-pixel shift right
@@ -1271,122 +533,6 @@ void V_CreateLookup_HiresHalfShiftDim ()
@reference: see Beagle Bro's Disk: "Silicon Salad", File: DOUBLE HI-RES
Fortunately double-hires is supported via pixel doubling, so we can do half-pixel shifts ;-)
- */
- switch (color)
- {
- case CM_Violet:
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_VIOLET ); // HiresToPalIndex
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , DARK_MAGENTA ); // HiresDimmedIndex
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_VIOLET ); // HiresToPalIndex
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, DARK_MAGENTA ); // HiresDimmedIndex
- break;
-
- case CM_Blue :
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_BLUE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y , DARK_BLUE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_BLUE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y+1, DARK_BLUE );
- // Prevent column gaps
- if (hibit)
- {
- if (iPixel <= 2)
- {
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , DARK_BLUE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, DARK_BLUE );
- }
- }
- break;
-
- case CM_Green :
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_GREEN );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , DARK_GREEN );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_GREEN );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, DARK_GREEN );
- break;
-
- case CM_Orange:
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_ORANGE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y , BROWN ); // DARK_RED is a bit "too" red
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_ORANGE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+2,y+1, BROWN ); // DARK_RED is a bit "too" red
- // Prevent column gaps
- if (hibit)
- {
- if (iPixel <= 2)
- {
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , BROWN ); // DARK_RED is a bit "too" red
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, BROWN ); // DARK_RED is a bit "too" red
- }
- }
- break;
-
- case CM_Black :
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_BLACK );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_BLACK );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_BLACK );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_BLACK );
- break;
-
- case CM_White :
- // Don't dither / half-shift white, since DROL cutscene looks bad :(
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_WHITE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y , HGR_WHITE );
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_WHITE ); // LIGHT_GRAY <- for that half scan-line look
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj+1,y+1, HGR_WHITE ); // LIGHT_GRAY <- for that half scan-line look
- // Prevent column gaps
- if (hibit)
- {
- if (iPixel <= 2)
- {
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y , HGR_WHITE ); // LIGHT_GRAY HGR_GREY1
- SETSOURCEPIXEL(SRCOFFS_HIRES+coloffs+x+adj ,y+1, HGR_WHITE ); // LIGHT_GRAY HGR_GREY1
- }
- }
- break;
- default:
- break;
- }
- x += 2;
- }
- }
- }
- }
-}
-
-//===========================================================================
-void V_CreateLookup_MonoHiResHalfPixel_Real ()
-{
- int iMono = GetMonochromeIndex();
-
- for (int iColumn = 0; iColumn < 16; iColumn++)
- {
- int offset = iColumn << 5; // every column is 32 bytes wide
-
- for (unsigned iByte = 0; iByte < 256; iByte++)
- {
- int aPixels[11]; // c2 c1 b7 b6 b5 b4 b3 b2 b1 b0 c8 c4
-
- 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 >> 7) & 1; // ((iByte & 0x80) != 0);
- int x = 0;
- int y = iByte << 1;
-
- // Fixup missing pixels that normally have been scan-line shifted -- Apple "half-pixel" -- but cross 14-pixel boundaries.
- if( hibit )
- {
- /* Test Cases
// Games
Archon Logo
Gumball (at Machine)
@@ -1399,67 +545,8 @@ void V_CreateLookup_MonoHiResHalfPixel_Real ()
C050 C052 C057
2000:D0 80 00
2800:80 D0 00
- */
- if ( aPixels[1] ) // preceeding pixel on?
- {
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x ,y ,iMono); // first 7 HGR_BLUE
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x ,y+1,iMono); // first 7
-
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+16,y ,iMono); // second 7 HGR_ORANGE
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+16,y+1,iMono); // second 7
- }
- }
-
- 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 = aPixels[iPixel] ? iMono : HGR_BLACK;
-
- // Colors - Top/Bottom Left/Right
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj +hibit,y ,color); // TL
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj+1+hibit,y ,color); // BL
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj +hibit,y+1,color); // BL
- SETSOURCEPIXEL(SRCOFFS_HIRES+offset+x+adj+1+hibit,y+1,color); // BR
- x += 2;
- }
- }
- }
- }
-}
-
-//===========================================================================
-void V_CreateLookup_MonoLoRes () {
- int iMonochrome = GetMonochromeIndex();
-
- for (int color = 0; color < 16; color++)
- {
- for (int x = 0; x < 16; x++)
- {
- for (int y = 0; y < 16; y++)
- {
- BYTE colorval = (color >> (x & 3) & 1) ? iMonochrome : BLACK;
-#if 0
- if (g_eVideoType == VT_MONO_AUTHENTIC)
- {
- if (y & 1)
- SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,BLACK);
- else
- SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,colorval);
- }
- else
+*/
#endif
- {
- SETSOURCEPIXEL(SRCOFFS_LORES+x,(color << 4)+y,colorval);
- }
- }
- }
- }
-}
-
// google: CreateDIBPatternBrushPt
// http://209.85.141.104/search?q=cache:mB3htrQGW8kJ:bookfire.net/wince/wince-programming-ms-press2/source/prowice/ch02e.htm
@@ -1471,57 +558,6 @@ struct BRUSHBMP
BYTE bBits[64];
};
-HBRUSH V_CreateCustomBrush(COLORREF nColor)
-{
- BRUSHBMP brbmp;
- BYTE *pBytes;
- int i;
- //DWORD dwBits[6][2] =
- //{
- // {0x000000ff,0x00000000}, // HS_HORIZONTAL 0 /* ----- */
- // {0x10101010,0x10101010}, // HS_VERTICAL 1 /* ||||| */
- // {0x01020408,0x10204080}, // HS_FDIAGONAL 2 /* \\\\\ */
- // {0x80402010,0x08040201}, // HS_BDIAGONAL 3 /* ///// */
- // {0x101010ff,0x10101010}, // HS_CROSS 4 /* +++++ */
- // {0x81422418,0x18244281}, // HS_DIAGCROSS 5 /* xxxxx */
- //};
- // if ((HatchStyle < 0) || (HatchStyle > 6))
- // return 0;
-
- int HatchStyle = 0;
- DWORD dwBits[1][2] =
- {
-// {0xff00ff00,0xff00ff00} // every other scan line
- {0xFFFFFFFF,0xFFFFFFFF}
- };
-
- memset (&brbmp, 0, sizeof (brbmp));
-
- brbmp.bmi.biSize = sizeof (BITMAPINFOHEADER);
- brbmp.bmi.biWidth = 8;
- brbmp.bmi.biHeight = 8;
- brbmp.bmi.biPlanes = 1;
- brbmp.bmi.biBitCount = 1;
- brbmp.bmi.biClrUsed = 2;
- brbmp.bmi.biClrImportant = 2;
-
- // Initialize the palette of the bitmap.
- brbmp.dwPal[0] = PALETTERGB(0x00,0x00,0x00);
- brbmp.dwPal[1] = PALETTERGB(
- (BYTE)((nColor >> 16) & 0xff),
- (BYTE)((nColor >> 8) & 0xff),
- (BYTE)((nColor >> 0) & 0xff));
-
- // Write the hatch data to the bitmap.
- pBytes = (BYTE *)&dwBits[HatchStyle];
- for (i = 0; i < 8; i++)
- brbmp.bBits[i*4] = *pBytes++;
-
- // Return the handle of the brush created.
- return CreateDIBPatternBrushPt (&brbmp, DIB_RGB_COLORS);
-}
-
-
//===========================================================================
static void CreateLookup_TextCommon(HDC hDstDC, DWORD rop)
@@ -1530,9 +566,9 @@ static void CreateLookup_TextCommon(HDC hDstDC, DWORD rop)
HDC hSrcDC = CreateCompatibleDC(hDstDC);
hCharBitmap[0] = LoadBitmap(g_hInstance,TEXT("CHARSET40"));
- hCharBitmap[1] = LoadBitmap(g_hInstance,TEXT("CHARSET82"));
- hCharBitmap[2] = LoadBitmap(g_hInstance,TEXT("CHARSET8C")); // FIXME: Pravets 8M probably has the same charset as Pravets 8C
- hCharBitmap[3] = LoadBitmap(g_hInstance,TEXT("CHARSET8C"));
+ hCharBitmap[1] = LoadBitmap(g_hInstance,TEXT("CHARSET82")); //82
+ hCharBitmap[2] = LoadBitmap(g_hInstance,TEXT("CHARSET82")); //8M
+ hCharBitmap[3] = LoadBitmap(g_hInstance,TEXT("CHARSET8C")); //8A
SelectObject(hSrcDC, hCharBitmap[g_nCharsetType]);
// TODO: Update with APPLE_FONT_Y_ values
@@ -1545,51 +581,6 @@ static void CreateLookup_TextCommon(HDC hDstDC, DWORD rop)
DeleteObject(hCharBitmap[i]);
}
-static void V_CreateLookup_Text(HDC hDstDC)
-{
- CreateLookup_TextCommon(hDstDC, SRCCOPY);
-}
-
-static void V_CreateLookup_MonoText(HDC hDstDC)
-{
- HBRUSH hBrush;
- switch (g_eVideoType)
- {
- case VT_MONO_AMBER: hBrush = CreateSolidBrush(RGB(0xFF,0x80,0x00)); break;
- case VT_MONO_GREEN: hBrush = CreateSolidBrush(RGB(0x00,0xC0,0x00)); break;
- case VT_MONO_WHITE: hBrush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF)); break;
- default : hBrush = CreateSolidBrush(monochrome); break;
- }
-
- SelectObject(hDstDC, hBrush);
-
- // NB. MERGECOPY (not SRCCOPY) to merge the src with the colour of the dst's selected brush
- CreateLookup_TextCommon(hDstDC, MERGECOPY);
-
- SelectObject(hDstDC,GetStockObject(NULL_BRUSH));
- DeleteObject(hBrush);
-}
-
-
-//===========================================================================
-void SetLastDrawnImage ()
-{
- memcpy(vidlastmem+0x400,g_pTextBank0,0x400);
-
- if (SW_HIRES)
- memcpy(vidlastmem+0x2000,g_pHiresBank0,0x2000);
- if (SW_DHIRES && SW_HIRES)
- memcpy(vidlastmem,g_pHiresBank1,0x2000);
- else if (SW_80COL) // Don't test for !SW_HIRES, as some 80-col text routines have SW_HIRES set (Bug #8300)
- memcpy(vidlastmem,g_pTextBank1,0x400);
-
- int loop;
- for (loop = 0; loop < 256; loop++)
- {
- *(memdirty+loop) &= ~2;
- }
-}
-
//===========================================================================
static inline int GetOriginal2EOffset(BYTE ch)
@@ -1598,435 +589,7 @@ static inline int GetOriginal2EOffset(BYTE ch)
return !IsOriginal2E() || !g_nAltCharSetOffset || (ch<0x40) || (ch>0x5F) ? 0 : -g_nAltCharSetOffset;
}
-bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset)
-{
- BYTE ch = *(g_pTextBank0+offset);
- bool bCharChanged = (ch != *(vidlastmem+offset+0x400) || g_VideoForceFullRedraw);
-
- // FLASHing chars:
- // - FLASHing if:Alt Char Set is OFF && 0x40<=char<=0x7F
- // - The inverse of this char is located at: char+0x40
- bool bCharFlashing = (g_nAltCharSetOffset == 0) && (ch >= 0x40) && (ch <= 0x7F);
-
- if(bCharChanged || (bCharFlashing && g_bTextFlashFlag))
- {
- bool bInvert = bCharFlashing ? g_bTextFlashState : false;
-
- CopySource(xpixel,ypixel,
- APPLE_FONT_WIDTH, APPLE_FONT_HEIGHT,
- (IS_APPLE2 ? SRCOFFS_IIPLUS : SRCOFFS_40COL) + ((ch & 0x0F) << 4),
- (ch & 0xF0) + g_nAltCharSetOffset + GetOriginal2EOffset(ch) + (bInvert ? 0x40 : 0x00));
-
- return true;
- }
-
- return false;
-}
-
-inline bool _Update80ColumnCell( BYTE c, const int xPixel, const int yPixel, bool bCharFlashing )
-{
- bool bInvert = bCharFlashing ? g_bTextFlashState : false;
-
- CopySource(
- xPixel, yPixel,
- (APPLE_FONT_WIDTH / 2), APPLE_FONT_HEIGHT,
- SRCOFFS_80COL + ((c & 0x0F) << 3),
- (c & 0xF0) + g_nAltCharSetOffset + GetOriginal2EOffset(c) + (bInvert ? 0x40 : 0x00));
-
- return true;
-}
-
//===========================================================================
-bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset)
-{
- bool bDirty = false;
-
-#if FLASH_80_COL
- BYTE c1 = *(g_pTextBank1 + offset); // aux
- BYTE c0 = *(g_pTextBank0 + offset); // main
-
- bool bC1Changed = (c1 != *(vidlastmem + offset + 0) || g_VideoForceFullRedraw);
- bool bC0Changed = (c0 != *(vidlastmem + offset + 0x400) || g_VideoForceFullRedraw);
-
- bool bC1Flashing = (g_nAltCharSetOffset == 0) && (c1 >= 0x40) && (c1 <= 0x7F);
- bool bC0Flashing = (g_nAltCharSetOffset == 0) && (c0 >= 0x40) && (c0 <= 0x7F);
-
- if (bC1Changed || (bC1Flashing && g_bTextFlashFlag))
- bDirty = _Update80ColumnCell( c1, xpixel, ypixel, bC1Flashing );
-
- if (bC0Changed || (bC0Flashing && g_bTextFlashFlag))
- bDirty |= _Update80ColumnCell( c0, xpixel + 7, ypixel, bC0Flashing );
-
-#else
- BYTE auxval = *(g_pTextBank1 + offset); // aux
- BYTE mainval = *(g_pTextBank0 + offset); // main
-
- if ((auxval != *(vidlastmem+offset)) ||
- (mainval != *(vidlastmem+offset+0x400)) ||
- g_VideoForceFullRedraw)
- {
- CopySource(xpixel,ypixel,
- (APPLE_FONT_WIDTH / 2), APPLE_FONT_HEIGHT,
- SRCOFFS_80COL + ((auxval & 15)<<3),
- ((auxval>>4)<<4) + g_nAltCharSetOffset);
-
- CopySource(xpixel+7,ypixel,
- (APPLE_FONT_WIDTH / 2), APPLE_FONT_HEIGHT,
- SRCOFFS_80COL + ((mainval & 15)<<3),
- ((mainval>>4)<<4) + g_nAltCharSetOffset );
-
- bDirty = true;
- }
-#endif
-
- return bDirty;
-}
-
-//===========================================================================
-bool UpdateDHiResCell (int x, int y, int xpixel, int ypixel, int offset)
-{
- bool bDirty = false;
- int yoffset = 0;
- while (yoffset < 0x2000) {
- BYTE byteval1 = (x > 0) ? *(g_pHiresBank0+offset+yoffset-1) : 0;
- BYTE byteval2 = *(g_pHiresBank1 +offset+yoffset);
- BYTE byteval3 = *(g_pHiresBank0+offset+yoffset);
- BYTE byteval4 = (x < 39) ? *(g_pHiresBank1 +offset+yoffset+1) : 0;
- if ((byteval2 != *(vidlastmem+offset+yoffset)) ||
- (byteval3 != *(vidlastmem+offset+yoffset+0x2000)) ||
- ((x > 0) && ((byteval1 & 0x70) != (*(vidlastmem+offset+yoffset+0x1FFF) & 0x70))) ||
- ((x < 39) && ((byteval4 & 0x07) != (*(vidlastmem+offset+yoffset+ 1) & 0x07))) ||
- g_VideoForceFullRedraw) {
- 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(xpixel+PIXEL,ypixel+(yoffset >> 9),7,2,
- SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR,LOBYTE(VALUE)<<1);
-#undef PIXEL
-#define PIXEL 7
- CopySource(xpixel+PIXEL,ypixel+(yoffset >> 9),7,2,
- SRCOFFS_DHIRES+10*HIBYTE(VALUE)+COLOR,LOBYTE(VALUE)<<1);
-#undef PIXEL
-#undef COLOR
-#undef VALUE
- bDirty = true;
- }
- yoffset += 0x400;
- }
-
- return bDirty;
-}
-
-/*
-
-Color Reference Tests:
-
-2000:D5 AA D5 AA D5 AA // blue blue blue
-2400:AA D5 2A 55 55 2A //+ red green violet
-// //= grey aqua violet
-
-2C00:AA D5 AA D5 2A 55 // red red green
-3000:2A 55 55 2A 55 2A //+ green violet violet
-// //= yellow pink grey
-
-*/
-
-//===========================================================================
-BYTE MixColors(BYTE c1, BYTE c2)
-{
- // For tv emulation HGR Video Mode
- #define COMBINATION(c1,c2,ref1,ref2) (((c1)==(ref1)&&(c2)==(ref2)) || ((c1)==(ref2)&&(c2)==(ref1)))
-
- if (c1 == c2)
- return c1;
- if (COMBINATION(c1,c2,HGR_BLUE,HGR_ORANGE))
- return HGR_GREY1;
- else if (COMBINATION(c1,c2,HGR_GREEN,HGR_VIOLET))
- return HGR_GREY2;
- else if (COMBINATION(c1,c2,HGR_ORANGE,HGR_GREEN))
- return HGR_YELLOW;
- else if (COMBINATION(c1,c2,HGR_BLUE,HGR_GREEN))
- return HGR_AQUA;
- else if (COMBINATION(c1,c2,HGR_BLUE,HGR_VIOLET))
- return HGR_PURPLE;
- else if (COMBINATION(c1,c2,HGR_ORANGE,HGR_VIOLET))
- return HGR_PINK;
- else
- return MONOCHROME_CUSTOM; // visible failure indicator
-
-#undef COMBINATION
-}
-
-
-//===========================================================================
-void CreateColorMixMap()
-{
- // For tv emulation HGR Video Mode
- #define FROM_NEIGHBOUR 0x00
-
- int t,m,b;
- BYTE cTop, cMid, cBot;
- WORD mixTop, mixBot;
-
-#define MIX_THRESHOLD 0x12 // bottom 2 HGR colors
-
- for (t=0; t<6; t++)
- for (m=0; m<6; m++)
- for (b=0; b<6; b++) {
- cTop = t | 0x10;
- cMid = m | 0x10;
- cBot = b | 0x10;
- if (cMid < MIX_THRESHOLD) {
- mixTop = mixBot = cMid;
- } else {
- if (cTop < MIX_THRESHOLD) {
- mixTop = FROM_NEIGHBOUR;
- } else {
- mixTop = MixColors(cMid,cTop);
- }
- if (cBot < MIX_THRESHOLD) {
- mixBot = FROM_NEIGHBOUR;
- } else {
- mixBot = MixColors(cMid,cBot);
- }
- if (mixTop == FROM_NEIGHBOUR && mixBot != FROM_NEIGHBOUR) {
- mixTop = mixBot;
- } else if (mixBot == FROM_NEIGHBOUR && mixTop != FROM_NEIGHBOUR) {
- mixBot = mixTop;
- } else if (mixBot == FROM_NEIGHBOUR && mixTop == FROM_NEIGHBOUR) {
- mixBot = mixTop = cMid;
- }
- }
- colormixmap[t][m][b] = (mixTop << 8) | mixBot;
- }
-#undef FROM_NEIGHBOUR
-}
-
-//===========================================================================
-void __stdcall MixColorsVertical(int matx, int maty)
-{
- // For tv emulation HGR Video Mode
-
- WORD twoHalfPixel;
- int bot1idx, bot2idx;
-
- if (SW_MIXED && maty > 159) {
- if (maty < 161) {
- bot1idx = hgrpixelmatrix[matx][maty+1] & 0x0F;
- bot2idx = 0;
- } else {
- bot1idx = bot2idx = 0;
- }
- } else {
- bot1idx = hgrpixelmatrix[matx][maty+1] & 0x0F;
- bot2idx = hgrpixelmatrix[matx][maty+2] & 0x0F;
- }
-
- twoHalfPixel = colormixmap[hgrpixelmatrix[matx][maty-2] & 0x0F]
- [hgrpixelmatrix[matx][maty-1] & 0x0F]
- [hgrpixelmatrix[matx][maty ] & 0x0F];
- colormixbuffer[0] = (twoHalfPixel & 0xFF00) >> 8;
- colormixbuffer[1] = twoHalfPixel & 0x00FF;
-
- twoHalfPixel = colormixmap[hgrpixelmatrix[matx][maty-1] & 0x0F]
- [hgrpixelmatrix[matx][maty ] & 0x0F]
- [bot1idx];
- colormixbuffer[2] = (twoHalfPixel & 0xFF00) >> 8;
- colormixbuffer[3] = twoHalfPixel & 0x00FF;
-
- twoHalfPixel = colormixmap[hgrpixelmatrix[matx][maty ] & 0x0F]
- [bot1idx]
- [bot2idx];
- colormixbuffer[4] = (twoHalfPixel & 0xFF00) >> 8;
- colormixbuffer[5] = twoHalfPixel & 0x00FF;
-}
-
-//===========================================================================
-
-static inline void __stdcall CopyMixedSource8(int x, int y, int sourcex, int sourcey)
-{
- // For tv emulation HGR Video Mode
-
- const BYTE* const currsourceptr = g_aSourceStartofLine[sourcey]+sourcex;
- BYTE* const currdestptr = g_aFrameBufferOffset[y*2] + (x*2);
-
- const int matx = x;
- const int maty = HGR_MATRIX_YOFFSET + y;
- const int hgrlinesabove = (y > 0) ? 1 : 0;
- const int hgrlinesbelow = SW_MIXED ? ((y < 159)? 1:0) : ((y < 191)? 1:0);
- const int istart = 2 - (hgrlinesabove*2);
- const int iend = 3 + (hgrlinesbelow*2);
-
- // transfer 7 pixels (i.e. the visible part of an apple hgr-byte) from row to pixelmatrix
- for (int count = 0, bufxoffset = 0; count < 7; count++, bufxoffset += 2)
- {
- hgrpixelmatrix[matx+count][maty] = *(currsourceptr+bufxoffset);
-
- // color mixing between adjacent scanlines at current x position
- MixColorsVertical(matx+count, maty);
-
- // transfer up to 6 mixed (half-)pixels of current column to framebuffer
- BYTE* currptr = currdestptr+bufxoffset;
- if (hgrlinesabove)
- currptr += g_nFrameBufferPitch * 2;
-
- for (int i = istart; i <= iend; currptr -= g_nFrameBufferPitch, i++)
- {
- if (g_uHalfScanLines && (i & 1))
- *currptr = *(currptr+1) = 0; // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows)
- else
- *currptr = *(currptr+1) = colormixbuffer[i];
- }
- }
-}
-
-// For tv emulation HGR Video Mode
-static void __stdcall CopyMixedSource(int x, int y, int sourcex, int sourcey)
-{
- if (!g_bIsFullScreen || !GetFullScreen32Bit())
- {
- CopyMixedSource8(x,y,sourcex,sourcey);
- return;
- }
-
- const BYTE* const currsourceptr = g_aSourceStartofLine[sourcey]+sourcex;
- UINT32* const currdestptr = (UINT32*) (g_aFrameBufferOffset[ y*2 ] + (x*2)*sizeof(UINT32));
-
- const int matx = x;
- const int maty = HGR_MATRIX_YOFFSET + y;
- const int hgrlinesabove = (y > 0) ? 1 : 0;
- const int hgrlinesbelow = SW_MIXED ? ((y < 159)? 1:0) : ((y < 191)? 1:0);
- const int istart = 2 - (hgrlinesabove*2);
- const int iend = 3 + (hgrlinesbelow*2);
-
- // transfer 7 pixels (i.e. the visible part of an apple hgr-byte) from row to pixelmatrix
- for (int count = 0, bufxoffset = 0; count < 7; count++, bufxoffset += 2)
- {
- hgrpixelmatrix[matx+count][maty] = *(currsourceptr+bufxoffset);
-
- // color mixing between adjacent scanlines at current x position
- MixColorsVertical(matx+count, maty);
-
- // transfer up to 6 mixed (half-)pixels of current column to framebuffer
- UINT32* currptr = currdestptr+bufxoffset;
- if (hgrlinesabove)
- currptr += (g_nFrameBufferPitch / sizeof(UINT32)) * 2;
-
- for (int i = istart; i <= iend; currptr -= g_nFrameBufferPitch/sizeof(UINT32), i++)
- {
- if (g_uHalfScanLines && (i & 1))
- {
- // 50% Half Scan Line clears every odd scanline (and SHIFT+PrintScreen saves only the even rows)
- *currptr = *(currptr+1) = 0;
- }
- else
- {
- const RGBQUAD& rRGB = g_pFramebufferinfo->bmiColors[ colormixbuffer[i] ];
- const UINT32 rgb = (((UINT32)rRGB.rgbRed)<<16) | (((UINT32)rRGB.rgbGreen)<<8) | ((UINT32)rRGB.rgbBlue);
- *currptr = *(currptr+1) = rgb;
- }
- }
- }
-}
-
-//===========================================================================
-bool UpdateHiResCell (int x, int y, int xpixel, int ypixel, int offset)
-{
- bool bDirty = false;
- int yoffset = 0;
- while (yoffset < 0x2000)
- {
-#if 0 // TRACE_VIDEO
- static char sText[ 256 ];
- sprintf(sText, "x: %3d y: %3d xpix: %3d ypix: %3d offset: %04X \n"
- , x, y, xpixel, ypixel, offset, yoffset
- );
- OutputDebugString("sText");
-#endif
-
- BYTE byteval1 = (x > 0) ? *(g_pHiresBank0+offset+yoffset-1) : 0;
- BYTE byteval2 = *(g_pHiresBank0+offset+yoffset );
- BYTE byteval3 = (x < 39) ? *(g_pHiresBank0+offset+yoffset+1) : 0;
- if ((byteval2 != *(vidlastmem+offset+yoffset+0x2000)) ||
- ((x > 0) && ((byteval1 & 0x60) != (*(vidlastmem+offset+yoffset+0x1FFF) & 0x60))) ||
- ((x < 39) && ((byteval3 & 0x03) != (*(vidlastmem+offset+yoffset+0x2001) & 0x03))) ||
- g_VideoForceFullRedraw)
- {
-#define COLOFFS (((byteval1 & 0x60) << 2) | \
- ((byteval3 & 0x03) << 5))
- if (g_eVideoType == VT_COLOR_TVEMU)
- {
- CopyMixedSource(
- xpixel >> 1, (ypixel+(yoffset >> 9)) >> 1,
- SRCOFFS_HIRES+COLOFFS+((x & 1) << 4), (((int)byteval2) << 1)
- );
- }
- else
- {
- CopySource(
- xpixel,ypixel+(yoffset >> 9),
- 14,2, // 2x upscale: 280x192 -> 560x384
- SRCOFFS_HIRES+COLOFFS+((x & 1) << 4), (((int)byteval2) << 1)
- );
- }
-#undef COLOFFS
- bDirty = true;
- }
- yoffset += 0x400;
- }
-
- return bDirty;
-}
-
-//===========================================================================
-bool UpdateLoResCell (int x, int y, int xpixel, int ypixel, int offset)
-{
- BYTE val = *(g_pTextBank0+offset);
- if ((val != *(vidlastmem+offset+0x400)) || g_VideoForceFullRedraw)
- {
- CopySource(xpixel,ypixel,
- 14,8,
- SRCOFFS_LORES+((x & 1) << 1),((val & 0xF) << 4));
- CopySource(xpixel,ypixel+8,
- 14,8,
- SRCOFFS_LORES+((x & 1) << 1),(val & 0xF0));
- return true;
- }
-
- return false;
-}
-
-//===========================================================================
-
-#define ROL_NIB(x) ( (((x)<<1)&0xF) | (((x)>>3)&1) )
-
-bool UpdateDLoResCell (int x, int y, int xpixel, int ypixel, int offset)
-{
- BYTE auxval = *(g_pTextBank1 + offset);
- BYTE mainval = *(g_pTextBank0 + offset);
-
- if ( (auxval != *(vidlastmem+offset)) ||
- (mainval != *(vidlastmem+offset+0x400)) ||
- g_VideoForceFullRedraw
- )
- {
- const BYTE auxval_h = auxval >> 4;
- const BYTE auxval_l = auxval & 0xF;
- auxval = (ROL_NIB(auxval_h)<<4) | ROL_NIB(auxval_l); // Fix Bug #14879
-
- CopySource( xpixel,ypixel , 7,8,SRCOFFS_LORES+((x & 1) << 1),((auxval & 0xF) << 4));
- CopySource( xpixel,ypixel+8, 7,8,SRCOFFS_LORES+((x & 1) << 1),(auxval & 0xF0));
- //
- CopySource( xpixel+7,ypixel , 7,8, SRCOFFS_LORES+((x & 1) << 1),((mainval & 0xF) << 4));
- CopySource( xpixel+7,ypixel+8, 7,8, SRCOFFS_LORES+((x & 1) << 1),(mainval & 0xF0));
- return true;
- }
-
- return false;
-}
-
//
// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE -----
@@ -2097,6 +660,7 @@ void VideoBenchmark () {
// GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO
// SIMULATE THE ACTIVITY OF AN AVERAGE GAME
DWORD totaltextfps = 0;
+
g_uVideoMode = VF_TEXT;
FillMemory(mem+0x400,0x400,0x14);
VideoRedrawScreen();
@@ -2109,7 +673,7 @@ void VideoBenchmark () {
FillMemory(mem+0x400,0x400,0x14);
else
CopyMemory(mem+0x400,mem+((cycle & 2) ? 0x4000 : 0x6000),0x400);
- VideoRefreshScreen();
+ VideoRefreshScreen(0);
if (cycle++ >= 3)
cycle = 0;
totaltextfps++;
@@ -2131,7 +695,7 @@ void VideoBenchmark () {
FillMemory(mem+0x2000,0x2000,0x14);
else
CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000);
- VideoRefreshScreen();
+ VideoRefreshScreen(0);
if (cycle++ >= 3)
cycle = 0;
totalhiresfps++;
@@ -2222,7 +786,7 @@ void VideoBenchmark () {
FillMemory(mem+0x2000,0x2000,0xAA);
else
CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000);
- VideoRefreshScreen();
+ VideoRedrawScreen(); // VideoRefreshScreen();
if (cycle++ >= 3)
cycle = 0;
realisticfps++;
@@ -2317,27 +881,31 @@ BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles)
*/
-BYTE VideoCheckVbl (WORD, WORD, BYTE, BYTE, ULONG uExecutedCycles)
+BYTE VideoCheckVbl ( ULONG uExecutedCycles )
{
bool bVblBar = VideoGetVbl(uExecutedCycles);
+ // NTSC: It is tempting to replace with
+ // bool bVblBar = NTSC_VideoIsVbl();
+ // But this breaks "ANSI STORY" intro center fade
BYTE r = KeybGetKeycode();
return (r & ~0x80) | (bVblBar ? 0x80 : 0);
}
+// This is called from PageConfig
//===========================================================================
-void VideoChooseColor ()
+void VideoChooseMonochromeColor ()
{
CHOOSECOLOR cc;
ZeroMemory(&cc,sizeof(CHOOSECOLOR));
cc.lStructSize = sizeof(CHOOSECOLOR);
cc.hwndOwner = g_hFrameWindow;
- cc.rgbResult = monochrome;
+ cc.rgbResult = g_nMonochromeRGB;
cc.lpCustColors = customcolors + 1;
cc.Flags = CC_RGBINIT | CC_SOLIDCOLOR;
if (ChooseColor(&cc))
{
- monochrome = cc.rgbResult;
+ g_nMonochromeRGB = cc.rgbResult;
VideoReinitialize();
if ((g_nAppMode != MODE_LOGO) && (g_nAppMode != MODE_DEBUG))
{
@@ -2383,7 +951,7 @@ void VideoDestroy () {
//===========================================================================
-void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale)
+static void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale)
{
HDC hSrcDC = CreateCompatibleDC( hDstDC );
SelectObject( hSrcDC, g_hLogoBitmap );
@@ -2403,51 +971,50 @@ void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int
//===========================================================================
void VideoDisplayLogo ()
{
- int xoff = 0, yoff = 0, scale = 0;
+ int nLogoX = 0, nLogoY = 0;
+ int scale = GetViewportScale();
+
HDC hFrameDC = FrameGetDC();
// DRAW THE LOGO
- HBRUSH brush = CreateSolidBrush(PALETTERGB(0x70,0x30,0xE0));
-
- SelectObject(hFrameDC, brush);
SelectObject(hFrameDC, GetStockObject(NULL_PEN));
- int nViewportCX, nViewportCY;
- GetViewportCXCY(nViewportCX, nViewportCY);
- Rectangle(hFrameDC, 0, 0, nViewportCX+1, nViewportCY+1);
-
if (g_hLogoBitmap)
{
BITMAP bm;
if (GetObject(g_hLogoBitmap, sizeof(bm), &bm))
{
- scale = nViewportCX / bm.bmWidth;
- if (nViewportCY / bm.bmHeight < scale)
- scale = nViewportCY / bm.bmHeight;
+ nLogoX = (g_nViewportCX - scale*bm.bmWidth )/2;
+ nLogoY = (g_nViewportCY - scale*bm.bmHeight)/2;
- if (scale > 0)
+ if( g_bIsFullScreen )
{
- if (nViewportCX > bm.bmWidth)
- xoff = (nViewportCX - (scale * bm.bmWidth)) / 2;
- if (nViewportCY > bm.bmHeight)
- yoff = (nViewportCY - (scale * bm.bmHeight)) / 2;
-
- VideoDrawLogoBitmap( hFrameDC, xoff, yoff, bm.bmWidth, bm.bmHeight, scale );
+#if 0
+ // Draw Logo at top of screen so when the Apple display is refreshed it will automagically clear it
+ nLogoX = 0;
+ nLogoY = 0;
+#else
+ nLogoX += GetFullScreenOffsetX();
+ nLogoY += GetFullScreenOffsetY();
+#endif
}
+ VideoDrawLogoBitmap( hFrameDC, nLogoX, nLogoY, bm.bmWidth, bm.bmHeight, scale );
}
}
// DRAW THE VERSION NUMBER
+ TCHAR sFontName[] = TEXT("Arial");
HFONT font = CreateFont(-20,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
VARIABLE_PITCH | 4 | FF_SWISS,
- TEXT("Arial"));
+ sFontName );
SelectObject(hFrameDC,font);
SetTextAlign(hFrameDC,TA_RIGHT | TA_TOP);
SetBkMode(hFrameDC,TRANSPARENT);
char szVersion[ 64 ] = "";
sprintf( szVersion, "Version %s", VERSIONSTRING );
+ int xoff = GetFullScreenOffsetX(), yoff = GetFullScreenOffsetY();
#define DRAWVERSION(x,y,c) \
SetTextColor(hFrameDC,c); \
@@ -2473,92 +1040,147 @@ void VideoDisplayLogo ()
DRAWVERSION( 0, -356*scale,RGB(0xFF,0x00,0xFF));
#endif
+// NTSC Alpha Version
+ DeleteObject(font);
+/*
+ font = CreateFontA(
+ -48,0,0,0,FW_NORMAL,0,0,0,ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
+ VARIABLE_PITCH | 4 | FF_SWISS,
+ sFontName)
+ );
+*/
+ PLOGFONT pLogFont = (PLOGFONT) LocalAlloc(LPTR, sizeof(LOGFONT));
+ int angle = (int)(7.5 * 10); // 3600 = 360 degrees
+ pLogFont->lfHeight = -48;
+ pLogFont->lfWeight = FW_NORMAL;
+ pLogFont->lfEscapement = angle;
+ pLogFont->lfOrientation = angle;
+ SetTextAlign(hFrameDC,TA_BASELINE);
+
+ font = CreateFontIndirect( pLogFont );
+ HGDIOBJ hFontPrev = SelectObject(hFrameDC, font);
+
+ SelectObject(hFrameDC,font);
+// sprintf( szVersion, "NTSC Alpha v14 HorzClock" );
+// sprintf( szVersion, "NTSC Alpha v15 Fraps" );
+// sprintf( szVersion, "NTSC Alpha v16 Palette" );
+// sprintf( szVersion, "NTSC Alpha v17 BMP Palette" );
+ sprintf( szVersion, "NTSC Alpha v18" );
+
+ xoff = -g_nViewportCX + g_nViewportCX/6 + GetFullScreenOffsetX();
+ yoff = -g_nViewportCY/16 + GetFullScreenOffsetY();
+ DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00));
+ DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00));
+ DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF));
+
+ sprintf( szVersion, "Blurry 80-col Text" );
+ xoff = -g_nViewportCX + g_nViewportCX/6 + GetFullScreenOffsetX();
+ yoff = +g_nViewportCY/16 + GetFullScreenOffsetY();
+ DRAWVERSION( 0, 0,RGB(0x00,0x00,0x00));
+ DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00));
+ DRAWVERSION( 2, 2,RGB(0xFF,0x00,0xFF));
+
+ LocalFree((LOCALHANDLE)pLogFont);
+ SelectObject(hFrameDC,hFontPrev);
+// NTSC END
+
#undef DRAWVERSION
- FrameReleaseDC();
- DeleteObject(brush);
+ FrameReleaseVideoDC();
+
DeleteObject(font);
}
//===========================================================================
-void VideoRealizePalette(HDC dc)
+
+// AZTEC.DSK: From boot to 'Press any key' (Release build)
+// . 66s always update every frame
+// . 15s only update if any video memory (main/aux, text/hgr, pages1&2) has changed
+// . 10s only update if HIRES changes (17s for Debug build)
+// . ~9s no update during full-speed (but IBIZA.DSK doesn't show anything!)
+
+void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInvalidate /*=false*/)
{
-#if 0
- if( g_bIsFullScreen )
+ static bool bValid = false;
+
+ if (bInvalidate)
{
- if( !g_pDDPal )
+ bValid = false;
+ return;
+ }
+
+ //
+
+ static BYTE text_main[1024*2] = {0}; // page1 & 2
+ static BYTE text_aux[1024*2] = {0}; // page1 & 2
+ static BYTE hgr_main[8192*2] = {0}; // page1 & 2
+ static BYTE hgr_aux[8192*2] = {0}; // page1 & 2
+
+ bool bRedraw = true; // Always redraw for bValid==false (ie. just entered full-speed mode)
+
+ if (bValid)
+ {
+ if ((g_uVideoMode&(VF_DHIRES|VF_HIRES|VF_TEXT|VF_MIXED)) == VF_HIRES)
{
- PALETTEENTRY aPal[256];
-
- BYTE *pSrc = ((BYTE*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER);
- BYTE *pDst = ((BYTE*)aPal);
-
- int iPal;
- for(iPal = 0; iPal < 256; iPal++ )
- {
- *(pDst + 0) = *(pSrc + 2); // BGR -> RGB
- *(pDst + 1) = *(pSrc + 1);
- *(pDst + 2) = *(pSrc + 0);
- *(pDst + 3) = 0;
- pDst += 4;
- pSrc += 4;
- }
- if (g_pDD->CreatePalette(DDPCAPS_8BIT, aPal, &g_pDDPal, NULL) != DD_OK)
- {
- g_pDDPal = NULL;
- }
+ // HIRES (not MIXED) - eg. AZTEC.DSK
+ if ((g_uVideoMode&VF_PAGE2) == 0)
+ bRedraw = memcmp(&hgr_main[0x0000], MemGetMainPtr(0x2000), 8192) != 0;
+ else
+ bRedraw = memcmp(&hgr_main[0x2000], MemGetMainPtr(0x4000), 8192) != 0;
}
-
- if (g_pDDPal)
+ else
{
- g_pDDPrimarySurface->SetPalette(g_pDDPal); // this sets the palette for the primary surface
+ bRedraw =
+ (memcmp(text_main, MemGetMainPtr(0x400), sizeof(text_main)) != 0) ||
+ (memcmp(text_aux, MemGetAuxPtr(0x400), sizeof(text_aux)) != 0) ||
+ (memcmp(hgr_main, MemGetMainPtr(0x2000), sizeof(hgr_main)) != 0) ||
+ (memcmp(hgr_aux, MemGetAuxPtr(0x2000), sizeof(hgr_aux)) != 0);
}
}
- else
- {
- if (g_hPalette)
- {
- SelectPalette(dc,g_hPalette,0);
- RealizePalette(dc);
- }
- }
-#endif
- if (g_hPalette)
- {
- SelectPalette(dc,g_hPalette,0);
- RealizePalette(dc);
- }
+ if (bRedraw)
+ VideoRedrawScreenAfterFullSpeed(dwCyclesThisFrame);
+
+ // Copy all video memory (+ screen holes)
+ memcpy(text_main, MemGetMainPtr(0x400), sizeof(text_main));
+ memcpy(text_aux, MemGetAuxPtr(0x400), sizeof(text_aux));
+ memcpy(hgr_main, MemGetMainPtr(0x2000), sizeof(hgr_main));
+ memcpy(hgr_aux, MemGetAuxPtr(0x2000), sizeof(hgr_aux));
+
+ bValid = true;
}
//===========================================================================
-// Called by DrawFrameWindow() when in fullscreen mode (eg. after WM_PAINT msg)
-VideoUpdateFuncPtr_t VideoRedrawScreen (UINT n)
+void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame)
{
- g_VideoForceFullRedraw = n;
- return VideoRefreshScreen();
+ const int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines;
+
+ g_nVideoClockVert = (uint16_t) (dwCyclesThisFrame / kHClocks) % nScanLines;
+ g_nVideoClockHorz = (uint16_t) (dwCyclesThisFrame % kHClocks);
+
+ VideoRedrawScreen(); // Better (no flicker) than using: NTSC_VideoReinitialize() or VideoReinitialize()
}
-VideoUpdateFuncPtr_t VideoRedrawScreen ()
+//===========================================================================
+
+void VideoRedrawScreen (UINT uDelayRefresh /* =0 */)
{
g_VideoForceFullRedraw = 1;
- return VideoRefreshScreen();
+
+ VideoRefreshScreen( g_uVideoMode, uDelayRefresh );
}
//===========================================================================
-void _Video_Dirty()
-{
- ZeroMemory(celldirty,40*32);
-}
-
-//===========================================================================
-void _Video_SetupBanks( bool bBank2 )
+int _Video_SetupBanks( bool bBank2 )
{
g_pHiresBank1 = MemGetAuxPtr (0x2000 << (int)bBank2);
g_pHiresBank0 = MemGetMainPtr(0x2000 << (int)bBank2);
g_pTextBank1 = MemGetAuxPtr (0x400 << (int)bBank2);
g_pTextBank0 = MemGetMainPtr(0x400 << (int)bBank2);
+
+ return bBank2 ? VF_PAGE2 : 0;
}
//===========================================================================
@@ -2585,208 +1207,105 @@ static void DebugRefresh(char uDebugFlag)
}
#endif
-VideoUpdateFuncPtr_t VideoRefreshScreen ()
+void VideoRefreshScreen ( int bVideoModeFlags, UINT uDelayRefresh /* =0 */ )
{
+ static UINT uDelayRefreshCount = 0;
+ if (uDelayRefresh) uDelayRefreshCount = uDelayRefresh;
+
#if defined(_DEBUG) && defined(DEBUG_REFRESH_TIMINGS)
DebugRefresh(0);
#endif
- // CHECK EACH CELL FOR CHANGED BYTES. REDRAW PIXELS FOR THE CHANGED BYTES
- // IN THE FRAME BUFFER. MARK CELLS IN WHICH REDRAWING HAS TAKEN PLACE AS
- // DIRTY.
- _Video_Dirty();
- _Video_SetupBanks( SW_PAGE2 != 0 );
-
- VideoUpdateFuncPtr_t pfUpdate = SW_TEXT
- ? SW_80COL
- ? Update80ColCell
- : Update40ColCell
- : SW_HIRES
- ? (SW_DHIRES && SW_80COL)
- ? UpdateDHiResCell
- : UpdateHiResCell
- : (SW_DHIRES && SW_80COL)
- ? UpdateDLoResCell
- : UpdateLoResCell;
-
- bool bMixed = (SW_MIXED) ? true : false;
- _Video_RedrawScreen( pfUpdate, bMixed );
-
- //g_VideoForceFullRedraw = 0;
- if (g_VideoForceFullRedraw) --g_VideoForceFullRedraw;
- return pfUpdate;
-}
-
-//===========================================================================
-void _Video_RedrawScreen( VideoUpdateFuncPtr_t pfUpdate, bool bMixed )
-{
- LPBYTE pDstFrameBufferBits = 0;
- LONG pitch = 0;
- HDC hFrameDC = FrameGetVideoDC(&pDstFrameBufferBits,&pitch);
- CreateFrameOffsetTable(pDstFrameBufferBits,pitch); // ptr to start of each scanline
-
- BOOL anydirty = 0;
- int y = 0;
- int ypixel = 0;
-
- while (y < 20) {
- int offset = ((y & 7) << 7) + ((y >> 3) * 40);
- int x = 0;
- int xpixel = 0;
- while (x < 40) {
- anydirty |= celldirty[x][y] = pfUpdate(x,y,xpixel,ypixel,offset+x);
- ++x;
- xpixel += 14;
- }
- ++y;
- ypixel += 16;
- }
-
- if( bMixed ) {
- pfUpdate = SW_80COL
- ? Update80ColCell
- : Update40ColCell;
- }
-
- while (y < 24) {
- int offset = ((y & 7) << 7) + ((y >> 3) * 40);
- int x = 0;
- int xpixel = 0;
- while (x < 40) {
- anydirty |= celldirty[x][y] = pfUpdate(x,y,xpixel,ypixel,offset+x);
- ++x;
- xpixel += 14;
- }
- ++y;
- ypixel += 16;
- }
-
- // Clear this flag after TEXT screen has been updated
- g_bTextFlashFlag = false;
-
-#if 1
- // New simpified code:
- // . Oliver Schmidt gets a flickering mouse cursor with this code
- if (hFrameDC && anydirty)
+ if( bVideoModeFlags )
{
- int nViewportCX, nViewportCY;
- GetViewportCXCY(nViewportCX, nViewportCY);
- StretchBlt(hFrameDC, 0 ,0, nViewportCX, nViewportCY, g_hDeviceDC, 0, 0, FRAMEBUFFER_W, FRAMEBUFFER_H, SRCCOPY);
- GdiFlush();
- }
-#else
- // Original code:
- if (!hFrameDC || !anydirty)
- {
- FrameReleaseVideoDC();
- SetLastDrawnImage();
- g_VideoForceFullRedraw = 0;
- return;
+ NTSC_SetVideoMode( bVideoModeFlags );
+ NTSC_VideoUpdateCycles( VIDEO_SCANNER_6502_CYCLES );
}
- // COPY DIRTY CELLS FROM THE DEVICE DEPENDENT BITMAP ONTO THE SCREEN
- // IN LONG HORIZONTAL RECTANGLES
- BOOL remainingdirty = 0;
- y = 0;
- ypixel = 0;
- while (y < 24) {
- int start = -1;
- int startx = 0;
- int x = 0;
- int xpixel = 0;
- while (x < 40) {
- if ((x == 39) && celldirty[x][y])
- if (start >= 0) {
- xpixel += 14;
- celldirty[x][y] = 0;
- }
- else
- remainingdirty = 1;
- if ((start >= 0) && !celldirty[x][y]) {
- if ((x - startx > 1) || ((x == 39) && (xpixel == FRAMEBUFFER_W))) {
- int height = 1;
- while ((y+height < 24)
- && celldirty[startx][y+height]
- && celldirty[x-1][y+height]
- && celldirty[(startx+x-1) >> 1][y+height])
- height++;
- BitBlt(hFrameDC,start,ypixel,xpixel-start,height << 4,
- g_hDeviceDC,start,ypixel,SRCCOPY);
- while (height--) {
- int loop = startx;
- while (loop < x+(xpixel == FRAMEBUFFER_W))
- celldirty[loop++][y+height] = 0;
- }
- start = -1;
- }
- else
- remainingdirty = 1;
- start = -1;
- }
- else if ((start == -1) && celldirty[x][y] && (x < 39)) {
- start = xpixel;
- startx = x;
- }
- x++;
- xpixel += 14;
- }
- y++;
- ypixel += 16;
- }
+// NTSC_BEGIN
+ LPBYTE pDstFrameBufferBits = 0;
+ LONG pitch = 0;
+ HDC hFrameDC = FrameGetVideoDC(&pDstFrameBufferBits,&pitch);
- // COPY ANY REMAINING DIRTY CELLS FROM THE DEVICE DEPENDENT BITMAP
- // ONTO THE SCREEN IN VERTICAL RECTANGLES
- if (remainingdirty) {
- int x = 0;
- int xpixel = 0;
- while (x < 40) {
- int start = -1;
- int y = 0;
- int ypixel = 0;
- while (y < 24) {
- if ((y == 23) && celldirty[x][y]) {
- if (start == -1)
- start = ypixel;
- ypixel += 16;
- celldirty[x][y] = 0;
- }
- if ((start >= 0) && !celldirty[x][y]) {
- BitBlt(hFrameDC,xpixel,start,14,ypixel-start,
- g_hDeviceDC,xpixel,start,SRCCOPY);
- start = -1;
- }
- else if ((start == -1) && celldirty[x][y])
- start = ypixel;
- y++;
- ypixel += 16;
- }
- x++;
- xpixel += 14;
- }
- }
-
- GdiFlush();
+#if 1 // Keep Aspect Ratio
+ // Need to clear full screen logo to black
+ #define W g_nViewportCX
+ #define H g_nViewportCY
+#else // Stretch
+ // Stretch - doesn't preserve 1:1 aspect ratio
+ #define W g_bIsFullScreen ? g_nDDFullScreenW : g_nViewportCX
+ #define H g_bIsFullScreen ? g_nDDFullScreenH : g_nViewportCY
#endif
+ if (hFrameDC)
+ {
+ if (uDelayRefreshCount)
+ {
+ // Delay the refresh in full-screen mode (to allow screen-capabilities to take effect) - required for Win7 (and others?)
+ --uDelayRefreshCount;
+ }
+ else
+ {
+ int xDst = 0;
+ int yDst = 0;
+
+ if (g_bIsFullScreen)
+ {
+ // Why the need to set the mid-position here, but not for (full-screen) LOGO or DEBUG modes?
+ xDst = (g_nDDFullScreenW-W)/2 - VIEWPORTX*2;
+ yDst = (g_nDDFullScreenH-H)/2;
+ }
+
+ int xSrc = BORDER_W;
+ int ySrc = BORDER_H;
+
+ if (g_eVideoType == VT_MONO_TV || g_eVideoType == VT_COLOR_TV)
+ {
+ // Adjust the src locations for the NTSC video modes
+ xSrc += 2;
+ ySrc -= 1;
+ }
+
+ int xdest = GetFullScreenOffsetX();
+ int ydest = GetFullScreenOffsetY();
+ int wdest = g_nViewportCX;
+ int hdest = g_nViewportCY;
+
+ SetStretchBltMode(hFrameDC, COLORONCOLOR);
+ StretchBlt(
+ hFrameDC,
+ xdest, ydest,
+ wdest, hdest,
+ g_hDeviceDC,
+ xSrc, ySrc,
+ FRAMEBUFFER_BORDERLESS_W, FRAMEBUFFER_BORDERLESS_H,
+ SRCCOPY);
+ }
+ }
+
+ GdiFlush();
+
FrameReleaseVideoDC();
- SetLastDrawnImage();
+
+ g_VideoForceFullRedraw = 0;
+// NTSC_END
}
//===========================================================================
void VideoReinitialize ()
{
- V_CreateIdentityPalette();
- V_CreateDIBSections();
+ NTSC_VideoReinitialize( g_dwCyclesThisFrame );
+ NTSC_VideoInitAppleType();
+ NTSC_SetVideoStyle();
+ NTSC_SetVideoMode( g_uVideoMode ); // Pre-condition: g_nVideoClockHorz (derived from g_dwCyclesThisFrame)
}
-
//===========================================================================
void VideoResetState ()
{
g_nAltCharSetOffset = 0;
g_uVideoMode = VF_TEXT;
g_VideoForceFullRedraw = 1;
- g_bVideoUpdatedThisFrame = false;
}
@@ -2795,15 +1314,16 @@ void VideoResetState ()
BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
{
address &= 0xFF;
- DWORD oldpage2 = SW_PAGE2;
- int oldvalue = g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2));
+
+// DWORD oldpage2 = SW_PAGE2;
+// int oldvalue = g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2));
switch (address)
{
- case 0x00: g_uVideoMode &= ~VF_80STORE; break;
- case 0x01: g_uVideoMode |= VF_80STORE; break;
- case 0x0C: if (!IS_APPLE2) g_uVideoMode &= ~VF_80COL; break;
- case 0x0D: if (!IS_APPLE2) g_uVideoMode |= VF_80COL; break;
+ case 0x00: g_uVideoMode &= ~VF_80STORE; break;
+ case 0x01: g_uVideoMode |= VF_80STORE; break;
+ case 0x0C: if (!IS_APPLE2){g_uVideoMode &= ~VF_80COL; NTSC_SetVideoTextMode(40);}; break;
+ case 0x0D: if (!IS_APPLE2){g_uVideoMode |= VF_80COL; NTSC_SetVideoTextMode(80);}; break;
case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off
case 0x0F: if (!IS_APPLE2) g_nAltCharSetOffset = 256; break; // Alternate char set on
case 0x50: g_uVideoMode &= ~VF_TEXT; break;
@@ -2818,9 +1338,17 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
case 0x5F: if (!IS_APPLE2) g_uVideoMode &= ~VF_DHIRES; break;
}
+ // Apple IIe, Technical Notes, #3: Double High-Resolution Graphics
+ // 80STORE must be OFF to display page 2
if (SW_80STORE)
g_uVideoMode &= ~VF_PAGE2;
+// NTSC_BEGIN
+ NTSC_SetVideoMode( g_uVideoMode );
+// NTSC_END
+
+#if 0 // NTSC_CLEANUP: Is this still needed??
+
if (oldvalue != g_nAltCharSetOffset+(int)(g_uVideoMode & ~(VF_80STORE | VF_PAGE2)))
g_VideoForceFullRedraw = 1; // Defer video redraw until VideoEndOfVideoFrame()
@@ -2832,67 +1360,20 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
// NB. Deferring the update by just setting /g_VideoForceFullRedraw/ is not an option, since this doesn't provide "flip-immediate"
//
// Ultimately this isn't the correct solution, and proper cycle-accurate video rendering should be done, but this is a much bigger job!
- //
+ // TODO-Michael: Is MemReadFloatingBus() still accurate now that we have proper per cycle video rendering??
if (!g_bVideoUpdatedThisFrame)
{
- VideoRefreshScreen();
+ VideoRedrawScreen(); // VideoRefreshScreen();
g_bVideoUpdatedThisFrame = true;
}
}
-
+#endif // NTSC_CLEANUP
return MemReadFloatingBus(uExecutedCycles);
}
//===========================================================================
-// Called at 60Hz (every 16.666ms)
-static void VideoUpdateFlash()
-{
- static UINT nTextFlashCnt = 0;
-
- // Flash rate:
- // . NTSC : 60/16 ~= 4Hz
- // . PAL : 50/16 ~= 3Hz
- nTextFlashCnt = (nTextFlashCnt+1) & 0xf;
-
- // BUG: In unthrottled CPU mode, flash rate should not be affected
- if(nTextFlashCnt == 0)
- {
- g_bTextFlashState = !g_bTextFlashState;
-
- // Redraw any FLASHing chars if any text showing. NB. No FLASH g_nAppMode for 80 cols
- if ((SW_TEXT || SW_MIXED) ) // && !SW_80COL) // FIX: FLASH 80-Column
- g_bTextFlashFlag = true;
- }
-}
-
-//===========================================================================
-
-// Called from main-loop every 17030 cycles (ie. 60Hz when CPU = 1MHz)
-void VideoEndOfVideoFrame(void)
-{
- g_bVideoUpdatedThisFrame = false; // Allow page1/2 toggle to result in an immediate video redraw
-
- VideoUpdateFlash(); // TODO: Flash rate should be constant (regardless of CPU speed)
-
- if (!VideoApparentlyDirty())
- return;
-
- // Apple II is not page flipping...
-
- static DWORD dwLastTime = 0;
- DWORD dwCurrTime = GetTickCount();
- if (!g_bFullSpeed ||
- (dwCurrTime-dwLastTime >= 100)) // FullSpeed: update every 100ms
- {
- VideoRefreshScreen();
- dwLastTime = dwCurrTime;
- }
-}
-
-//===========================================================================
-
bool VideoGetSW80COL(void)
{
return SW_80COL ? true : false;
@@ -2946,6 +1427,7 @@ void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode)
{
g_nAltCharSetOffset = !AltCharSet ? 0 : 256;
g_uVideoMode = VideoMode;
+ g_dwCyclesThisFrame = 0;
}
//
@@ -3002,6 +1484,7 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines;
int nVSyncLine = bVideoScannerNTSC ? kNTSCVSyncLine : kPALVSyncLine;
int nScanCycles = nScanLines * kHClocks;
+ nCycles %= nScanCycles;
// calculate horizontal scanning state
//
@@ -3107,6 +1590,8 @@ bool VideoGetVbl(const DWORD uExecutedCycles)
// calculate video parameters according to display standard
//
int nScanLines = bVideoScannerNTSC ? kNTSCScanLines : kPALScanLines;
+ int nScanCycles = nScanLines * kHClocks;
+ nCycles %= nScanCycles;
// calculate vertical scanning state
//
@@ -3212,53 +1697,6 @@ void Video_TakeScreenShot( int iScreenShotType )
g_nLastScreenShot++;
}
-
-typedef char int8;
-typedef short int16;
-typedef int int32;
-typedef unsigned char u8;
-typedef signed short s16;
-
-/// turn of MSVC struct member padding
-#pragma pack(push,1)
-
-struct bgra_t
-{
- u8 b;
- u8 g;
- u8 r;
- u8 a; // reserved on Win32
-};
-
-struct WinBmpHeader_t
-{
- // BITMAPFILEHEADER // Addr Size
- char nCookie[2] ; // 0x00 0x02 BM
- int32 nSizeFile ; // 0x02 0x04 0 = ignore
- int16 nReserved1 ; // 0x06 0x02
- int16 nReserved2 ; // 0x08 0x02
- int32 nOffsetData ; // 0x0A 0x04
- // == 0x0D (14)
-
- // BITMAPINFOHEADER
- int32 nStructSize ; // 0x0E 0x04 biSize
- int32 nWidthPixels ; // 0x12 0x04 biWidth
- int32 nHeightPixels ; // 0x16 0x04 biHeight
- int16 nPlanes ; // 0x1A 0x02 biPlanes
- int16 nBitsPerPixel ; // 0x1C 0x02 biBitCount
- int32 nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB
- int32 nSizeImage ; // 0x22 0x04 0 = ignore
- int32 nXPelsPerMeter ; // 0x26 0x04
- int32 nYPelsPerMeter ; // 0x2A 0x04
- int32 nPaletteColors ; // 0x2E 0x04
- int32 nImportantColors; // 0x32 0x04
- // == 0x28 (40)
-
- // RGBQUAD
- // pixelmap
-};
-#pragma pack(pop)
-
WinBmpHeader_t g_tBmpHeader;
#if SCREENSHOT_TGA
@@ -3291,27 +1729,51 @@ WinBmpHeader_t g_tBmpHeader;
TargaHeader_t g_tTargaHeader;
#endif // SCREENSHOT_TGA
+void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel )
+{
+#if SCREENSHOT_BMP
+ pBmp->nCookie[ 0 ] = 'B'; // 0x42
+ pBmp->nCookie[ 1 ] = 'M'; // 0x4d
+ pBmp->nSizeFile = 0;
+ pBmp->nReserved1 = 0;
+ pBmp->nReserved2 = 0;
+#if VIDEO_SCREENSHOT_PALETTE
+ pBmp->nOffsetData = sizeof(WinBmpHeader_t) + (256 * sizeof(bgra_t));
+#else
+ pBmp->nOffsetData = sizeof(WinBmpHeader_t);
+#endif
+ pBmp->nStructSize = 0x28; // sizeof( WinBmpHeader_t );
+ pBmp->nWidthPixels = nWidth;
+ pBmp->nHeightPixels = nHeight;
+ pBmp->nPlanes = 1;
+#if VIDEO_SCREENSHOT_PALETTE
+ pBmp->nBitsPerPixel = 8;
+#else
+ pBmp->nBitsPerPixel = nBitsPerPixel;
+#endif
+ pBmp->nCompression = BI_RGB; // none
+ pBmp->nSizeImage = 0;
+ pBmp->nXPelsPerMeter = 0;
+ pBmp->nYPelsPerMeter = 0;
+#if VIDEO_SCREENSHOT_PALETTE
+ pBmp->nPaletteColors = 256;
+#else
+ pBmp->nPaletteColors = 0;
+#endif
+ pBmp->nImportantColors = 0;
+}
+
//===========================================================================
void Video_MakeScreenShot(FILE *pFile)
{
-#if SCREENSHOT_BMP
- g_tBmpHeader.nCookie[ 0 ] = 'B'; // 0x42
- g_tBmpHeader.nCookie[ 1 ] = 'M'; // 0x4d
- g_tBmpHeader.nSizeFile = 0;
- g_tBmpHeader.nReserved1 = 0;
- g_tBmpHeader.nReserved2 = 0;
- g_tBmpHeader.nOffsetData = sizeof(WinBmpHeader_t) + (256 * sizeof(bgra_t));
- g_tBmpHeader.nStructSize = 0x28; // sizeof( WinBmpHeader_t );
- g_tBmpHeader.nWidthPixels = g_iScreenshotType ? FRAMEBUFFER_W/2 :FRAMEBUFFER_W;
- g_tBmpHeader.nHeightPixels = g_iScreenshotType ? FRAMEBUFFER_H/2 : FRAMEBUFFER_H;
- g_tBmpHeader.nPlanes = 1;
- g_tBmpHeader.nBitsPerPixel = 8;
- g_tBmpHeader.nCompression = BI_RGB;
- g_tBmpHeader.nSizeImage = 0;
- g_tBmpHeader.nXPelsPerMeter = 0;
- g_tBmpHeader.nYPelsPerMeter = 0;
- g_tBmpHeader.nPaletteColors = 256;
- g_tBmpHeader.nImportantColors = 0;
+ WinBmpHeader_t *pBmp = &g_tBmpHeader;
+
+ Video_SetBitmapHeader(
+ pBmp,
+ g_iScreenshotType ? FRAMEBUFFER_BORDERLESS_W/2 : FRAMEBUFFER_BORDERLESS_W,
+ g_iScreenshotType ? FRAMEBUFFER_BORDERLESS_H/2 : FRAMEBUFFER_BORDERLESS_H,
+ 32
+ );
// char sText[256];
// sprintf( sText, "sizeof: BITMAPFILEHEADER = %d\n", sizeof(BITMAPFILEHEADER) ); // = 14
@@ -3319,50 +1781,58 @@ void Video_MakeScreenShot(FILE *pFile)
// sprintf( sText, "sizeof: BITMAPINFOHEADER = %d\n", sizeof(BITMAPINFOHEADER) ); // = 40
// MessageBox( g_hFrameWindow, sText, "Info 2", MB_OK );
- char sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize[ sizeof( WinBmpHeader_t ) == (14 + 40) ];
- sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize;
+ char sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize54[ sizeof( WinBmpHeader_t ) == (14 + 40) ];
+ /**/ sIfSizeZeroOrUnknown_BadWinBmpHeaderPackingSize54[0]=0;
// Write Header
- int nLen;
- fwrite( &g_tBmpHeader, sizeof( g_tBmpHeader ), 1, pFile );
+ fwrite( pBmp, sizeof( WinBmpHeader_t ), 1, pFile );
+ uint32_t *pSrc;
+#if VIDEO_SCREENSHOT_PALETTE
// Write Palette Data
- u8 *pSrc = ((u8*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER);
- nLen = g_tBmpHeader.nPaletteColors * sizeof(bgra_t); // RGBQUAD
+ pSrc = ((uint8_t*)g_pFramebufferinfo) + sizeof(BITMAPINFOHEADER);
+ int nLen = g_tBmpHeader.nPaletteColors * sizeof(bgra_t); // RGBQUAD
fwrite( pSrc, nLen, 1, pFile );
pSrc += nLen;
+#endif
// Write Pixel Data
// No need to use GetDibBits() since we already have http://msdn.microsoft.com/en-us/library/ms532334.aspx
// @reference: "Storing an Image" http://msdn.microsoft.com/en-us/library/ms532340(VS.85).aspx
- pSrc = ((u8*)g_pFramebufferbits);
- nLen = g_tBmpHeader.nWidthPixels * g_tBmpHeader.nHeightPixels * g_tBmpHeader.nBitsPerPixel / 8;
+ pSrc = (uint32_t*) g_pFramebufferbits;
+ pSrc += BORDER_H * FRAMEBUFFER_W; // Skip top border
+ pSrc += BORDER_W; // Skip left border
if( g_iScreenshotType == SCREENSHOT_280x192 )
{
pSrc += FRAMEBUFFER_W; // Start on odd scanline (otherwise for 50% scanline mode get an all black image!)
- u8 aScanLine[ 280 ];
- u8 *pDst;
+ uint32_t aScanLine[ 280 ];
+ uint32_t *pDst;
// 50% Half Scan Line clears every odd scanline.
// SHIFT+PrintScreen saves only the even rows.
// NOTE: Keep in sync with _Video_RedrawScreen() & Video_MakeScreenShot()
- for( int y = 0; y < FRAMEBUFFER_H/2; y++ )
+ for( int y = 0; y < FRAMEBUFFER_BORDERLESS_H/2; y++ )
{
pDst = aScanLine;
- for( int x = 0; x < FRAMEBUFFER_W/2; x++ )
+ for( int x = 0; x < FRAMEBUFFER_BORDERLESS_W/2; x++ )
{
*pDst++ = pSrc[1]; // correction for left edge loss of scaled scanline [Bill Buckel, B#18928]
pSrc += 2; // skip odd pixels
}
- fwrite( aScanLine, FRAMEBUFFER_W/2, 1, pFile );
+ fwrite( aScanLine, sizeof(uint32_t), FRAMEBUFFER_BORDERLESS_W/2, pFile );
pSrc += FRAMEBUFFER_W; // scan lines doubled - skip odd ones
+ pSrc += BORDER_W*2; // Skip right border & next line's left border
}
}
else
{
- fwrite( pSrc, nLen, 1, pFile );
+ for( int y = 0; y < FRAMEBUFFER_BORDERLESS_H; y++ )
+ {
+ fwrite( pSrc, sizeof(uint32_t), FRAMEBUFFER_BORDERLESS_W, pFile );
+ pSrc += FRAMEBUFFER_W;
+ }
}
#endif // SCREENSHOT_BMP
@@ -3370,10 +1840,10 @@ void Video_MakeScreenShot(FILE *pFile)
TargaHeader_t *pHeader = &g_tTargaHeader;
memset( (void*)pHeader, 0, sizeof( TargaHeader_t ) );
- pHeader->iImageType = TARGA_RGB;
+ pHeader->iImageType = TARGA_RGB;
pHeader->nWidthPixels = FRAMEBUFFER_W;
pHeader->nHeightPixels = FRAMEBUFFER_H;
- pHeader->nBitsPerPixel = 24;
+ pHeader->nBitsPerPixel = 24;
#endif // SCREENSHOT_TGA
}
@@ -3400,15 +1870,47 @@ 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 ),&monochrome);
+ REGLOAD(TEXT(REGVALUE_VIDEO_MONO_COLOR ),&g_nMonochromeRGB);
if (g_eVideoType >= NUM_VIDEO_MODES)
- g_eVideoType = VT_COLOR_STANDARD; // Old default: VT_COLOR_TVEMU
+ g_eVideoType = VT_COLOR_MONITOR;
}
void Config_Save_Video()
{
REGSAVE(TEXT(REGVALUE_VIDEO_MODE ),g_eVideoType);
REGSAVE(TEXT(REGVALUE_VIDEO_HALF_SCAN_LINES),g_uHalfScanLines);
- REGSAVE(TEXT(REGVALUE_VIDEO_MONO_COLOR ),monochrome);
+ REGSAVE(TEXT(REGVALUE_VIDEO_MONO_COLOR ),g_nMonochromeRGB);
+}
+
+// ____________________________________________________________________
+
+//===========================================================================
+static void videoCreateDIBSection()
+{
+ // CREATE THE DEVICE CONTEXT
+ HWND window = GetDesktopWindow();
+ HDC dc = GetDC(window);
+ if (g_hDeviceDC)
+ {
+ DeleteDC(g_hDeviceDC);
+ }
+ g_hDeviceDC = CreateCompatibleDC(dc);
+
+ // CREATE THE FRAME BUFFER DIB SECTION
+ if (g_hDeviceBitmap)
+ DeleteObject(g_hDeviceBitmap);
+ g_hDeviceBitmap = CreateDIBSection(
+ dc,
+ g_pFramebufferinfo,
+ DIB_RGB_COLORS,
+ (LPVOID *)&g_pFramebufferbits,0,0
+ );
+ 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, FRAMEBUFFER_W*FRAMEBUFFER_H*4 );
+
+ NTSC_VideoInit( g_pFramebufferbits );
}
diff --git a/source/Video.h b/source/Video.h
index 8aecda23..29cee8d8 100644
--- a/source/Video.h
+++ b/source/Video.h
@@ -6,73 +6,177 @@
// NOTE: Used/Serialized by: g_eVideoType
enum VideoType_e
{
- VT_MONO_HALFPIXEL_REAL // uses custom monochrome
- , VT_COLOR_STANDARD
- , VT_COLOR_TEXT_OPTIMIZED
- , VT_COLOR_TVEMU
- , VT_MONO_AMBER // now half pixel
- , VT_MONO_GREEN // now half pixel
- , VT_MONO_WHITE // now half pixel
+ VT_MONO_CUSTOM
+ , VT_COLOR_MONITOR
+ , VT_MONO_TV
+ , VT_COLOR_TV
+ , VT_MONO_AMBER
+ , VT_MONO_GREEN
+ , VT_MONO_WHITE
, NUM_VIDEO_MODES
};
extern TCHAR g_aVideoChoices[];
extern char *g_apVideoModeDesc[ NUM_VIDEO_MODES ];
-enum AppleFont_e
+ enum VideoFlag_e
+ {
+ VF_80COL = 0x00000001,
+ VF_DHIRES = 0x00000002,
+ VF_HIRES = 0x00000004,
+ VF_80STORE= 0x00000008, // was called VF_MASK2
+ VF_MIXED = 0x00000010,
+ VF_PAGE2 = 0x00000020,
+ VF_TEXT = 0x00000040
+ };
+
+ enum AppleFont_e
+ {
+ // 40-Column mode is 1x Zoom (default)
+ // 80-Column mode is ~0.75x Zoom (7 x 16)
+ // Tiny mode is 0.5 zoom (7x8) for debugger
+ APPLE_FONT_WIDTH = 14, // in pixels
+ APPLE_FONT_HEIGHT = 16, // in pixels
+
+ // Each cell has a reserved aligned pixel area (grid spacing)
+ APPLE_FONT_CELL_WIDTH = 16,
+ APPLE_FONT_CELL_HEIGHT = 16,
+
+ // The bitmap contains 3 regions
+ // Each region is 256x256 pixels = 16x16 chars
+ APPLE_FONT_X_REGIONSIZE = 256, // in pixelx
+ APPLE_FONT_Y_REGIONSIZE = 256, // in pixels
+
+ // Starting Y offsets (pixels) for the regions
+ APPLE_FONT_Y_APPLE_2PLUS = 0, // ][+
+ APPLE_FONT_Y_APPLE_80COL = 256, // //e (inc. Mouse Text)
+ APPLE_FONT_Y_APPLE_40COL = 512, // ][
+ };
+
+#ifdef _MSC_VER
+ /// turn of MSVC struct member padding
+ #pragma pack(push,1)
+ #define PACKED
+#else
+ #define PACKED // TODO: FIXME: gcc/clang __attribute__
+#endif
+
+struct bgra_t
{
- // 40-Column mode is 1x Zoom (default)
- // 80-Column mode is ~0.75x Zoom (7 x 16)
- // Tiny mode is 0.5 zoom (7x8) for debugger
- APPLE_FONT_WIDTH = 14, // in pixels
- APPLE_FONT_HEIGHT = 16, // in pixels
-
- // Each cell has a reserved aligned pixel area (grid spacing)
- APPLE_FONT_CELL_WIDTH = 16,
- APPLE_FONT_CELL_HEIGHT = 16,
-
- // The bitmap contains 3 regions
- // Each region is 256x256 pixels = 16x16 chars
- APPLE_FONT_X_REGIONSIZE = 256, // in pixelx
- APPLE_FONT_Y_REGIONSIZE = 256, // in pixels
-
- // Starting Y offsets (pixels) for the regions
- APPLE_FONT_Y_APPLE_2PLUS = 0, // ][+
- APPLE_FONT_Y_APPLE_80COL = 256, // //e (inc. Mouse Text)
- APPLE_FONT_Y_APPLE_40COL = 512, // ][
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+ uint8_t a; // reserved on Win32
};
+struct WinBmpHeader_t
+{
+ // BITMAPFILEHEADER // Addr Size
+ uint8_t nCookie[2] ; // 0x00 0x02 BM
+ uint32_t nSizeFile ; // 0x02 0x04 0 = ignore
+ uint16_t nReserved1 ; // 0x06 0x02
+ uint16_t nReserved2 ; // 0x08 0x02
+ uint32_t nOffsetData ; // 0x0A 0x04
+ // == 0x0D (14)
+
+ // BITMAPINFOHEADER
+ uint32_t nStructSize ; // 0x0E 0x04 biSize
+ uint32_t nWidthPixels ; // 0x12 0x04 biWidth
+ uint32_t nHeightPixels ; // 0x16 0x04 biHeight
+ uint16_t nPlanes ; // 0x1A 0x02 biPlanes
+ uint16_t nBitsPerPixel ; // 0x1C 0x02 biBitCount
+ uint32_t nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB
+ uint32_t nSizeImage ; // 0x22 0x04 0 = ignore
+ uint32_t nXPelsPerMeter ; // 0x26 0x04
+ uint32_t nYPelsPerMeter ; // 0x2A 0x04
+ uint32_t nPaletteColors ; // 0x2E 0x04
+ uint32_t nImportantColors; // 0x32 0x04
+ // == 0x28 (40)
+
+ // RGBQUAD
+ // pixelmap
+};
+
+struct WinCIEXYZ
+{
+ uint32_t r; // fixed point 2.30
+ uint32_t g; // fixed point 2.30
+ uint32_t b; // fixed point 2.30
+};
+
+struct WinBmpHeader4_t
+{
+ // BITMAPFILEHEADER // Addr Size
+ uint8_t nCookie[2] ; // 0x00 0x02 BM
+ uint32_t nSizeFile ; // 0x02 0x04 0 = ignore
+ uint16_t nReserved1 ; // 0x06 0x02
+ uint16_t nReserved2 ; // 0x08 0x02
+ uint32_t nOffsetData ; // 0x0A 0x04
+ // ==== 0x0D (14)
+
+ // BITMAPINFOHEADER
+ uint32_t nStructSize ; // 0x0E 0x04 biSize
+ uint32_t nWidthPixels ; // 0x12 0x04 biWidth
+ uint32_t nHeightPixels ; // 0x16 0x04 biHeight
+ uint16_t nPlanes ; // 0x1A 0x02 biPlanes
+ uint16_t nBitsPerPixel ; // 0x1C 0x02 biBitCount
+ uint32_t nCompression ; // 0x1E 0x04 biCompression 0 = BI_RGB
+ uint32_t nSizeImage ; // 0x22 0x04 0 = ignore
+ uint32_t nXPelsPerMeter ; // 0x26 0x04
+ uint32_t nYPelsPerMeter ; // 0x2A 0x04
+ uint32_t nPaletteColors ; // 0x2E 0x04
+ uint32_t nImportantColors; // 0x32 0x04
+ // ==== 0x28 (40)
+
+ //BITMAPV4HEADER new fields
+ uint32_t nRedMask ; // 0x36 0x04
+ uint32_t nGreenMask ; // 0x3A 0x04
+ uint32_t nBlueMask ; // 0x3E 0x04
+ uint32_t nAlphaMask ; // 0x42 0x04
+ uint32_t nType ; // 0x46 0x04
+
+ uint32_t Rx, Ry, Rz ; // 0x4A 0x0C
+ uint32_t Gx, Gy, Gz ; // 0x56 0x0C
+ uint32_t Bx, By, Bz ; // 0x62 0x0C
+
+ uint32_t nRedGamma ; // 0x6E 0x04
+ uint32_t nGreenGamma ; // 0x72 0x04
+ uint32_t nBlueGamma ; // 0x76 0x04
+};
+
+#ifdef _MSC_VER
+ #pragma pack(pop)
+#endif
+
// Globals __________________________________________________________
extern HBITMAP g_hLogoBitmap;
-extern COLORREF monochrome; // saved
-extern DWORD g_eVideoType; // saved
-extern DWORD g_uHalfScanLines; // saved
-extern LPBYTE g_pFramebufferbits;
+extern COLORREF g_nMonochromeRGB; // saved to Registry
+extern uint32_t g_uVideoMode;
+extern DWORD g_eVideoType; // saved to Registry
+extern DWORD g_uHalfScanLines; // saved to Registry
+extern uint8_t *g_pFramebufferbits;
typedef bool (*VideoUpdateFuncPtr_t)(int,int,int,int,int);
// Prototypes _______________________________________________________
-void CreateColorMixMap();
-
BOOL VideoApparentlyDirty ();
void VideoBenchmark ();
-void VideoChooseColor ();
+void VideoChooseMonochromeColor (); // FIXME: Should be moved to PageConfig and call VideoSetMonochromeColor()
void VideoDestroy ();
-void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale);
void VideoDisplayLogo ();
void VideoInitialize ();
void VideoRealizePalette (HDC);
-VideoUpdateFuncPtr_t VideoRedrawScreen (UINT);
-VideoUpdateFuncPtr_t VideoRedrawScreen ();
-VideoUpdateFuncPtr_t VideoRefreshScreen ();
+void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInvalidate = false);
+void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame);
+void VideoRedrawScreen (UINT uDelayRefresh = 0);
+void VideoRefreshScreen (int bVideoFlags, UINT uDelayRefresh =0 );
void VideoReinitialize ();
void VideoResetState ();
WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles);
bool VideoGetVbl(DWORD uExecutedCycles);
-void VideoEndOfVideoFrame(void);
bool VideoGetSW80COL(void);
bool VideoGetSWDHIRES(void);
@@ -89,9 +193,7 @@ void VideoSetSnapshot_v1(const UINT AltCharSet, const UINT VideoMode);
void VideoSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void VideoLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);
-void _Video_Dirty();
-void _Video_RedrawScreen( VideoUpdateFuncPtr_t update, bool bMixed = false );
-void _Video_SetupBanks( bool bBank2 );
+int _Video_SetupBanks( bool bBank2 );
bool Update40ColCell (int x, int y, int xpixel, int ypixel, int offset);
bool Update80ColCell (int x, int y, int xpixel, int ypixel, int offset);
bool UpdateLoResCell (int x, int y, int xpixel, int ypixel, int offset);
@@ -109,10 +211,12 @@ enum VideoScreenShot_e
SCREENSHOT_280x192
};
void Video_TakeScreenShot( int iScreenShotType );
+void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel );
+
// Win32/MSVC: __stdcall
BYTE VideoCheckMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
-BYTE VideoCheckVbl (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
+BYTE VideoCheckVbl ( ULONG uExecutedCycles );
BYTE VideoSetMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
void Config_Load_Video(void);
diff --git a/test/TestCPU6502/TestCPU6502.cpp b/test/TestCPU6502/TestCPU6502.cpp
index 75d62029..4a6f12b9 100644
--- a/test/TestCPU6502/TestCPU6502.cpp
+++ b/test/TestCPU6502/TestCPU6502.cpp
@@ -4,6 +4,7 @@
#include "../../source/CPU.h"
// From Applewin.cpp
+bool g_bFullSpeed = false;
enum AppMode_e g_nAppMode = MODE_RUNNING;
// From Memory.cpp
@@ -98,6 +99,11 @@ DWORD z80_mainloop(ULONG uTotalCycles, ULONG uExecutedCycles)
return 0;
}
+// From NTSC.cpp
+void NTSC_VideoUpdateCycles( long cycles6502 )
+{
+}
+
//-------------------------------------
#include "../../source/cpu/cpu_general.inl"