/* This file is part of BKBTL. BKBTL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. BKBTL 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with BKBTL. If not, see . */ // BKBTL.cpp : Defines the entry point for the application. #include "stdafx.h" #include #include #include #include #include #include #include #include "Main.h" #include "Emulator.h" #include "Views.h" #include "Joystick.h" #include "util/BitmapFile.h" ////////////////////////////////////////////////////////////////////// // Global Variables HINSTANCE g_hInst = NULL; // current instance HWND g_hwnd = NULL; long m_nMainLastFrameTicks = 0; ////////////////////////////////////////////////////////////////////// // Forward declarations BOOL InitInstance(HINSTANCE, int); void DoneInstance(); void ParseCommandLine(); LPCTSTR g_CommandLineHelp = _T("Usage: BKBTL [options]\r\n\r\n") _T("Command line options:\r\n\r\n") _T("/h /help\r\n\tShow command line options (this box)\r\n") _T("/autostart /autostarton\r\n\tStart emulation on window open\r\n") _T("/noautostart /autostartoff\r\n\tDo not start emulation on window open\r\n") _T("/debug /debugon /debugger\r\n\tSwitch to debug mode\r\n") _T("/nodebug /debugoff\r\n\tSwitch off the debug mode\r\n") _T("/sound /soundon\r\n\tTurn sound on\r\n") _T("/nosound /soundoff\r\n\tTurn sound off\r\n") _T("/diskN:filePath\r\n\tAttach disk image, N=0..3\r\n"); ////////////////////////////////////////////////////////////////////// int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); #ifdef _DEBUG _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF); int n = 0; _CrtSetBreakAlloc(n); #endif g_hInst = hInstance; // Store instance handle in our global variable LARGE_INTEGER nFrameStartTime; nFrameStartTime.QuadPart = 0; // Initialize global strings LoadString(g_hInst, IDS_APP_TITLE, g_szTitle, MAX_LOADSTRING); LoadString(g_hInst, IDC_APPLICATION, g_szWindowClass, MAX_LOADSTRING); MainWindow_RegisterClass(); // Perform application initialization if (! InitInstance(hInstance, nCmdShow)) return FALSE; HACCEL hAccelTable = ::LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_APPLICATION)); if (Option_ShowHelp) ::PostMessage(g_hwnd, WM_COMMAND, ID_HELP_COMMAND_LINE_HELP, NULL); LARGE_INTEGER nPerformanceFrequency; ::QueryPerformanceFrequency(&nPerformanceFrequency); TIMECAPS caps; VERIFY(!::timeGetDevCaps(&caps, sizeof(caps))); VERIFY(!::timeBeginPeriod(caps.wPeriodMin)); // Main message loop MSG msg; for (;;) { ::QueryPerformanceCounter(&nFrameStartTime); if (!g_okEmulatorRunning) ::Sleep(1); else { if (!Emulator_SystemFrame()) // Breakpoint hit { Emulator_Stop(); // Turn on degugger if not yet if (!Settings_GetDebug()) ::PostMessage(g_hwnd, WM_COMMAND, ID_VIEW_DEBUG, 0); else ::FlashWindow(g_hwnd, TRUE); } ScreenView_RedrawScreen(); } // Process all queue while (::PeekMessage( &msg, NULL, 0, 0, PM_REMOVE )) { if (msg.message == WM_QUIT) goto endprog; if (::TranslateAccelerator(g_hwnd, hAccelTable, &msg)) continue; ::TranslateMessage(&msg); ::DispatchMessage(&msg); } if (g_okEmulatorRunning && !Settings_GetSound()) { WORD speed = Settings_GetRealSpeed(); if (speed == 0) ::Sleep(0); // Speed MAX, consume 100% of one CPU core else { LONGLONG nFrameDelay; switch (speed) { case 0x7ffd: nFrameDelay = 1000ll / FRAMERATE * 10; break; // Speed 10% case 0x7ffe: nFrameDelay = 1000ll / FRAMERATE * 4; break; // Speed 25% case 0x7fff: nFrameDelay = 1000ll / FRAMERATE * 2; break; // Speed 50% case 2: nFrameDelay = 1000ll / FRAMERATE / 2; break; // Speed 200% case 3: nFrameDelay = 1000ll / FRAMERATE / 4; break; // Speed 400% default: // Speed 100% nFrameDelay = 1000ll / FRAMERATE; // 1000 millisec / 50 = 20 millisec break; } for (;;) { LARGE_INTEGER nFrameFinishTime; // Frame start time ::QueryPerformanceCounter(&nFrameFinishTime); LONGLONG nTimeElapsed = (nFrameFinishTime.QuadPart - nFrameStartTime.QuadPart) * 1000ll / nPerformanceFrequency.QuadPart; if (nTimeElapsed <= 0 || nTimeElapsed >= nFrameDelay) break; LONGLONG nDelayRemaining = nFrameDelay - nTimeElapsed; ::Sleep((DWORD)(nDelayRemaining / 2)); } } } //// Time bomb for perfomance analysis //if (Emulator_GetUptime() >= 300) // 5 minutes // ::PostQuitMessage(0); } endprog: ::timeEndPeriod(caps.wPeriodMin); DoneInstance(); #ifdef _DEBUG if (_CrtDumpMemoryLeaks()) ::MessageBeep(MB_ICONEXCLAMATION); #endif return (int) msg.wParam; } // // FUNCTION: InitInstance(HINSTANCE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE /*hInstance*/, int /*nCmdShow*/) { INITCOMMONCONTROLSEX ics; ics.dwSize = sizeof(ics); ics.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&ics); BitmapFile_Init(); #if !defined(PRODUCT) DebugLogClear(); #endif Settings_Init(); Joystick_Init(); Joystick_SelectJoystick(Settings_GetJoystick()); ParseCommandLine(); // Override settings by command-line option if needed if (!Emulator_Init()) return FALSE; int conf = Settings_GetConfiguration(); if (conf == 0) conf = BK_CONF_BK0010_BASIC; if (!Emulator_InitConfiguration((BKConfiguration)conf)) return FALSE; Emulator_SetSound(Settings_GetSound() != 0); Emulator_SetSpeed(Settings_GetRealSpeed()); Emulator_SetCovox(Settings_GetSoundCovox() != 0); Emulator_SetSoundAY(Settings_GetSoundAY() != 0); if (!CreateMainWindow()) return FALSE; return TRUE; } // Instance finalization void DoneInstance() { ScreenView_Done(); DisasmView_Done(); Emulator_Done(); Joystick_Done(); BitmapFile_Done(); Settings_Done(); } void ParseCommandLine() { LPTSTR commandline = ::GetCommandLine(); int argnum = 0; LPTSTR* args = CommandLineToArgvW(commandline, &argnum); for (int curargn = 1; curargn < argnum; curargn++) { LPTSTR arg = args[curargn]; if (_tcscmp(arg, _T("/help")) == 0 || _tcscmp(arg, _T("/h")) == 0) { Option_ShowHelp = true; } else if (_tcscmp(arg, _T("/autostart")) == 0 || _tcscmp(arg, _T("/autostarton")) == 0) { Settings_SetAutostart(TRUE); } else if (_tcscmp(arg, _T("/autostartoff")) == 0 || _tcscmp(arg, _T("/noautostart")) == 0) { Settings_SetAutostart(FALSE); } else if (_tcscmp(arg, _T("/debug")) == 0 || _tcscmp(arg, _T("/debugon")) == 0 || _tcscmp(arg, _T("/debugger")) == 0) { Settings_SetDebug(TRUE); } else if (_tcscmp(arg, _T("/debugoff")) == 0 || _tcscmp(arg, _T("/nodebug")) == 0) { Settings_SetDebug(FALSE); } else if (_tcscmp(arg, _T("/sound")) == 0 || _tcscmp(arg, _T("/soundon")) == 0) { Settings_SetSound(TRUE); } else if (_tcscmp(arg, _T("/soundoff")) == 0 || _tcscmp(arg, _T("/nosound")) == 0) { Settings_SetSound(FALSE); } else if (_tcslen(arg) > 7 && _tcsncmp(arg, _T("/disk"), 5) == 0) // "/diskN:filePath", N=A..D { if (arg[5] >= _T('A') && arg[5] <= _T('D') && arg[6] == ':') { int slot = arg[5] - _T('A'); LPCTSTR filePath = arg + 7; Settings_SetFloppyFilePath(slot, filePath); } } //TODO: "/state:filepath" } ::LocalFree(args); } //////////////////////////////////////////////////////////////////////