diff --git a/source/Applewin.cpp b/source/Applewin.cpp index dd210225..d34aa828 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -254,41 +254,13 @@ void ContinueExecution(void) emulmsec_frac %= CLKS_PER_MS; } - // DETERMINE WHETHER THE SCREEN WAS UPDATED THIS CLOCKTICK - static BOOL anyupdates = 0; - VideoCheckPage(0); // force=0 - anyupdates |= VideoHasRefreshed(); // Only called from here. Returns & clears 'hasrefreshed' flag - - // - if (g_dwCyclesThisFrame >= dwClksPerFrame) { g_dwCyclesThisFrame -= dwClksPerFrame; - VideoUpdateFlash(); - - static BOOL lastupdates[2] = {0,0}; - if (!anyupdates && !lastupdates[0] && !lastupdates[1] && VideoApparentlyDirty()) - { - VideoCheckPage(1); // force=1 - static DWORD lasttime = 0; - DWORD currtime = GetTickCount(); - if ((!g_bFullSpeed) || - (currtime-lasttime >= (DWORD)(g_bGraphicsMode ? 100 : 25))) - { - VideoRefreshScreen(); - lasttime = currtime; - } - } - - lastupdates[1] = lastupdates[0]; - lastupdates[0] = anyupdates; - anyupdates = 0; - + VideoEndOfVideoFrame(); MB_EndOfVideoFrame(); } - // - if (!g_bFullSpeed) { SysClk_WaitTimer(); diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 92b7e7f9..40b8d8a4 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -4711,9 +4711,9 @@ size_t Util_GetTextScreen ( char* &pText_ ) g_nTextScreen = 0; memset( pBeg, 0, sizeof( g_aTextScreen ) ); - int bBank2 = g_bVideoDisplayPage2; - LPBYTE g_pTextBank1 = MemGetAuxPtr (0x400 << (int)bBank2); - LPBYTE g_pTextBank0 = MemGetMainPtr(0x400 << (int)bBank2); + unsigned int uBank2 = VideoGetSWPAGE2() ? 1 : 0; + LPBYTE g_pTextBank1 = MemGetAuxPtr (0x400 << uBank2); + LPBYTE g_pTextBank0 = MemGetMainPtr(0x400 << uBank2); for( int y = 0; y < 24; y++ ) { @@ -4724,7 +4724,7 @@ size_t Util_GetTextScreen ( char* &pText_ ) { char c; // TODO: FormatCharTxtCtrl() ? - if ( g_bVideoMode & VF_80COL ) + if ( VideoGetSW80COL() ) { // AUX c = g_pTextBank1[ nAddressStart ] & 0x7F; c = RemapChar(c); @@ -4792,7 +4792,7 @@ int CmdTextSave (int nArgs) _tcscpy( g_sMemoryLoadSaveFileName, g_aArgs[ 1 ].sArg ); else { - if( g_bVideoMode & VF_80COL ) + if( VideoGetSW80COL() ) sprintf( g_sMemoryLoadSaveFileName, "AppleWin_Text80.txt" ); else sprintf( g_sMemoryLoadSaveFileName, "AppleWin_Text40.txt" ); @@ -5997,11 +5997,11 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ); Update_t _ViewOutput( ViewVideoPage_t iPage, VideoUpdateFuncPtr_t pfUpdate ) { - g_VideoForceFullRedraw = true; + VideoSetForceFullRedraw(); _Video_Dirty(); switch( iPage ) { - case VIEW_PAGE_X: _Video_SetupBanks( g_bVideoDisplayPage2 ); break; // Page Current + 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 ! default: diff --git a/source/Debugger/Debugger_Display.cpp b/source/Debugger/Debugger_Display.cpp index e0b88ed1..7fd183bd 100644 --- a/source/Debugger/Debugger_Display.cpp +++ b/source/Debugger/Debugger_Display.cpp @@ -2735,38 +2735,38 @@ void DrawSoftSwitches( int iSoftSwitch ) // GR / TEXT // GRAPH/TEXT // TEXT ON/OFF - sprintf( sText, !(g_bVideoMode & VF_TEXT) ? "GR / ----" : "-- / TEXT" ); + sprintf( sText, !VideoGetSWTEXT() ? "GR / ----" : "-- / TEXT" ); PrintTextCursorY( sText, rect ); // $C052 / $C053 = MIXEDOFF/MIXEDON = SW.MIXCLR/SW.MIXSET // FULL/MIXED // MIX OFF/ON - sprintf( sText, !(g_bVideoMode & VF_MIXED) ? "FULL/-----" : "----/MIXED" ); + sprintf( sText, !VideoGetSWMIXED() ? "FULL/-----" : "----/MIXED" ); PrintTextCursorY( sText, rect ); // $C054 / $C055 = PAGE1/PAGE2 = PAGE2OFF/PAGE2ON = SW.LOWSCR/SW.HISCR // PAGE 1 / 2 - sprintf( sText, !(g_bVideoMode & VF_PAGE2) ? "PAGE 1 / -" : "PAGE - / 2" ); + sprintf( sText, !VideoGetSWPAGE2() ? "PAGE 1 / -" : "PAGE - / 2" ); PrintTextCursorY( sText, rect ); // $C056 / $C057 LORES/HIRES = HIRESOFF/HIRESON = SW.LORES/SW.HIRES // LO / HIRES // LO / ----- // -- / HIRES - sprintf( sText, !(g_bVideoMode & VF_HIRES) ? "LO /-- RES" : "---/HI RES" ); + sprintf( sText, !VideoGetSWHIRES() ? "LO /-- RES" : "---/HI RES" ); PrintTextCursorY( sText, rect ); PrintTextCursorY( "", rect ); // Extended soft switches - sprintf( sText, !(g_bVideoMode & VF_80COL) ? "40 / -- COL" : "-- / 80 COL" ); + sprintf( sText, !VideoGetSW80COL() ? "40 / -- COL" : "-- / 80 COL" ); PrintTextCursorY( sText, rect ); - sprintf(sText, (g_nAltCharSetOffset == 0) ? "ASCII/-----" : "-----/MOUSE" ); + sprintf(sText, VideoGetSWAltCharSet() ? "ASCII/-----" : "-----/MOUSE" ); PrintTextCursorY( sText, rect ); // 280/560 HGR - sprintf(sText, !(g_bVideoMode & VF_DHIRES) ? "HGR / ----" : "--- / DHGR" ); + sprintf(sText, !VideoGetSWDHIRES() ? "HGR / ----" : "--- / DHGR" ); PrintTextCursorY( sText, rect ); #else //SOFTSWITCH_OLD // See: VideoSetMode() @@ -2778,25 +2778,25 @@ void DrawSoftSwitches( int iSoftSwitch ) bool bSet; // $C050 / $C051 = TEXTOFF/TEXTON = SW.TXTCLR/SW.TXTSET - bSet = !(g_bVideoMode & VF_TEXT); + bSet = !VideoGetSWTEXT(); _DrawSoftSwitch( rect, 0xC050, bSet, NULL, "GR.", "TEXT" ); // $C052 / $C053 = MIXEDOFF/MIXEDON = SW.MIXCLR/SW.MIXSET // FULL/MIXED // MIX OFF/ON - bSet = !(g_bVideoMode & VF_MIXED); + bSet = !VideoGetSWMIXED(); _DrawSoftSwitch( rect, 0xC052, bSet, NULL, "FULL", "MIX" ); // $C054 / $C055 = PAGE1/PAGE2 = PAGE2OFF/PAGE2ON = SW.LOWSCR/SW.HISCR // PAGE 1 / 2 - bSet = !(g_bVideoMode & VF_PAGE2); + bSet = !VideoGetSWPAGE2(); _DrawSoftSwitch( rect, 0xC054, bSet, "PAGE ", "1", "2" ); // $C056 / $C057 LORES/HIRES = HIRESOFF/HIRESON = SW.LORES/SW.HIRES // LO / HIRES // LO / ----- // -- / HIRES - bSet = !(g_bVideoMode & VF_HIRES); + bSet = !VideoGetSWHIRES(); _DrawSoftSwitch( rect, 0xC056, bSet, NULL, "LO", "HI", "RES" ); DebuggerSetColorBG( DebuggerGetColor( BG_INFO )); @@ -2805,20 +2805,20 @@ void DrawSoftSwitches( int iSoftSwitch ) // 280/560 HGR // C05E = ON, C05F = OFF - bSet = (g_bVideoMode & VF_DHIRES) ? true : false; + bSet = VideoGetSWDHIRES(); _DrawSoftSwitch( rect, 0xC05E, bSet, NULL, "DHGR", "HGR" ); // Extended soft switches // C00C = off, C00D = on - bSet = !(g_bVideoMode & VF_80COL); + bSet = !VideoGetSW80COL(); _DrawSoftSwitch( rect, 0xC00C, bSet, "Col", "40", "80" ); // C00E = off, C00F = on - bSet = (g_nAltCharSetOffset == 0); + bSet = VideoGetSWAltCharSet(); _DrawSoftSwitch( rect, 0xC00E, bSet, NULL, "ASC", "MOUS" ); // ASCII/MouseText // C000 = 80STOREOFF, C001 = 80STOREON - bSet = !(g_bVideoMode & VF_MASK2); + bSet = !VideoGetSW80STORE(); _DrawSoftSwitch( rect, 0xC000, bSet, "80Sto", "0", "1" ); #endif // SOFTSWITCH_OLD } diff --git a/source/Video.cpp b/source/Video.cpp index 9060d26e..58dbfc27 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -197,10 +197,21 @@ 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_bVideoMode & VF_80COL) #define SW_DHIRES (g_bVideoMode & VF_DHIRES) #define SW_HIRES (g_bVideoMode & VF_HIRES) - #define SW_MASK2 (g_bVideoMode & VF_MASK2) + #define SW_80STORE (g_bVideoMode & VF_80STORE) #define SW_MIXED (g_bVideoMode & VF_MIXED) #define SW_PAGE2 (g_bVideoMode & VF_PAGE2) #define SW_TEXT (g_bVideoMode & VF_TEXT) @@ -261,24 +272,21 @@ static BYTE colormixbuffer[6]; static WORD colormixmap[6][6][6]; // - int g_nAltCharSetOffset = 0; // alternate character set +static int g_nAltCharSetOffset = 0; // alternate character set - bool g_bVideoDisplayPage2 = 0; - /*bool*/ UINT g_VideoForceFullRedraw = 1; +static /*bool*/ UINT g_VideoForceFullRedraw = 1; static LPBYTE framebufferaddr = (LPBYTE)0; static LONG g_nFrameBufferPitch = 0; -BOOL g_bGraphicsMode = 0; -static BOOL hasrefreshed = 0; static DWORD lastpageflip = 0; COLORREF monochrome = RGB(0xC0,0xC0,0xC0); static BOOL rebuiltsource = 0; static LPBYTE vidlastmem = NULL; - int g_bVideoMode = VF_TEXT; +static int g_bVideoMode = VF_TEXT; DWORD g_eVideoType = VT_COLOR_TVEMU; - DWORD g_uHalfScanLines = true; // drop 50% scan lines for a more authentic look + DWORD g_uHalfScanLines = 1; // drop 50% scan lines for a more authentic look static bool g_bTextFlashState = false; @@ -1924,8 +1932,8 @@ BOOL VideoApparentlyDirty () return 1; DWORD address = (SW_HIRES && !SW_TEXT) - ? (0x20 << (int)g_bVideoDisplayPage2) - : (0x04 << (int)g_bVideoDisplayPage2); + ? (0x20 << (SW_PAGE2 ? 1 : 0)) + : (0x04 << (SW_PAGE2 ? 1 : 0)); DWORD length = (SW_HIRES && !SW_TEXT) ? 0x20 : 0x4; while (length--) if (*(memdirty+(address++)) & 2) @@ -1938,7 +1946,7 @@ BOOL VideoApparentlyDirty () // Scan visible text page for any flashing chars if((SW_TEXT || SW_MIXED) && (g_nAltCharSetOffset == 0)) { - BYTE* pnMemText = MemGetMainPtr(0x400 << (int)g_bVideoDisplayPage2); + BYTE* pnMemText = MemGetMainPtr(0x400 << (SW_PAGE2 ? 1 : 0)); // Scan 8 long-lines of 120 chars (at 128 char offsets): // . Skip 8-char holes in TEXT @@ -2154,25 +2162,6 @@ BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles) //=========================================================================== -// Check if we should call VideoRefreshScreen() based on unexpected page -// - Only called from 2 places in main ContinueExecution() loop -void VideoCheckPage(BOOL force) -{ - const bool bUnexpectedPage = (g_bVideoDisplayPage2 != (SW_PAGE2 != 0)); - //_ASSERT(!bUnexpectedPage); // [TC] Q: When does this happen? A: EG. When page-flipping && Scroll-Lock is pressed - - if (bUnexpectedPage && // Unexpected page && - (force || (emulmsec-lastpageflip > 500))) // force || >500ms since last flip - { - g_bVideoDisplayPage2 = (SW_PAGE2 != 0); - VideoRefreshScreen(); - hasrefreshed = 1; - lastpageflip = emulmsec; - } -} - -//=========================================================================== - /* // Drol expects = 80 68DE A5 02 LDX #02 @@ -2384,13 +2373,6 @@ void VideoDisplayLogo () DeleteObject(font); } -//=========================================================================== -BOOL VideoHasRefreshed () { - BOOL result = hasrefreshed; - hasrefreshed = 0; - return result; -} - //=========================================================================== void VideoRealizePalette(HDC dc) { @@ -2505,7 +2487,7 @@ VideoUpdateFuncPtr_t VideoRefreshScreen () // IN THE FRAME BUFFER. MARK CELLS IN WHICH REDRAWING HAS TAKEN PLACE AS // DIRTY. _Video_Dirty(); - _Video_SetupBanks( g_bVideoDisplayPage2 ); + _Video_SetupBanks( SW_PAGE2 != 0 ); VideoUpdateFuncPtr_t pfUpdate = SW_TEXT ? SW_80COL @@ -2694,15 +2676,8 @@ void VideoReinitialize () void VideoResetState () { g_nAltCharSetOffset = 0; - g_bVideoDisplayPage2 = 0; g_bVideoMode = VF_TEXT; g_VideoForceFullRedraw = 1; - -#if 0 // Debug HGR2 without having to exec 6502 code - g_bVideoDisplayPage2 = 1; - g_bVideoMode = VF_TEXT | VF_HIRES; -#endif - } @@ -2711,10 +2686,12 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) { address &= 0xFF; DWORD oldpage2 = SW_PAGE2; - int oldvalue = g_nAltCharSetOffset+(int)(g_bVideoMode & ~(VF_MASK2 | VF_PAGE2)); - switch (address) { - case 0x00: g_bVideoMode &= ~VF_MASK2; break; - case 0x01: g_bVideoMode |= VF_MASK2; break; + int oldvalue = g_nAltCharSetOffset+(int)(g_bVideoMode & ~(VF_80STORE | VF_PAGE2)); + + switch (address) + { + case 0x00: g_bVideoMode &= ~VF_80STORE; break; + case 0x01: g_bVideoMode |= VF_80STORE; break; case 0x0C: if (!IS_APPLE2) g_bVideoMode &= ~VF_80COL; break; case 0x0D: if (!IS_APPLE2) g_bVideoMode |= VF_80COL; break; case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off @@ -2730,29 +2707,21 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) case 0x5E: if (!IS_APPLE2) g_bVideoMode |= VF_DHIRES; break; case 0x5F: if (!IS_APPLE2) g_bVideoMode &= ~VF_DHIRES; break; } - if (SW_MASK2) + + if (SW_80STORE) g_bVideoMode &= ~VF_PAGE2; - if (oldvalue != g_nAltCharSetOffset+(int)(g_bVideoMode & ~(VF_MASK2 | VF_PAGE2))) { - g_bGraphicsMode = !SW_TEXT; - g_VideoForceFullRedraw = 1; - } - if (g_bFullSpeed && oldpage2 && !SW_PAGE2) { - static DWORD lasttime = 0; - DWORD currtime = GetTickCount(); - if (currtime-lasttime >= 20) - lasttime = currtime; - else - oldpage2 = SW_PAGE2; + + if (oldvalue != g_nAltCharSetOffset+(int)(g_bVideoMode & ~(VF_80STORE | VF_PAGE2))) + { + g_VideoForceFullRedraw = 1; } if (oldpage2 != SW_PAGE2) { - g_bVideoDisplayPage2 = (SW_PAGE2 != 0); if (!g_VideoForceFullRedraw) { #if 1 VideoRefreshScreen(); - hasrefreshed = 1; #else g_VideoForceFullRedraw = 1; // GH#129,GH204: Defer the redraw until the main ContinueExecution() loop (TODO: What effect does this have on other games?) #endif @@ -2766,7 +2735,7 @@ BYTE VideoSetMode (WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles) //=========================================================================== // Called at 60Hz (every 16.666ms) -void VideoUpdateFlash() +static void VideoUpdateFlash() { static UINT nTextFlashCnt = 0; @@ -2788,11 +2757,75 @@ void VideoUpdateFlash() //=========================================================================== -bool VideoGetSW80COL() +// Called from main-loop every 17030 cycles (ie. 60Hz when CPU = 1MHz) +void VideoEndOfVideoFrame(void) +{ + 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; } +bool VideoGetSWDHIRES(void) +{ + return SW_DHIRES ? true : false; +} + +bool VideoGetSWHIRES(void) +{ + return SW_HIRES ? true : false; +} + +bool VideoGetSW80STORE(void) +{ + return SW_80STORE ? true : false; +} + +bool VideoGetSWMIXED(void) +{ + return SW_MIXED ? true : false; +} + +bool VideoGetSWPAGE2(void) +{ + return SW_PAGE2 ? true : false; +} + +bool VideoGetSWTEXT(void) +{ + return SW_TEXT ? true : false; +} + +bool VideoGetSWAltCharSet(void) +{ + return g_nAltCharSetOffset == 0; +} + +//=========================================================================== + +void VideoSetForceFullRedraw(void) +{ + g_VideoForceFullRedraw = 1; +} + //=========================================================================== DWORD VideoGetSnapshot(SS_IO_Video* pSS) @@ -2808,12 +2841,6 @@ DWORD VideoSetSnapshot(SS_IO_Video* pSS) { g_nAltCharSetOffset = !pSS->bAltCharSet ? 0 : 256; g_bVideoMode = pSS->dwVidMode; - - // - - g_bGraphicsMode = !SW_TEXT; - g_bVideoDisplayPage2 = (SW_PAGE2 != 0); - return 0; } diff --git a/source/Video.h b/source/Video.h index afee07c5..9aa270b9 100644 --- a/source/Video.h +++ b/source/Video.h @@ -19,17 +19,6 @@ extern TCHAR g_aVideoChoices[]; extern char *g_apVideoModeDesc[ NUM_VIDEO_MODES ]; - enum VideoFlag_e - { - VF_80COL = 0x00000001, - VF_DHIRES = 0x00000002, - VF_HIRES = 0x00000004, - VF_MASK2 = 0x00000008, - VF_MIXED = 0x00000010, - VF_PAGE2 = 0x00000020, - VF_TEXT = 0x00000040 - }; - enum AppleFont_e { // 40-Column mode is 1x Zoom (default) @@ -57,15 +46,11 @@ enum AppleFont_e extern HBITMAP g_hLogoBitmap; -extern BOOL g_bGraphicsMode; extern COLORREF monochrome; // saved extern DWORD g_eVideoType; // saved extern DWORD g_uHalfScanLines; // saved extern LPBYTE g_pFramebufferbits; -extern int g_nAltCharSetOffset; -extern int g_bVideoMode; // g_bVideoMode - typedef bool (*VideoUpdateFuncPtr_t)(int,int,int,int,int); // Prototypes _______________________________________________________ @@ -74,12 +59,10 @@ void CreateColorMixMap(); BOOL VideoApparentlyDirty (); void VideoBenchmark (); -void VideoCheckPage (BOOL); void VideoChooseColor (); void VideoDestroy (); void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale); void VideoDisplayLogo (); -BOOL VideoHasRefreshed (); void VideoInitialize (); void VideoRealizePalette (HDC); VideoUpdateFuncPtr_t VideoRedrawScreen (UINT); @@ -89,15 +72,22 @@ void VideoReinitialize (); void VideoResetState (); WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles); bool VideoGetVbl(DWORD uExecutedCycles); -void VideoUpdateFlash(); -bool VideoGetSW80COL(); +void VideoEndOfVideoFrame(void); + +bool VideoGetSW80COL(void); +bool VideoGetSWDHIRES(void); +bool VideoGetSWHIRES(void); +bool VideoGetSW80STORE(void); +bool VideoGetSWMIXED(void); +bool VideoGetSWPAGE2(void); +bool VideoGetSWTEXT(void); +bool VideoGetSWAltCharSet(void); + +void VideoSetForceFullRedraw(void); + DWORD VideoGetSnapshot(SS_IO_Video* pSS); DWORD VideoSetSnapshot(SS_IO_Video* pSS); - -extern bool g_bVideoDisplayPage2; -extern /*bool*/ UINT g_VideoForceFullRedraw; - void _Video_Dirty(); void _Video_RedrawScreen( VideoUpdateFuncPtr_t update, bool bMixed = false ); void _Video_SetupBanks( bool bBank2 );