#include #include #include #include #include "MainWindow.h" #include "PtrMacro.h" #include "../PS2VM.h" #include "../PS2OS.h" #include "../AppConfig.h" #include "GSH_OpenGLWin32.h" #include "GSH_Software.h" #include "../GSH_Null.h" #include "PH_DirectInput.h" #include "win32/FileDialog.h" #include "win32/AcceleratorTableGenerator.h" #include "VFSManagerWnd.h" #include "McManagerWnd.h" #include "Debugger.h" #include "SysInfoWnd.h" #include "AboutWnd.h" #include "../Profiler.h" #include "resource.h" #include "string_cast.h" #define CLSNAME _T("MainWindow") #define WNDSTYLE (WS_CLIPCHILDREN | WS_DLGFRAME | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX) #define STATUSPANEL 0 #define FPSPANEL 1 #define TITLEA "Purei!" #define TITLEW L"プレイ!" #define VMMENUPOS 1 #define ID_MAIN_VM_STATESLOT_0 (0xBEEF) #define MAX_STATESLOTS 10 #define ID_MAIN_DEBUG_SHOW (0xDEAD) #define PREF_UI_PAUSEWHENFOCUSLOST "ui.pausewhenfocuslost" using namespace Framework; using namespace std; using namespace std::tr1; using namespace std::tr1::placeholders; using namespace boost; double CMainWindow::m_nStatusBarPanelWidths[2] = { 0.7, 0.3, }; CMainWindow::CMainWindow(CPS2VM& virtualMachine, char* sCmdLine) : m_virtualMachine(virtualMachine) { RECT rc; TCHAR sVersion[256]; CAppConfig::GetInstance().RegisterPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST, true); if(!DoesWindowClassExist(CLSNAME)) { WNDCLASSEX wc; memset(&wc, 0, sizeof(WNDCLASSEX)); wc.cbSize = sizeof(WNDCLASSEX); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = CLSNAME; wc.lpfnWndProc = CWindow::WndProc; wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; RegisterClassEx(&wc); } SetRect(&rc, 0, 0, 640, 480); Create(NULL, CLSNAME, _T(""), WNDSTYLE, &rc, NULL, NULL); SetClassPtr(); #ifdef DEBUGGER_INCLUDED CDebugger::InitializeConsole(); #endif m_virtualMachine.Initialize(); SetIcon(ICON_SMALL, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_PUREI))); SetIcon(ICON_BIG, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_PUREI))); SetMenu(LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MAINWINDOW))); #ifdef DEBUGGER_INCLUDED m_pDebugger = new CDebugger(m_virtualMachine); CreateDebugMenu(); #endif PrintVersion(sVersion, countof(sVersion)); SetRect(&rc, 0, 0, 1, 1); m_pOutputWnd = new COutputWnd(m_hWnd, &rc); m_pStatusBar = new Win32::CStatusBar(m_hWnd); m_pStatusBar->SetParts(2, m_nStatusBarPanelWidths); m_pStatusBar->SetText(STATUSPANEL, sVersion); m_pStatusBar->SetText(FPSPANEL, _T("0 fps")); m_pOutputWnd->m_OnSizeChange.connect(bind(&CMainWindow::OnOutputWndSizeChange, this)); // m_virtualMachine.CreateGSHandler(CGSH_Null::GetFactoryFunction()); m_virtualMachine.CreateGSHandler(CGSH_OpenGLWin32::GetFactoryFunction(m_pOutputWnd)); // CGSH_Software::CreateGSHandler(m_virtualMachine, m_pOutputWnd); m_virtualMachine.CreatePadHandler(CPH_DirectInput::GetFactoryFunction(m_hWnd)); //Initialize FPS counter m_nFrames = 0; m_nStateSlot = 0; m_nDeactivatePause = false; m_nPauseFocusLost = CAppConfig::GetInstance().GetPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST); m_virtualMachine.m_pGS->OnNewFrame.connect(bind(&CMainWindow::OnNewFrame, this)); SetTimer(m_hWnd, NULL, 1000, NULL); m_virtualMachine.m_os->m_OnExecutableChange.connect(bind(&CMainWindow::OnExecutableChange, this)); CreateStateSlotMenu(); CreateAccelerators(); if(strstr(sCmdLine, "-cdrom0") != NULL) { BootCDROM(); } else if(strlen(sCmdLine)) { LoadELF(sCmdLine); } UpdateUI(); Show(SW_SHOW); #if (_DEBUG && DEBUGGER_INCLUDED) ShowDebugger(); #endif } CMainWindow::~CMainWindow() { m_virtualMachine.Pause(); m_virtualMachine.DestroyPadHandler(); m_virtualMachine.DestroyGSHandler(); #ifdef DEBUGGER_INCLUDED DELETEPTR(m_pDebugger); #endif DELETEPTR(m_pOutputWnd); DELETEPTR(m_pStatusBar); DestroyAcceleratorTable(m_nAccTable); m_virtualMachine.Destroy(); } int CMainWindow::Loop() { MSG msg; HWND hActive; bool nDispatched; while(IsWindow()) { GetMessage(&msg, NULL, 0, 0); nDispatched = false; hActive = GetActiveWindow(); if(hActive == m_hWnd) { nDispatched = TranslateAccelerator(m_hWnd, m_nAccTable, &msg) != 0; } #ifdef DEBUGGER_INCLUDED else if(hActive == m_pDebugger->m_hWnd) { nDispatched = TranslateAccelerator(m_pDebugger->m_hWnd, m_pDebugger->GetAccelerators(), &msg) != 0; } #endif if(!nDispatched) { TranslateMessage(&msg); DispatchMessage(&msg); } } return 0; } long CMainWindow::OnCommand(unsigned short nID, unsigned short nCmd, HWND hSender) { switch(nID) { case ID_MAIN_FILE_LOADELF: OpenELF(); break; case ID_MAIN_FILE_BOOTCDROM: BootCDROM(); break; case ID_MAIN_FILE_EXIT: DestroyWindow(m_hWnd); break; case ID_MAIN_VM_RESUME: ResumePause(); break; case ID_MAIN_VM_RESET: Reset(); break; case ID_MAIN_VM_PAUSEFOCUS: PauseWhenFocusLost(); break; case ID_MAIN_VM_SAVESTATE: SaveState(); break; case ID_MAIN_VM_LOADSTATE: LoadState(); break; case ID_MAIN_VM_FRAMESKIP_DECREMENT: ChangeFrameskip(true); break; case ID_MAIN_VM_FRAMESKIP_INCREMENT: ChangeFrameskip(false); break; case ID_MAIN_VM_STATESLOT_0 + 0: case ID_MAIN_VM_STATESLOT_0 + 1: case ID_MAIN_VM_STATESLOT_0 + 2: case ID_MAIN_VM_STATESLOT_0 + 3: case ID_MAIN_VM_STATESLOT_0 + 4: case ID_MAIN_VM_STATESLOT_0 + 5: case ID_MAIN_VM_STATESLOT_0 + 6: case ID_MAIN_VM_STATESLOT_0 + 7: case ID_MAIN_VM_STATESLOT_0 + 8: case ID_MAIN_VM_STATESLOT_0 + 9: ChangeStateSlot(nID - ID_MAIN_VM_STATESLOT_0); break; case ID_MAIN_OPTIONS_RENDERER: ShowRendererSettings(); break; case ID_MAIN_OPTIONS_CONTROLLER: ShowControllerSettings(); break; case ID_MAIN_OPTIONS_VFSMANAGER: ShowVfsManager(); break; case ID_MAIN_OPTIONS_MCMANAGER: ShowMcManager(); break; case ID_MAIN_DEBUG_SHOW: ShowDebugger(); break; case ID_MAIN_HELP_SYSINFO: ShowSysInfo(); break; case ID_MAIN_HELP_ABOUT: ShowAbout(); break; } return TRUE; } long CMainWindow::OnTimer() { tstring sCaption = lexical_cast(m_nFrames) + _T(" fps"); m_pStatusBar->SetText(FPSPANEL, sCaption.c_str()); m_nFrames = 0; #ifdef PROFILE CProfiler::ZoneList Zones; double nTotalTime; xstringstream sProfileCaption; Zones = CProfiler::GetInstance().GetStats(); CProfiler::GetInstance().Reset(); nTotalTime = 0; for(CProfiler::ZoneList::iterator itZone = Zones.begin(); itZone != Zones.end(); itZone++) { nTotalTime += (*itZone).GetTime(); } sProfileCaption.precision(4); for(CProfiler::ZoneList::iterator itZone = Zones.begin(); itZone != Zones.end(); itZone++) { sProfileCaption << (*itZone).GetName() << ": " << setw(5) << ((double)(*itZone).GetTime() / nTotalTime) * 100 << " "; } m_pStatusBar->SetText(STATUSPANEL, sProfileCaption.str().c_str()); #endif return TRUE; } long CMainWindow::OnActivateApp(bool nActive, unsigned long nThreadId) { if(m_nPauseFocusLost == true) { if(nActive == false) { if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING) { ResumePause(); m_nDeactivatePause = true; } } if((nActive == true) && (m_nDeactivatePause == true)) { ResumePause(); m_nDeactivatePause = false; } } return FALSE; } void CMainWindow::OpenELF() { Win32::CFileDialog d; int nRet; d.m_OFN.lpstrFilter = _T("ELF Executable Files (*.elf)\0*.elf\0All files (*.*)\0*.*\0"); Enable(FALSE); nRet = d.Summon(m_hWnd); Enable(TRUE); SetFocus(); if(nRet == 0) return; LoadELF(string_cast(d.m_sFile).c_str()); } void CMainWindow::ResumePause() { if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING) { m_virtualMachine.Pause(); SetStatusText(_T("Virtual Machine paused.")); } else { m_virtualMachine.Resume(); SetStatusText(_T("Virtual Machine resumed.")); } } void CMainWindow::Reset() { //Calling this will clear the RAM completely and remove the executable from memory... //CPS2VM::Reset(); //SetStatusText(_X("Virtual Machine reset.")); } void CMainWindow::PauseWhenFocusLost() { m_nPauseFocusLost = !m_nPauseFocusLost; if(m_nPauseFocusLost) { m_nDeactivatePause = false; } CAppConfig::GetInstance().SetPreferenceBoolean(PREF_UI_PAUSEWHENFOCUSLOST, m_nPauseFocusLost); UpdateUI(); } void CMainWindow::SaveState() { if(m_virtualMachine.m_os->GetELF() == NULL) return; if(m_virtualMachine.SaveState(GenerateStatePath().c_str()) == 0) { PrintStatusTextA("Saved state to slot %i.", m_nStateSlot); } else { PrintStatusTextA("Error saving state to slot %i.", m_nStateSlot); } } void CMainWindow::LoadState() { if(m_virtualMachine.m_os->GetELF() == NULL) return; if(m_virtualMachine.LoadState(GenerateStatePath().c_str()) == 0) { PrintStatusTextA("Loaded state from slot %i.", m_nStateSlot); } else { PrintStatusTextA("Error loading state from slot %i.", m_nStateSlot); } } void CMainWindow::ChangeFrameskip(bool decrement) { int frameSkip = CAppConfig::GetInstance().GetPreferenceInteger(PREF_PS2_FRAMESKIP); frameSkip += decrement ? -1 : 1; frameSkip = max(frameSkip, 0); frameSkip = min(frameSkip, 10); m_virtualMachine.SetFrameSkip(frameSkip); PrintStatusTextA("Frame skip set to %i.", frameSkip); } void CMainWindow::ChangeStateSlot(unsigned int nSlot) { m_nStateSlot = nSlot % MAX_STATESLOTS; UpdateUI(); } void CMainWindow::ShowDebugger() { #ifdef DEBUGGER_INCLUDED m_pDebugger->Show(SW_MAXIMIZE); SetForegroundWindow(m_pDebugger->m_hWnd); #endif } void CMainWindow::ShowSysInfo() { { CSysInfoWnd SysInfoWnd(m_hWnd); SysInfoWnd.DoModal(); } Redraw(); } void CMainWindow::ShowAbout() { { CAboutWnd AboutWnd(m_hWnd); AboutWnd.DoModal(); } Redraw(); } void CMainWindow::ShowSettingsDialog(CSettingsDialogProvider* provider) { if(!provider) return; bool nPaused = false; if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING) { nPaused = true; ResumePause(); } Win32::CModalWindow* pWindow = provider->CreateSettingsDialog(m_hWnd); pWindow->DoModal(); DELETEPTR(pWindow); provider->OnSettingsDialogDestroyed(); Redraw(); if(nPaused) { ResumePause(); } } void CMainWindow::ShowRendererSettings() { ShowSettingsDialog(dynamic_cast(m_virtualMachine.GetGSHandler())); /* bool nPaused = false; if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING) { nPaused = true; ResumePause(); } CSettingsDialogProvider* pProvider = dynamic_cast(m_virtualMachine.GetGSHandler()); if(pProvider != NULL) { Win32::CModalWindow* pWindow = pProvider->CreateSettingsDialog(m_hWnd); pWindow->DoModal(); DELETEPTR(pWindow); pProvider->OnSettingsDialogDestroyed(); } Redraw(); if(nPaused) { ResumePause(); } */ } void CMainWindow::ShowControllerSettings() { if(!m_virtualMachine.m_pPad) return; ShowSettingsDialog(dynamic_cast(m_virtualMachine.m_pPad)); } void CMainWindow::ShowVfsManager() { bool nPaused; nPaused = false; if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING) { nPaused = true; ResumePause(); } CVFSManagerWnd VFSManagerWnd(m_hWnd); VFSManagerWnd.DoModal(); Redraw(); if(nPaused) { ResumePause(); } } void CMainWindow::ShowMcManager() { bool nPaused; nPaused = false; if(m_virtualMachine.GetStatus() == CVirtualMachine::RUNNING) { nPaused = true; ResumePause(); } CMcManagerWnd McManagerWnd(m_hWnd); McManagerWnd.DoModal(); Redraw(); if(nPaused) { ResumePause(); } } void CMainWindow::LoadELF(const char* sFilename) { CPS2OS& os = *m_virtualMachine.m_os; m_virtualMachine.Reset(); try { os.BootFromFile(sFilename); #if !defined(_DEBUG) && !defined(DEBUGGER_INCLUDED) m_virtualMachine.Resume(); #endif PrintStatusTextA("Loaded executable '%s'.", os.GetExecutableName()); } catch(const exception& Exception) { MessageBoxA(m_hWnd, Exception.what(), NULL, 16); } } void CMainWindow::BootCDROM() { CPS2OS& os = *m_virtualMachine.m_os; m_virtualMachine.Reset(); try { os.BootFromCDROM(); #ifndef _DEBUG m_virtualMachine.Resume(); #endif PrintStatusTextA("Loaded executable '%s' from cdrom0.", os.GetExecutableName()); } catch(const exception& Exception) { MessageBoxA(m_hWnd, Exception.what(), NULL, 16); } } void CMainWindow::RefreshLayout() { RECT rc; unsigned int nViewW, nViewH; m_pOutputWnd->GetWindowRect(&rc); nViewW = rc.right - rc.left; nViewH = rc.bottom - rc.top; SetRect(&rc, 0, 0, nViewW, nViewH); rc.bottom += m_pStatusBar->GetHeight(); AdjustWindowRect(&rc, WNDSTYLE, TRUE); SetSize(rc.right - rc.left, rc.bottom - rc.top); m_pStatusBar->RefreshGeometry(); m_pStatusBar->SetParts(2, m_nStatusBarPanelWidths); //m_pStatusBar->SetPosition(0, nViewH + 2); //m_pStatusBar->SetSize(nViewW, 21); Center(); } void CMainWindow::PrintStatusTextA(const char* sFormat, ...) { char sText[256]; va_list Args; va_start(Args, sFormat); _vsnprintf(sText, 256, sFormat, Args); va_end(Args); m_pStatusBar->SetText(STATUSPANEL, string_cast(sText).c_str()); } void CMainWindow::SetStatusText(const TCHAR* sText) { m_pStatusBar->SetText(STATUSPANEL, sText); } void CMainWindow::CreateAccelerators() { Win32::CAcceleratorTableGenerator generator; generator.Insert(ID_MAIN_VM_RESUME, VK_F5, FVIRTKEY); generator.Insert(ID_MAIN_FILE_LOADELF, 'O', FVIRTKEY | FCONTROL); generator.Insert(ID_MAIN_VM_SAVESTATE, VK_F7, FVIRTKEY); generator.Insert(ID_MAIN_VM_LOADSTATE, VK_F8, FVIRTKEY); generator.Insert(ID_MAIN_VM_FRAMESKIP_DECREMENT, VK_SUBTRACT, FVIRTKEY); generator.Insert(ID_MAIN_VM_FRAMESKIP_INCREMENT, VK_ADD, FVIRTKEY); m_nAccTable = generator.Create(); } void CMainWindow::CreateDebugMenu() { HMENU hMenu; MENUITEMINFO ItemInfo; hMenu = CreatePopupMenu(); InsertMenu(hMenu, 0, MF_STRING, ID_MAIN_DEBUG_SHOW, _T("Show Debugger")); memset(&ItemInfo, 0, sizeof(MENUITEMINFO)); ItemInfo.cbSize = sizeof(MENUITEMINFO); ItemInfo.fMask = MIIM_STRING | MIIM_SUBMENU; ItemInfo.dwTypeData = _T("Debug"); ItemInfo.hSubMenu = hMenu; InsertMenuItem(GetMenu(m_hWnd), 3, TRUE, &ItemInfo); } void CMainWindow::CreateStateSlotMenu() { HMENU hMenu; MENUITEMINFO ItemInfo; unsigned int i; hMenu = CreatePopupMenu(); for(i = 0; i < MAX_STATESLOTS; i++) { tstring sCaption; sCaption = _T("Slot ") + lexical_cast(i); InsertMenu(hMenu, i, MF_STRING, ID_MAIN_VM_STATESLOT_0 + i, sCaption.c_str()); } memset(&ItemInfo, 0, sizeof(MENUITEMINFO)); ItemInfo.cbSize = sizeof(MENUITEMINFO); ItemInfo.fMask = MIIM_SUBMENU; ItemInfo.hSubMenu = hMenu; hMenu = GetSubMenu(GetMenu(m_hWnd), VMMENUPOS); SetMenuItemInfo(hMenu, ID_MAIN_VM_STATESLOT, FALSE, &ItemInfo); } string CMainWindow::GenerateStatePath() { return string("./states/") + m_virtualMachine.m_os->GetExecutableName() + ".st" + lexical_cast(m_nStateSlot) + ".zip"; } void CMainWindow::UpdateUI() { HMENU hMenu; const char* sExec; TCHAR sTitle[256]; MENUITEMINFO MenuItem; unsigned int i; //Fix the virtual machine sub menu hMenu = GetSubMenu(GetMenu(m_hWnd), VMMENUPOS); CPS2OS& os = *m_virtualMachine.m_os; bool hasElf = (os.GetELF() != NULL); EnableMenuItem(hMenu, ID_MAIN_VM_RESUME, (!hasElf ? MF_GRAYED : 0) | MF_BYCOMMAND); // EnableMenuItem(hMenu, ID_MAIN_VM_RESET, (!hasElf ? MF_GRAYED : 0) | MF_BYCOMMAND); CheckMenuItem(hMenu, ID_MAIN_VM_PAUSEFOCUS, (m_nPauseFocusLost ? MF_CHECKED : MF_UNCHECKED) | MF_BYCOMMAND); EnableMenuItem(hMenu, ID_MAIN_VM_SAVESTATE, (!hasElf ? MF_GRAYED : 0) | MF_BYCOMMAND); EnableMenuItem(hMenu, ID_MAIN_VM_LOADSTATE, (!hasElf ? MF_GRAYED : 0) | MF_BYCOMMAND); //Get state slot sub-menu memset(&MenuItem, 0, sizeof(MENUITEMINFO)); MenuItem.cbSize = sizeof(MENUITEMINFO); MenuItem.fMask = MIIM_SUBMENU; GetMenuItemInfo(hMenu, ID_MAIN_VM_STATESLOT, FALSE, &MenuItem); hMenu = MenuItem.hSubMenu; //Change state slot number checkbox for(i = 0; i < MAX_STATESLOTS; i++) { memset(&MenuItem, 0, sizeof(MENUITEMINFO)); MenuItem.cbSize = sizeof(MENUITEMINFO); MenuItem.fMask = MIIM_STATE; MenuItem.fState = (m_nStateSlot == i) ? MFS_CHECKED : MFS_UNCHECKED; SetMenuItemInfo(hMenu, ID_MAIN_VM_STATESLOT_0 + i, FALSE, &MenuItem); } sExec = os.GetExecutableName(); if(strlen(sExec)) { _sntprintf(sTitle, countof(sTitle), _T("%s - [ %s ]"), tcond(TITLEA, TITLEW), string_cast(sExec).c_str()); } else { _sntprintf(sTitle, countof(sTitle), _T("%s"), tcond(TITLEA, TITLEW)); } SetText(sTitle); } void CMainWindow::PrintVersion(TCHAR* sVersion, size_t nCount) { _sntprintf(sVersion, nCount, _T("プレイ! v%i.%0.2i - %s"), VERSION_MAJOR, VERSION_MINOR, string_cast(__DATE__).c_str()); } void CMainWindow::OnOutputWndSizeChange() { RefreshLayout(); } void CMainWindow::OnNewFrame() { m_nFrames++; } void CMainWindow::OnExecutableChange() { UpdateUI(); }