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"