From 2a7191f5ce658f99b0db972b81676cc2a2a50388 Mon Sep 17 00:00:00 2001 From: Andrea Date: Sat, 21 Nov 2020 20:57:56 +0000 Subject: [PATCH] Split Video.cpp to WinVideo.cpp to remove most of the Win32 specific functions (PR #872) . Moved DirectInput.cpp/h and WinVideo.cpp/h to a new "Windows" folder. --- AppleWinExpress2008.vcproj | 28 +- AppleWinExpress2019.vcxproj | 6 +- AppleWinExpress2019.vcxproj.filters | 17 +- source/AppleWin.cpp | 4 +- source/CPU.cpp | 1 - source/Configuration/PageConfig.cpp | 2 +- source/Debugger/Debug.cpp | 1 + source/Disk.cpp | 1 + source/Frame.cpp | 6 +- source/Keyboard.cpp | 2 +- source/Speaker.cpp | 2 +- source/Video.cpp | 611 +------------------------ source/Video.h | 15 +- source/{ => Windows}/DirectInput.cpp | 2 +- source/{ => Windows}/DirectInput.h | 0 source/Windows/WinVideo.cpp | 638 +++++++++++++++++++++++++++ source/Windows/WinVideo.h | 19 + 17 files changed, 712 insertions(+), 643 deletions(-) rename source/{ => Windows}/DirectInput.cpp (99%) rename source/{ => Windows}/DirectInput.h (100%) create mode 100644 source/Windows/WinVideo.cpp create mode 100644 source/Windows/WinVideo.h diff --git a/AppleWinExpress2008.vcproj b/AppleWinExpress2008.vcproj index c834422a..700a0630 100644 --- a/AppleWinExpress2008.vcproj +++ b/AppleWinExpress2008.vcproj @@ -621,14 +621,6 @@ RelativePath=".\source\CardManager.h" > - - - - @@ -958,6 +950,26 @@ > + + + + + + + + + + diff --git a/AppleWinExpress2019.vcxproj b/AppleWinExpress2019.vcxproj index 1b71176c..561d2aa1 100644 --- a/AppleWinExpress2019.vcxproj +++ b/AppleWinExpress2019.vcxproj @@ -62,7 +62,6 @@ - @@ -109,6 +108,8 @@ + + @@ -140,7 +141,6 @@ - @@ -214,6 +214,8 @@ NotUsing + + diff --git a/AppleWinExpress2019.vcxproj.filters b/AppleWinExpress2019.vcxproj.filters index 04f6de5f..faa855c1 100644 --- a/AppleWinExpress2019.vcxproj.filters +++ b/AppleWinExpress2019.vcxproj.filters @@ -202,8 +202,11 @@ Source Files\Emulator - - Source Files\Emulator + + Source Files\Windows + + + Source Files\Windows @@ -492,8 +495,11 @@ Source Files\Emulator - - Source Files\Emulator + + Source Files\Windows + + + Source Files\Windows @@ -735,6 +741,9 @@ {15b450e4-f89f-4d80-9c44-48b32f33f3e3} + + {95d0abc3-4007-4eb0-8222-4579b565de23} + diff --git a/source/AppleWin.cpp b/source/AppleWin.cpp index b7e86d57..068f3f87 100644 --- a/source/AppleWin.cpp +++ b/source/AppleWin.cpp @@ -54,7 +54,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Speech.h" #endif #include "SynchronousEventManager.h" -#include "Video.h" +#include "Windows/WinVideo.h" #include "RGBMonitor.h" #include "NTSC.h" @@ -2064,7 +2064,7 @@ static void RepeatInitialization(void) JoyInitialize(); LogFileOutput("Main: JoyInitialize()\n"); - VideoInitialize(); // g_pFramebufferinfo been created now + DirectVideoInitialize(); // g_pFramebufferinfo been created now LogFileOutput("Main: VideoInitialize()\n"); LogFileOutput("Main: FrameCreateWindow() - pre\n"); diff --git a/source/CPU.cpp b/source/CPU.cpp index b4eda4c0..eb32b7ba 100644 --- a/source/CPU.cpp +++ b/source/CPU.cpp @@ -89,7 +89,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "CPU.h" #include "AppleWin.h" #include "CardManager.h" -#include "Frame.h" #include "Memory.h" #include "Mockingboard.h" #include "MouseInterface.h" diff --git a/source/Configuration/PageConfig.cpp b/source/Configuration/PageConfig.cpp index ddeeb225..0d97d4a5 100644 --- a/source/Configuration/PageConfig.cpp +++ b/source/Configuration/PageConfig.cpp @@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../Frame.h" #include "../Registry.h" #include "../SerialComms.h" -#include "../Video.h" +#include "../Windows/WinVideo.h" #include "../resource/resource.h" CPageConfig* CPageConfig::ms_this = 0; // reinit'd in ctor diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 251762d6..2ad4386c 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -43,6 +43,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../Memory.h" #include "../NTSC.h" #include "../SoundCore.h" // SoundCore_SetFade() +#include "../Windows/WinVideo.h" #include "../Video.h" // #define DEBUG_COMMAND_HELP 1 diff --git a/source/Disk.cpp b/source/Disk.cpp index ef1f68ee..235c6592 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -43,6 +43,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Registry.h" #include "SaveState.h" #include "Video.h" +#include "Windows/WinVideo.h" #include "YamlHelper.h" #include "../resource/resource.h" diff --git a/source/Frame.cpp b/source/Frame.cpp index 577a5d45..32e2aabb 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -40,7 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Memory.h" #include "Mockingboard.h" #include "MouseInterface.h" -#include "DirectInput.h" +#include "Windows/DirectInput.h" #include "NTSC.h" #include "ParallelPrinter.h" #include "Pravets.h" @@ -52,7 +52,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifdef USE_SPEECH_API #include "Speech.h" #endif -#include "Video.h" +#include "Windows/WinVideo.h" #include "../resource/resource.h" #include "Configuration/PropertySheet.h" @@ -1162,7 +1162,7 @@ LRESULT CALLBACK FrameWndProc ( CpuDestroy(); MemDestroy(); SpkrDestroy(); - VideoDestroy(); + DirectVideoDestroy(); MB_Destroy(); DeleteGdiObjects(); DIMouse::DirectInputUninit(window); // NB. do before window is destroyed diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index a534e794..00939557 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Pravets.h" #include "Tape.h" #include "YamlHelper.h" -#include "Video.h" // Needed by TK3000 //e, to refresh the frame at each |Mode| change +#include "Windows/WinVideo.h" // Needed by TK3000 //e, to refresh the frame at each |Mode| change #include "Log.h" static BYTE asciicode[2][10] = { diff --git a/source/Speaker.cpp b/source/Speaker.cpp index 42f693ef..1b4bbe6d 100644 --- a/source/Speaker.cpp +++ b/source/Speaker.cpp @@ -35,7 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Log.h" #include "Memory.h" #include "SoundCore.h" -#include "Video.h" // VideoRedrawScreen() +#include "Windows/WinVideo.h" // VideoRedrawScreen() #include "YamlHelper.h" #include "Riff.h" diff --git a/source/Video.cpp b/source/Video.cpp index 59d3e152..423d4846 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -31,17 +31,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Video.h" #include "AppleWin.h" #include "CPU.h" -#include "Disk.h" // DiskUpdateDriveState() #include "Frame.h" -#include "Keyboard.h" #include "Log.h" #include "Memory.h" #include "Registry.h" #include "NTSC.h" #include "RGBMonitor.h" -#include "../resource/resource.h" -#include "Configuration/PropertySheet.h" #include "YamlHelper.h" #define SW_80COL (g_uVideoMode & VF_80COL) @@ -54,7 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // Globals (Public) - uint8_t *g_pFramebufferbits = NULL; // last drawn frame + uint8_t *g_pFramebufferbits = NULL; // last drawn frame (initialized in DirectVideoInitialize) int g_nAltCharSetOffset = 0; // alternate character set // Globals (Private) @@ -77,14 +73,6 @@ int const kVPresetLine = 256; // line when V state presets int const kVSyncLines = 4; // lines per VSync duration int const kVDisplayableScanLines = 192; // max displayable scanlines -static COLORREF customcolors[256]; // MONOCHROME is last custom color - -static HBITMAP g_hDeviceBitmap; -static HDC g_hDeviceDC; -static LPBITMAPINFO g_pFramebufferinfo = NULL; - - HBITMAP g_hLogoBitmap; - COLORREF g_nMonochromeRGB = RGB(0xC0,0xC0,0xC0); uint32_t g_uVideoMode = VF_TEXT; // Current Video Mode (this is the last set one as it may change mid-scan line!) @@ -94,8 +82,6 @@ static VideoStyle_e g_eVideoStyle = VS_HALF_SCANLINES; static bool g_bVideoScannerNTSC = true; // NTSC video scanning (or PAL) -static LPDIRECTDRAW g_lpDD = NULL; - //------------------------------------- // NOTE: KEEP IN SYNC: VideoType_e g_aVideoChoices g_apVideoModeDesc @@ -130,39 +116,10 @@ static LPDIRECTDRAW g_lpDD = NULL; bool g_bDisplayPrintScreenFileName = false; bool g_bShowPrintScreenWarningDialog = true; - void Util_MakeScreenShotFileName( TCHAR *pFinalFileName_, DWORD chars ); - bool Util_TestScreenShotFileName( const TCHAR *pFileName ); - void Video_SaveScreenShot( const VideoScreenShot_e ScreenShotType, const TCHAR *pScreenShotFileName ); - void Video_MakeScreenShot( FILE *pFile, const VideoScreenShot_e ScreenShotType ); - void videoCreateDIBSection(); - -//=========================================================================== -void VideoInitialize () -{ - // RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET - VideoResetState(); - - // LOAD THE LOGO - g_hLogoBitmap = LoadBitmap( g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN) ); - - // CREATE A BITMAPINFO STRUCTURE FOR THE FRAME BUFFER - g_pFramebufferinfo = (LPBITMAPINFO)VirtualAlloc( - NULL, - sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD), - MEM_COMMIT, - PAGE_READWRITE); - - ZeroMemory(g_pFramebufferinfo,sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD)); - g_pFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - g_pFramebufferinfo->bmiHeader.biWidth = GetFrameBufferWidth(); - g_pFramebufferinfo->bmiHeader.biHeight = GetFrameBufferHeight(); - g_pFramebufferinfo->bmiHeader.biPlanes = 1; - g_pFramebufferinfo->bmiHeader.biBitCount = 32; - g_pFramebufferinfo->bmiHeader.biCompression = BI_RGB; - g_pFramebufferinfo->bmiHeader.biClrUsed = 0; - - videoCreateDIBSection(); -} + static void Util_MakeScreenShotFileName( TCHAR *pFinalFileName_, DWORD chars ); + static bool Util_TestScreenShotFileName( const TCHAR *pFileName ); + static void Video_MakeScreenShot( FILE *pFile, const VideoScreenShot_e ScreenShotType ); + static void videoCreateDIBSection(); //=========================================================================== @@ -170,448 +127,6 @@ void VideoInitialize () // ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- // -//=========================================================================== -void VideoBenchmark () { - _ASSERT(g_nAppMode == MODE_BENCHMARK); - Sleep(500); - - // PREPARE TWO DIFFERENT FRAME BUFFERS, EACH OF WHICH HAVE HALF OF THE - // BYTES SET TO 0x14 AND THE OTHER HALF SET TO 0xAA - int loop; - LPDWORD mem32 = (LPDWORD)mem; - for (loop = 4096; loop < 6144; loop++) - *(mem32+loop) = ((loop & 1) ^ ((loop & 0x40) >> 6)) ? 0x14141414 - : 0xAAAAAAAA; - for (loop = 6144; loop < 8192; loop++) - *(mem32+loop) = ((loop & 1) ^ ((loop & 0x40) >> 6)) ? 0xAAAAAAAA - : 0x14141414; - - // SEE HOW MANY TEXT FRAMES PER SECOND WE CAN PRODUCE WITH NOTHING ELSE - // 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(); - DWORD milliseconds = GetTickCount(); - while (GetTickCount() == milliseconds) ; - milliseconds = GetTickCount(); - DWORD cycle = 0; - do { - if (cycle & 1) - FillMemory(mem+0x400,0x400,0x14); - else - CopyMemory(mem+0x400,mem+((cycle & 2) ? 0x4000 : 0x6000),0x400); - VideoRefreshScreen(); - if (cycle++ >= 3) - cycle = 0; - totaltextfps++; - } while (GetTickCount() - milliseconds < 1000); - - // SEE HOW MANY HIRES FRAMES PER SECOND WE CAN PRODUCE WITH NOTHING ELSE - // GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO - // SIMULATE THE ACTIVITY OF AN AVERAGE GAME - DWORD totalhiresfps = 0; - g_uVideoMode = VF_HIRES; - FillMemory(mem+0x2000,0x2000,0x14); - VideoRedrawScreen(); - milliseconds = GetTickCount(); - while (GetTickCount() == milliseconds) ; - milliseconds = GetTickCount(); - cycle = 0; - do { - if (cycle & 1) - FillMemory(mem+0x2000,0x2000,0x14); - else - CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000); - VideoRefreshScreen(); - if (cycle++ >= 3) - cycle = 0; - totalhiresfps++; - } while (GetTickCount() - milliseconds < 1000); - - // DETERMINE HOW MANY 65C02 CLOCK CYCLES WE CAN EMULATE PER SECOND WITH - // NOTHING ELSE GOING ON - DWORD totalmhz10[2] = {0,0}; // bVideoUpdate & !bVideoUpdate - for (UINT i=0; i<2; i++) - { - CpuSetupBenchmark(); - milliseconds = GetTickCount(); - while (GetTickCount() == milliseconds) ; - milliseconds = GetTickCount(); - do { - CpuExecute(100000, i==0 ? true : false); - totalmhz10[i]++; - } while (GetTickCount() - milliseconds < 1000); - } - - // IF THE PROGRAM COUNTER IS NOT IN THE EXPECTED RANGE AT THE END OF THE - // CPU BENCHMARK, REPORT AN ERROR AND OPTIONALLY TRACK IT DOWN - if ((regs.pc < 0x300) || (regs.pc > 0x400)) - if (MessageBox(g_hFrameWindow, - TEXT("The emulator has detected a problem while running ") - TEXT("the CPU benchmark. Would you like to gather more ") - TEXT("information?"), - TEXT("Benchmarks"), - MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES) { - BOOL error = 0; - WORD lastpc = 0x300; - int loop = 0; - while ((loop < 10000) && !error) { - CpuSetupBenchmark(); - CpuExecute(loop, true); - if ((regs.pc < 0x300) || (regs.pc > 0x400)) - error = 1; - else { - lastpc = regs.pc; - ++loop; - } - } - if (error) { - TCHAR outstr[256]; - wsprintf(outstr, - TEXT("The emulator experienced an error %u clock cycles ") - TEXT("into the CPU benchmark. Prior to the error, the ") - TEXT("program counter was at $%04X. After the error, it ") - TEXT("had jumped to $%04X."), - (unsigned)loop, - (unsigned)lastpc, - (unsigned)regs.pc); - MessageBox(g_hFrameWindow, - outstr, - TEXT("Benchmarks"), - MB_ICONINFORMATION | MB_SETFOREGROUND); - } - else - MessageBox(g_hFrameWindow, - TEXT("The emulator was unable to locate the exact ") - TEXT("point of the error. This probably means that ") - TEXT("the problem is external to the emulator, ") - TEXT("happening asynchronously, such as a problem in ") - TEXT("a timer interrupt handler."), - TEXT("Benchmarks"), - MB_ICONINFORMATION | MB_SETFOREGROUND); - } - - // DO A REALISTIC TEST OF HOW MANY FRAMES PER SECOND WE CAN PRODUCE - // WITH FULL EMULATION OF THE CPU, JOYSTICK, AND DISK HAPPENING AT - // THE SAME TIME - DWORD realisticfps = 0; - FillMemory(mem+0x2000,0x2000,0xAA); - VideoRedrawScreen(); - milliseconds = GetTickCount(); - while (GetTickCount() == milliseconds) ; - milliseconds = GetTickCount(); - cycle = 0; - do { - if (realisticfps < 10) { - int cycles = 100000; - while (cycles > 0) { - DWORD executedcycles = CpuExecute(103, true); - cycles -= executedcycles; - GetCardMgr().GetDisk2CardMgr().UpdateDriveState(executedcycles); - JoyUpdateButtonLatch(executedcycles); - } - } - if (cycle & 1) - FillMemory(mem+0x2000,0x2000,0xAA); - else - CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000); - VideoRedrawScreen(); - if (cycle++ >= 3) - cycle = 0; - realisticfps++; - } while (GetTickCount() - milliseconds < 1000); - - // DISPLAY THE RESULTS - VideoDisplayLogo(); - TCHAR outstr[256]; - wsprintf(outstr, - TEXT("Pure Video FPS:\t%u hires, %u text\n") - TEXT("Pure CPU MHz:\t%u.%u%s (video update)\n") - TEXT("Pure CPU MHz:\t%u.%u%s (full-speed)\n\n") - TEXT("EXPECTED AVERAGE VIDEO GAME\n") - TEXT("PERFORMANCE: %u FPS"), - (unsigned)totalhiresfps, - (unsigned)totaltextfps, - (unsigned)(totalmhz10[0] / 10), (unsigned)(totalmhz10[0] % 10), (LPCTSTR)(IS_APPLE2 ? TEXT(" (6502)") : TEXT("")), - (unsigned)(totalmhz10[1] / 10), (unsigned)(totalmhz10[1] % 10), (LPCTSTR)(IS_APPLE2 ? TEXT(" (6502)") : TEXT("")), - (unsigned)realisticfps); - MessageBox(g_hFrameWindow, - outstr, - TEXT("Benchmarks"), - MB_ICONINFORMATION | MB_SETFOREGROUND); -} - -// This is called from PageConfig -//=========================================================================== -void VideoChooseMonochromeColor () -{ - CHOOSECOLOR cc; - ZeroMemory(&cc,sizeof(CHOOSECOLOR)); - cc.lStructSize = sizeof(CHOOSECOLOR); - cc.hwndOwner = g_hFrameWindow; - cc.rgbResult = g_nMonochromeRGB; - cc.lpCustColors = customcolors + 1; - cc.Flags = CC_RGBINIT | CC_SOLIDCOLOR; - if (ChooseColor(&cc)) - { - g_nMonochromeRGB = cc.rgbResult; - VideoReinitialize(); - if ((g_nAppMode != MODE_LOGO) && (g_nAppMode != MODE_DEBUG)) - { - VideoRedrawScreen(); - } - Config_Save_Video(); - } -} - -//=========================================================================== -void VideoDestroy () { - - // DESTROY BUFFERS - VirtualFree(g_pFramebufferinfo,0,MEM_RELEASE); - g_pFramebufferinfo = NULL; - - // DESTROY FRAME BUFFER - DeleteDC(g_hDeviceDC); - DeleteObject(g_hDeviceBitmap); - g_hDeviceDC = (HDC)0; - g_hDeviceBitmap = (HBITMAP)0; - - // DESTROY LOGO - if (g_hLogoBitmap) { - DeleteObject(g_hLogoBitmap); - g_hLogoBitmap = (HBITMAP)0; - } - - NTSC_Destroy(); -} - -//=========================================================================== - -static void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale) -{ - HDC hSrcDC = CreateCompatibleDC( hDstDC ); - SelectObject( hSrcDC, g_hLogoBitmap ); - StretchBlt( - hDstDC, // hdcDest - xoff, yoff, // nXDest, nYDest - scale * srcw, scale * srch, // nWidth, nHeight - hSrcDC, // hdcSrc - 0, 0, // nXSrc, nYSrc - srcw, srch, - SRCCOPY // dwRop - ); - - DeleteObject( hSrcDC ); -} - -//=========================================================================== -void VideoDisplayLogo () -{ - int nLogoX = 0, nLogoY = 0; - int scale = GetViewportScale(); - - HDC hFrameDC = FrameGetDC(); - - // DRAW THE LOGO - SelectObject(hFrameDC, GetStockObject(NULL_PEN)); - - if (g_hLogoBitmap) - { - BITMAP bm; - if (GetObject(g_hLogoBitmap, sizeof(bm), &bm)) - { - nLogoX = (g_nViewportCX - scale*bm.bmWidth )/2; - nLogoY = (g_nViewportCY - scale*bm.bmHeight)/2; - - if( IsFullScreen() ) - { - nLogoX += GetFullScreenOffsetX(); - nLogoY += GetFullScreenOffsetY(); - } - - 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, - sFontName ); - SelectObject(hFrameDC,font); - SetTextAlign(hFrameDC,TA_RIGHT | TA_TOP); - SetBkMode(hFrameDC,TRANSPARENT); - - TCHAR szVersion[ 64 ]; - StringCbPrintf(szVersion, 64, "Version %s", VERSIONSTRING); - int xoff = GetFullScreenOffsetX(), yoff = GetFullScreenOffsetY(); - -#define DRAWVERSION(x,y,c) \ - SetTextColor(hFrameDC,c); \ - TextOut(hFrameDC, \ - scale*540+x+xoff,scale*358+y+yoff, \ - szVersion, \ - strlen(szVersion)); - - if (GetDeviceCaps(hFrameDC,PLANES) * GetDeviceCaps(hFrameDC,BITSPIXEL) <= 4) { - DRAWVERSION( 2, 2,RGB(0x00,0x00,0x00)); - DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); - DRAWVERSION( 0, 0,RGB(0xFF,0x00,0xFF)); - } else { - DRAWVERSION( 1, 1,PALETTERGB(0x30,0x30,0x70)); - DRAWVERSION(-1,-1,PALETTERGB(0xC0,0x70,0xE0)); - DRAWVERSION( 0, 0,PALETTERGB(0x70,0x30,0xE0)); - } - -#if _DEBUG - StringCbPrintf(szVersion, 64, "DEBUG"); - DRAWVERSION( 2, -358*scale,RGB(0x00,0x00,0x00)); - DRAWVERSION( 1, -357*scale,RGB(0x00,0x00,0x00)); - DRAWVERSION( 0, -356*scale,RGB(0xFF,0x00,0xFF)); -#endif - -#undef DRAWVERSION - - DeleteObject(font); -} - -//=========================================================================== - -void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInit /*=false*/) -{ - static DWORD dwFullSpeedStartTime = 0; -// static bool bValid = false; - - if (bInit) - { - // Just entered full-speed mode -// bValid = false; - dwFullSpeedStartTime = GetTickCount(); - return; - } - - DWORD dwFullSpeedDuration = GetTickCount() - dwFullSpeedStartTime; - if (dwFullSpeedDuration <= 16) // Only update after every realtime ~17ms of *continuous* full-speed - return; - - dwFullSpeedStartTime += dwFullSpeedDuration; - - // - -#if 0 - 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) - { - // 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; - } - else - { - 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); - } - } - - 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; -#else - VideoRedrawScreenAfterFullSpeed(dwCyclesThisFrame); -#endif -} - -//=========================================================================== - -void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame) -{ - NTSC_VideoClockResync(dwCyclesThisFrame); - VideoRedrawScreen(); // Better (no flicker) than using: NTSC_VideoReinitialize() or VideoReinitialize() -} - -//=========================================================================== - -void VideoRedrawScreen (void) -{ - // NB. Can't rely on g_uVideoMode being non-zero (ie. so it can double up as a flag) since 'GR,PAGE1,non-mixed' mode == 0x00. - VideoRefreshScreen( g_uVideoMode, true ); -} - -//=========================================================================== - -void VideoRefreshScreen ( uint32_t uRedrawWholeScreenVideoMode /* =0*/, bool bRedrawWholeScreen /* =false*/ ) -{ - if (bRedrawWholeScreen || g_nAppMode == MODE_PAUSED) - { - // uVideoModeForWholeScreen set if: - // . MODE_DEBUG : always - // . MODE_RUNNING : called from VideoRedrawScreen(), eg. during full-speed - if (bRedrawWholeScreen) - NTSC_SetVideoMode( uRedrawWholeScreenVideoMode ); - NTSC_VideoRedrawWholeScreen(); - - // MODE_DEBUG|PAUSED: Need to refresh a 2nd time if changing video-type, otherwise could have residue from prev image! - // . eg. Amber -> B&W TV - if (g_nAppMode == MODE_DEBUG || g_nAppMode == MODE_PAUSED) - NTSC_VideoRedrawWholeScreen(); - } - - HDC hFrameDC = FrameGetDC(); - - if (hFrameDC) - { - int xSrc = GetFrameBufferBorderWidth(); - int ySrc = GetFrameBufferBorderHeight(); - - int xdest = IsFullScreen() ? GetFullScreenOffsetX() : 0; - int ydest = IsFullScreen() ? GetFullScreenOffsetY() : 0; - int wdest = g_nViewportCX; - int hdest = g_nViewportCY; - - SetStretchBltMode(hFrameDC, COLORONCOLOR); - StretchBlt( - hFrameDC, - xdest, ydest, - wdest, hdest, - g_hDeviceDC, - xSrc, ySrc, - GetFrameBufferBorderlessWidth(), GetFrameBufferBorderlessHeight(), - SRCCOPY); - } - -#ifdef NO_DIRECT_X -#else - //if (g_lpDD) g_lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); -#endif // NO_DIRECT_X - - GdiFlush(); -} - //=========================================================================== void VideoReinitialize (bool bInitVideoScannerAddress /*= true*/) { @@ -903,80 +418,6 @@ bool VideoGetVblBar(const DWORD uExecutedCycles) return g_nVideoClockVert < kVDisplayableScanLines; } - -//=========================================================================== - -#define MAX_DRAW_DEVICES 10 - -static char *draw_devices[MAX_DRAW_DEVICES]; -static GUID draw_device_guid[MAX_DRAW_DEVICES]; -static int num_draw_devices = 0; - -static BOOL CALLBACK DDEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext) -{ - int i = num_draw_devices; - if (i == MAX_DRAW_DEVICES) - return TRUE; - if (lpGUID != NULL) - memcpy(&draw_device_guid[i], lpGUID, sizeof (GUID)); - draw_devices[i] = _strdup(lpszDesc); - - if (g_fh) fprintf(g_fh, "%d: %s - %s\n",i,lpszDesc,lpszDrvName); - - num_draw_devices++; - return TRUE; -} - -bool DDInit(void) -{ -#ifdef NO_DIRECT_X - - return false; - -#else - HRESULT hr = DirectDrawEnumerate((LPDDENUMCALLBACK)DDEnumProc, NULL); - if (FAILED(hr)) - { - LogFileOutput("DSEnumerate failed (%08X)\n", hr); - return false; - } - - LogFileOutput("Number of draw devices = %d\n", num_draw_devices); - - bool bCreatedOK = false; - for (int x=0; xRelease(); (p)=NULL; } } - -void DDUninit(void) -{ - SAFE_RELEASE(g_lpDD); -} - -#undef SAFE_RELEASE - //=========================================================================== #define SCREENSHOT_BMP 1 @@ -1052,16 +493,6 @@ void Video_TakeScreenShot( const VideoScreenShot_e ScreenShotType ) g_nLastScreenShot++; } -void Video_RedrawAndTakeScreenShot( const TCHAR* pScreenshotFilename ) -{ - _ASSERT(pScreenshotFilename); - if (!pScreenshotFilename) - return; - - VideoRedrawScreen(); - Video_SaveScreenShot( SCREENSHOT_560x384, pScreenshotFilename ); -} - WinBmpHeader_t g_tBmpHeader; #if SCREENSHOT_TGA @@ -1218,7 +649,7 @@ static void Video_MakeScreenShot(FILE *pFile, const VideoScreenShot_e ScreenShot } //=========================================================================== -static void Video_SaveScreenShot( const VideoScreenShot_e ScreenShotType, const TCHAR *pScreenShotFileName ) +void Video_SaveScreenShot( const VideoScreenShot_e ScreenShotType, const TCHAR *pScreenShotFileName ) { FILE *pFile = fopen( pScreenShotFileName, "wb" ); if( pFile ) @@ -1413,36 +844,6 @@ void SetVideoRefreshRate(VideoRefreshRate_e rate) NTSC_SetRefreshRate(rate); } -//=========================================================================== -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); - - // DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER - ZeroMemory( g_pFramebufferbits, GetFrameBufferWidth()*GetFrameBufferHeight()*sizeof(bgra_t) ); - - // CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE FRAME BUFFER - NTSC_VideoInit( g_pFramebufferbits ); -} - //=========================================================================== const char* VideoGetAppWindowTitle(void) diff --git a/source/Video.h b/source/Video.h index 0d76f6fa..8377e9ca 100644 --- a/source/Video.h +++ b/source/Video.h @@ -167,7 +167,6 @@ struct WinBmpHeader4_t #endif // Globals __________________________________________________________ - extern COLORREF g_nMonochromeRGB; // saved to Registry extern uint32_t g_uVideoMode; extern DWORD g_eVideoType; // saved to Registry @@ -175,15 +174,6 @@ extern uint8_t *g_pFramebufferbits; // Prototypes _______________________________________________________ -void VideoBenchmark (); -void VideoChooseMonochromeColor (); // FIXME: Should be moved to PageConfig and call VideoSetMonochromeColor() -void VideoDestroy (); -void VideoDisplayLogo (); -void VideoInitialize (); -void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInit = false); -void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame); -void VideoRedrawScreen (void); -void VideoRefreshScreen (uint32_t uRedrawWholeScreenVideoMode = 0, bool bRedrawWholeScreen = false); void VideoReinitialize (bool bInitVideoScannerAddress = true); void VideoResetState (); enum VideoScanner_e {VS_FullAddr, VS_PartialAddrV, VS_PartialAddrH}; @@ -213,8 +203,8 @@ enum VideoScreenShot_e SCREENSHOT_280x192 }; void Video_TakeScreenShot( VideoScreenShot_e ScreenShotType ); -void Video_RedrawAndTakeScreenShot( const char* pScreenshotFilename ); void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel ); +void Video_SaveScreenShot(const VideoScreenShot_e ScreenShotType, const TCHAR* pScreenShotFileName); BYTE VideoSetMode(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles); @@ -238,7 +228,4 @@ bool IsVideoStyle(VideoStyle_e mask); VideoRefreshRate_e GetVideoRefreshRate(void); void SetVideoRefreshRate(VideoRefreshRate_e rate); -bool DDInit(void); -void DDUninit(void); - const char* VideoGetAppWindowTitle(void); diff --git a/source/DirectInput.cpp b/source/Windows/DirectInput.cpp similarity index 99% rename from source/DirectInput.cpp rename to source/Windows/DirectInput.cpp index e514ea2f..86597a67 100644 --- a/source/DirectInput.cpp +++ b/source/Windows/DirectInput.cpp @@ -34,7 +34,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //#define STRICT -#include "DirectInput.h" +#include "Windows/DirectInput.h" #include "SoundCore.h" // SAFE_RELEASE() #include "Log.h" #include "Common.h" diff --git a/source/DirectInput.h b/source/Windows/DirectInput.h similarity index 100% rename from source/DirectInput.h rename to source/Windows/DirectInput.h diff --git a/source/Windows/WinVideo.cpp b/source/Windows/WinVideo.cpp new file mode 100644 index 00000000..172f21c3 --- /dev/null +++ b/source/Windows/WinVideo.cpp @@ -0,0 +1,638 @@ +/* +AppleWin : An Apple //e emulator for Windows + +Copyright (C) 1994-1996, Michael O'Brien +Copyright (C) 1999-2001, Oliver Schmidt +Copyright (C) 2002-2005, Tom Charlesworth +Copyright (C) 2006-2010, Tom Charlesworth, Michael Pohoreski, Nick Westgate + +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 +*/ + +/* Description: Emulation of video modes + * + * Author: Various + */ + +#include "StdAfx.h" + +#include "Windows/WinVideo.h" +#include "AppleWin.h" +#include "Video.h" +#include "CPU.h" +#include "Joystick.h" +#include "Frame.h" +#include "Log.h" +#include "Memory.h" +#include "CardManager.h" +#include "NTSC.h" + +#include "../resource/resource.h" + +static COLORREF customcolors[256]; // MONOCHROME is last custom color +static HBITMAP g_hLogoBitmap; +static HBITMAP g_hDeviceBitmap; +static HDC g_hDeviceDC; +static LPBITMAPINFO g_pFramebufferinfo = NULL; + +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); + + // DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER + ZeroMemory(g_pFramebufferbits, GetFrameBufferWidth() * GetFrameBufferHeight() * sizeof(bgra_t)); + + // CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE FRAME BUFFER + NTSC_VideoInit(g_pFramebufferbits); +} + +// +// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- +// + +void DirectVideoInitialize() +{ + // RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET + VideoResetState(); + + // LOAD THE LOGO + g_hLogoBitmap = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN)); + + // CREATE A BITMAPINFO STRUCTURE FOR THE FRAME BUFFER + g_pFramebufferinfo = (LPBITMAPINFO)VirtualAlloc( + NULL, + sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD), + MEM_COMMIT, + PAGE_READWRITE); + + ZeroMemory(g_pFramebufferinfo, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)); + g_pFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + g_pFramebufferinfo->bmiHeader.biWidth = GetFrameBufferWidth(); + g_pFramebufferinfo->bmiHeader.biHeight = GetFrameBufferHeight(); + g_pFramebufferinfo->bmiHeader.biPlanes = 1; + g_pFramebufferinfo->bmiHeader.biBitCount = 32; + g_pFramebufferinfo->bmiHeader.biCompression = BI_RGB; + g_pFramebufferinfo->bmiHeader.biClrUsed = 0; + + videoCreateDIBSection(); +} + +void DirectVideoDestroy() +{ + + // DESTROY BUFFERS + VirtualFree(g_pFramebufferinfo, 0, MEM_RELEASE); + g_pFramebufferinfo = NULL; + + // DESTROY FRAME BUFFER + DeleteDC(g_hDeviceDC); + DeleteObject(g_hDeviceBitmap); + g_hDeviceDC = (HDC)0; + g_hDeviceBitmap = (HBITMAP)0; + g_pFramebufferbits = NULL; + + // DESTROY LOGO + if (g_hLogoBitmap) { + DeleteObject(g_hLogoBitmap); + g_hLogoBitmap = (HBITMAP)0; + } + + NTSC_Destroy(); +} + +//=========================================================================== +void VideoBenchmark () { + _ASSERT(g_nAppMode == MODE_BENCHMARK); + Sleep(500); + + // PREPARE TWO DIFFERENT FRAME BUFFERS, EACH OF WHICH HAVE HALF OF THE + // BYTES SET TO 0x14 AND THE OTHER HALF SET TO 0xAA + int loop; + LPDWORD mem32 = (LPDWORD)mem; + for (loop = 4096; loop < 6144; loop++) + *(mem32+loop) = ((loop & 1) ^ ((loop & 0x40) >> 6)) ? 0x14141414 + : 0xAAAAAAAA; + for (loop = 6144; loop < 8192; loop++) + *(mem32+loop) = ((loop & 1) ^ ((loop & 0x40) >> 6)) ? 0xAAAAAAAA + : 0x14141414; + + // SEE HOW MANY TEXT FRAMES PER SECOND WE CAN PRODUCE WITH NOTHING ELSE + // 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(); + DWORD milliseconds = GetTickCount(); + while (GetTickCount() == milliseconds) ; + milliseconds = GetTickCount(); + DWORD cycle = 0; + do { + if (cycle & 1) + FillMemory(mem+0x400,0x400,0x14); + else + CopyMemory(mem+0x400,mem+((cycle & 2) ? 0x4000 : 0x6000),0x400); + VideoRefreshScreen(); + if (cycle++ >= 3) + cycle = 0; + totaltextfps++; + } while (GetTickCount() - milliseconds < 1000); + + // SEE HOW MANY HIRES FRAMES PER SECOND WE CAN PRODUCE WITH NOTHING ELSE + // GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO + // SIMULATE THE ACTIVITY OF AN AVERAGE GAME + DWORD totalhiresfps = 0; + g_uVideoMode = VF_HIRES; + FillMemory(mem+0x2000,0x2000,0x14); + VideoRedrawScreen(); + milliseconds = GetTickCount(); + while (GetTickCount() == milliseconds) ; + milliseconds = GetTickCount(); + cycle = 0; + do { + if (cycle & 1) + FillMemory(mem+0x2000,0x2000,0x14); + else + CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000); + VideoRefreshScreen(); + if (cycle++ >= 3) + cycle = 0; + totalhiresfps++; + } while (GetTickCount() - milliseconds < 1000); + + // DETERMINE HOW MANY 65C02 CLOCK CYCLES WE CAN EMULATE PER SECOND WITH + // NOTHING ELSE GOING ON + DWORD totalmhz10[2] = {0,0}; // bVideoUpdate & !bVideoUpdate + for (UINT i=0; i<2; i++) + { + CpuSetupBenchmark(); + milliseconds = GetTickCount(); + while (GetTickCount() == milliseconds) ; + milliseconds = GetTickCount(); + do { + CpuExecute(100000, i==0 ? true : false); + totalmhz10[i]++; + } while (GetTickCount() - milliseconds < 1000); + } + + // IF THE PROGRAM COUNTER IS NOT IN THE EXPECTED RANGE AT THE END OF THE + // CPU BENCHMARK, REPORT AN ERROR AND OPTIONALLY TRACK IT DOWN + if ((regs.pc < 0x300) || (regs.pc > 0x400)) + if (MessageBox(g_hFrameWindow, + TEXT("The emulator has detected a problem while running ") + TEXT("the CPU benchmark. Would you like to gather more ") + TEXT("information?"), + TEXT("Benchmarks"), + MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES) { + BOOL error = 0; + WORD lastpc = 0x300; + int loop = 0; + while ((loop < 10000) && !error) { + CpuSetupBenchmark(); + CpuExecute(loop, true); + if ((regs.pc < 0x300) || (regs.pc > 0x400)) + error = 1; + else { + lastpc = regs.pc; + ++loop; + } + } + if (error) { + TCHAR outstr[256]; + wsprintf(outstr, + TEXT("The emulator experienced an error %u clock cycles ") + TEXT("into the CPU benchmark. Prior to the error, the ") + TEXT("program counter was at $%04X. After the error, it ") + TEXT("had jumped to $%04X."), + (unsigned)loop, + (unsigned)lastpc, + (unsigned)regs.pc); + MessageBox(g_hFrameWindow, + outstr, + TEXT("Benchmarks"), + MB_ICONINFORMATION | MB_SETFOREGROUND); + } + else + MessageBox(g_hFrameWindow, + TEXT("The emulator was unable to locate the exact ") + TEXT("point of the error. This probably means that ") + TEXT("the problem is external to the emulator, ") + TEXT("happening asynchronously, such as a problem in ") + TEXT("a timer interrupt handler."), + TEXT("Benchmarks"), + MB_ICONINFORMATION | MB_SETFOREGROUND); + } + + // DO A REALISTIC TEST OF HOW MANY FRAMES PER SECOND WE CAN PRODUCE + // WITH FULL EMULATION OF THE CPU, JOYSTICK, AND DISK HAPPENING AT + // THE SAME TIME + DWORD realisticfps = 0; + FillMemory(mem+0x2000,0x2000,0xAA); + VideoRedrawScreen(); + milliseconds = GetTickCount(); + while (GetTickCount() == milliseconds) ; + milliseconds = GetTickCount(); + cycle = 0; + do { + if (realisticfps < 10) { + int cycles = 100000; + while (cycles > 0) { + DWORD executedcycles = CpuExecute(103, true); + cycles -= executedcycles; + GetCardMgr().GetDisk2CardMgr().UpdateDriveState(executedcycles); + JoyUpdateButtonLatch(executedcycles); + } + } + if (cycle & 1) + FillMemory(mem+0x2000,0x2000,0xAA); + else + CopyMemory(mem+0x2000,mem+((cycle & 2) ? 0x4000 : 0x6000),0x2000); + VideoRedrawScreen(); + if (cycle++ >= 3) + cycle = 0; + realisticfps++; + } while (GetTickCount() - milliseconds < 1000); + + // DISPLAY THE RESULTS + VideoDisplayLogo(); + TCHAR outstr[256]; + wsprintf(outstr, + TEXT("Pure Video FPS:\t%u hires, %u text\n") + TEXT("Pure CPU MHz:\t%u.%u%s (video update)\n") + TEXT("Pure CPU MHz:\t%u.%u%s (full-speed)\n\n") + TEXT("EXPECTED AVERAGE VIDEO GAME\n") + TEXT("PERFORMANCE: %u FPS"), + (unsigned)totalhiresfps, + (unsigned)totaltextfps, + (unsigned)(totalmhz10[0] / 10), (unsigned)(totalmhz10[0] % 10), (LPCTSTR)(IS_APPLE2 ? TEXT(" (6502)") : TEXT("")), + (unsigned)(totalmhz10[1] / 10), (unsigned)(totalmhz10[1] % 10), (LPCTSTR)(IS_APPLE2 ? TEXT(" (6502)") : TEXT("")), + (unsigned)realisticfps); + MessageBox(g_hFrameWindow, + outstr, + TEXT("Benchmarks"), + MB_ICONINFORMATION | MB_SETFOREGROUND); +} + +// This is called from PageConfig +//=========================================================================== +void VideoChooseMonochromeColor () +{ + CHOOSECOLOR cc; + ZeroMemory(&cc,sizeof(CHOOSECOLOR)); + cc.lStructSize = sizeof(CHOOSECOLOR); + cc.hwndOwner = g_hFrameWindow; + cc.rgbResult = g_nMonochromeRGB; + cc.lpCustColors = customcolors + 1; + cc.Flags = CC_RGBINIT | CC_SOLIDCOLOR; + if (ChooseColor(&cc)) + { + g_nMonochromeRGB = cc.rgbResult; + VideoReinitialize(); + if ((g_nAppMode != MODE_LOGO) && (g_nAppMode != MODE_DEBUG)) + { + VideoRedrawScreen(); + } + Config_Save_Video(); + } +} + +//=========================================================================== + +static void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale) +{ + HDC hSrcDC = CreateCompatibleDC( hDstDC ); + SelectObject( hSrcDC, g_hLogoBitmap ); + StretchBlt( + hDstDC, // hdcDest + xoff, yoff, // nXDest, nYDest + scale * srcw, scale * srch, // nWidth, nHeight + hSrcDC, // hdcSrc + 0, 0, // nXSrc, nYSrc + srcw, srch, + SRCCOPY // dwRop + ); + + DeleteObject( hSrcDC ); +} + +//=========================================================================== +void VideoDisplayLogo () +{ + int nLogoX = 0, nLogoY = 0; + int scale = GetViewportScale(); + + HDC hFrameDC = FrameGetDC(); + + // DRAW THE LOGO + SelectObject(hFrameDC, GetStockObject(NULL_PEN)); + + if (g_hLogoBitmap) + { + BITMAP bm; + if (GetObject(g_hLogoBitmap, sizeof(bm), &bm)) + { + nLogoX = (g_nViewportCX - scale*bm.bmWidth )/2; + nLogoY = (g_nViewportCY - scale*bm.bmHeight)/2; + + if( IsFullScreen() ) + { + nLogoX += GetFullScreenOffsetX(); + nLogoY += GetFullScreenOffsetY(); + } + + 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, + sFontName ); + SelectObject(hFrameDC,font); + SetTextAlign(hFrameDC,TA_RIGHT | TA_TOP); + SetBkMode(hFrameDC,TRANSPARENT); + + TCHAR szVersion[ 64 ]; + StringCbPrintf(szVersion, 64, "Version %s", VERSIONSTRING); + int xoff = GetFullScreenOffsetX(), yoff = GetFullScreenOffsetY(); + +#define DRAWVERSION(x,y,c) \ + SetTextColor(hFrameDC,c); \ + TextOut(hFrameDC, \ + scale*540+x+xoff,scale*358+y+yoff, \ + szVersion, \ + strlen(szVersion)); + + if (GetDeviceCaps(hFrameDC,PLANES) * GetDeviceCaps(hFrameDC,BITSPIXEL) <= 4) { + DRAWVERSION( 2, 2,RGB(0x00,0x00,0x00)); + DRAWVERSION( 1, 1,RGB(0x00,0x00,0x00)); + DRAWVERSION( 0, 0,RGB(0xFF,0x00,0xFF)); + } else { + DRAWVERSION( 1, 1,PALETTERGB(0x30,0x30,0x70)); + DRAWVERSION(-1,-1,PALETTERGB(0xC0,0x70,0xE0)); + DRAWVERSION( 0, 0,PALETTERGB(0x70,0x30,0xE0)); + } + +#if _DEBUG + StringCbPrintf(szVersion, 64, "DEBUG"); + DRAWVERSION( 2, -358*scale,RGB(0x00,0x00,0x00)); + DRAWVERSION( 1, -357*scale,RGB(0x00,0x00,0x00)); + DRAWVERSION( 0, -356*scale,RGB(0xFF,0x00,0xFF)); +#endif + +#undef DRAWVERSION + + DeleteObject(font); +} + +//=========================================================================== + +void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInit /*=false*/) +{ + static DWORD dwFullSpeedStartTime = 0; +// static bool bValid = false; + + if (bInit) + { + // Just entered full-speed mode +// bValid = false; + dwFullSpeedStartTime = GetTickCount(); + return; + } + + DWORD dwFullSpeedDuration = GetTickCount() - dwFullSpeedStartTime; + if (dwFullSpeedDuration <= 16) // Only update after every realtime ~17ms of *continuous* full-speed + return; + + dwFullSpeedStartTime += dwFullSpeedDuration; + + // + +#if 0 + 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) + { + // 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; + } + else + { + 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); + } + } + + 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; +#else + VideoRedrawScreenAfterFullSpeed(dwCyclesThisFrame); +#endif +} + +//=========================================================================== + +void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame) +{ + NTSC_VideoClockResync(dwCyclesThisFrame); + VideoRedrawScreen(); // Better (no flicker) than using: NTSC_VideoReinitialize() or VideoReinitialize() +} + +//=========================================================================== + +void VideoRedrawScreen (void) +{ + // NB. Can't rely on g_uVideoMode being non-zero (ie. so it can double up as a flag) since 'GR,PAGE1,non-mixed' mode == 0x00. + VideoRefreshScreen( g_uVideoMode, true ); +} + +//=========================================================================== + +void VideoRefreshScreen ( uint32_t uRedrawWholeScreenVideoMode /* =0*/, bool bRedrawWholeScreen /* =false*/ ) +{ + if (bRedrawWholeScreen || g_nAppMode == MODE_PAUSED) + { + // uVideoModeForWholeScreen set if: + // . MODE_DEBUG : always + // . MODE_RUNNING : called from VideoRedrawScreen(), eg. during full-speed + if (bRedrawWholeScreen) + NTSC_SetVideoMode( uRedrawWholeScreenVideoMode ); + NTSC_VideoRedrawWholeScreen(); + + // MODE_DEBUG|PAUSED: Need to refresh a 2nd time if changing video-type, otherwise could have residue from prev image! + // . eg. Amber -> B&W TV + if (g_nAppMode == MODE_DEBUG || g_nAppMode == MODE_PAUSED) + NTSC_VideoRedrawWholeScreen(); + } + + HDC hFrameDC = FrameGetDC(); + + if (hFrameDC) + { + int xSrc = GetFrameBufferBorderWidth(); + int ySrc = GetFrameBufferBorderHeight(); + + int xdest = IsFullScreen() ? GetFullScreenOffsetX() : 0; + int ydest = IsFullScreen() ? GetFullScreenOffsetY() : 0; + int wdest = g_nViewportCX; + int hdest = g_nViewportCY; + + SetStretchBltMode(hFrameDC, COLORONCOLOR); + StretchBlt( + hFrameDC, + xdest, ydest, + wdest, hdest, + g_hDeviceDC, + xSrc, ySrc, + GetFrameBufferBorderlessWidth(), GetFrameBufferBorderlessHeight(), + SRCCOPY); + } + +#ifdef NO_DIRECT_X +#else + //if (g_lpDD) g_lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL); +#endif // NO_DIRECT_X + + GdiFlush(); +} + +//=========================================================================== + +#define MAX_DRAW_DEVICES 10 + +static char *draw_devices[MAX_DRAW_DEVICES]; +static GUID draw_device_guid[MAX_DRAW_DEVICES]; +static int num_draw_devices = 0; +static LPDIRECTDRAW g_lpDD = NULL; + +static BOOL CALLBACK DDEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext) +{ + int i = num_draw_devices; + if (i == MAX_DRAW_DEVICES) + return TRUE; + if (lpGUID != NULL) + memcpy(&draw_device_guid[i], lpGUID, sizeof (GUID)); + draw_devices[i] = _strdup(lpszDesc); + + if (g_fh) fprintf(g_fh, "%d: %s - %s\n",i,lpszDesc,lpszDrvName); + + num_draw_devices++; + return TRUE; +} + +bool DDInit(void) +{ +#ifdef NO_DIRECT_X + + return false; + +#else + HRESULT hr = DirectDrawEnumerate((LPDDENUMCALLBACK)DDEnumProc, NULL); + if (FAILED(hr)) + { + LogFileOutput("DSEnumerate failed (%08X)\n", hr); + return false; + } + + LogFileOutput("Number of draw devices = %d\n", num_draw_devices); + + bool bCreatedOK = false; + for (int x=0; xRelease(); (p)=NULL; } } + +void DDUninit(void) +{ + SAFE_RELEASE(g_lpDD); +} + +#undef SAFE_RELEASE + +//=========================================================================== + +void Video_RedrawAndTakeScreenShot(const char* pScreenshotFilename) +{ + _ASSERT(pScreenshotFilename); + if (!pScreenshotFilename) + return; + + VideoRedrawScreen(); + Video_SaveScreenShot(SCREENSHOT_560x384, pScreenshotFilename); +} diff --git a/source/Windows/WinVideo.h b/source/Windows/WinVideo.h new file mode 100644 index 00000000..0b7324ff --- /dev/null +++ b/source/Windows/WinVideo.h @@ -0,0 +1,19 @@ +#pragma once + +// Prototypes _______________________________________________________ + +void DirectVideoInitialize(); +void DirectVideoDestroy(); + +void VideoBenchmark (); +void VideoChooseMonochromeColor (); // FIXME: Should be moved to PageConfig and call VideoSetMonochromeColor() +void VideoDisplayLogo (); +void VideoRedrawScreenDuringFullSpeed(DWORD dwCyclesThisFrame, bool bInit = false); +void VideoRedrawScreenAfterFullSpeed(DWORD dwCyclesThisFrame); +void VideoRedrawScreen (void); +void VideoRefreshScreen (uint32_t uRedrawWholeScreenVideoMode = 0, bool bRedrawWholeScreen = false); + +void Video_RedrawAndTakeScreenShot(const char* pScreenshotFilename); + +bool DDInit(void); +void DDUninit(void);