/* FCE Ultra - NES/Famicom Emulator * * Copyright notice for this file: * Copyright (C) 2002 Xodnizel * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" // I like hacks. #define uint8 __UNO492032 #include #include "ddraw.h" #undef LPCWAVEFORMATEX #include "dsound.h" #include "dinput.h" #include #include #include // For directories configuration dialog. #undef uint8 #include #include "../../version.h" #include "../../types.h" #include "../../fceu.h" #include "../../state.h" #include "../../debug.h" #include "../../movie.h" #include "../../fceulua.h" #include "archive.h" #include "input.h" #include "netplay.h" #include "memwatch.h" #include "joystick.h" #include "keyboard.h" #include "ppuview.h" #include "debugger.h" #include "cheat.h" #include "debug.h" #include "ntview.h" #include "ram_search.h" #include "ramwatch.h" #include "memview.h" #include "tracer.h" #include "cdlogger.h" #include "throttle.h" #include "tasedit.h" #include "replay.h" #include "palette.h" //For the SetPalette function #include "main.h" #include "args.h" #include "config.h" #include "sound.h" #include "wave.h" #include "video.h" #include "utils/xstring.h" #include //--------------------------- //mbg merge 6/29/06 - new aboutbox #if defined(MSVC) #ifdef _M_X64 #define _MSVC_ARCH "x64" #else #define _MSVC_ARCH "x86" #endif #ifdef _DEBUG #define _MSVC_BUILD "debug" #else #define _MSVC_BUILD "release" #endif #define __COMPILER__STRING__ "msvc " _Py_STRINGIZE(_MSC_VER) " " _MSVC_ARCH " " _MSVC_BUILD #define _Py_STRINGIZE(X) _Py_STRINGIZE1((X)) #define _Py_STRINGIZE1(X) _Py_STRINGIZE2 ## X #define _Py_STRINGIZE2(X) #X //re: http://72.14.203.104/search?q=cache:HG-okth5NGkJ:mail.python.org/pipermail/python-checkins/2002-November/030704.html+_msc_ver+compiler+version+string&hl=en&gl=us&ct=clnk&cd=5 #elif defined(__GNUC__) #ifdef _DEBUG #define _GCC_BUILD "debug" #else #define _GCC_BUILD "release" #endif #define __COMPILER__STRING__ "gcc " __VERSION__ " " _GCC_BUILD #else #define __COMPILER__STRING__ "unknown" #endif // External functions extern std::string cfgFile; //Contains the filename of the config file used. extern bool turbo; //Is game in turbo mode? void ResetVideo(void); void ShowCursorAbs(int w); void HideFWindow(int h); void FixWXY(int pref); void SetMainWindowStuff(void); int GetClientAbsRect(LPRECT lpRect); void UpdateFCEUWindow(void); void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count); void ApplyDefaultCommandMapping(void); // Internal variables int frameSkipAmt = 18; uint8 *xbsave = NULL; int eoptions = EO_BGRUN | EO_FORCEISCALE; //global variables int soundoptions = SO_SECONDARY | SO_GFOCUS; int soundrate = 44100; int soundbuftime = 50; int soundquality = 1; //Sound volume controls (range 0-150 by 10's)j----- int soundvolume = 150; //Master sound volume int soundTrianglevol = 256; //Sound channel Triangle - volume control int soundSquare1vol = 256; //Sound channel Square1 - volume control int soundSquare2vol = 256; //Sound channel Square2 - volume control int soundNoisevol = 256; //Sound channel Noise - volume control int soundPCMvol = 256; //Sound channel PCM - volume control //------------------------------------------------- int KillFCEUXonFrame = 0; //TODO: clean up, this is used in fceux, move it over there? double saspectw = 1, saspecth = 1; double winsizemulx = 1, winsizemuly = 1; int genie = 0; int pal_emulation = 0; int ntsccol = 0, ntsctint, ntschue; std::string BaseDirectory; int PauseAfterLoad; unsigned int skippy = 0; //Frame skip int frameSkipCounter = 0; //Counter for managing frame skip // Contains the names of the overridden standard directories // in the order roms, nonvol, states, fdsrom, snaps, cheats, movies, memwatch, macro, input presets, lua scripts, base char *directory_names[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //Handle of the main window. HWND hAppWnd = 0; uint32 goptions = GOO_DISABLESS; // Some timing-related variables (now ignored). int maxconbskip = 32; //Maximum consecutive blit skips. int ffbskip = 32; //Blit skips per blit when FF-ing HINSTANCE fceu_hInstance; HACCEL fceu_hAccel; HRESULT ddrval; static char TempArray[2048]; static int exiting = 0; static volatile int moocow = 0; int windowedfailed; int fullscreen = 0; //Windows files only, variable that keeps track of fullscreen status static volatile int _userpause = 0; //mbg merge 7/18/06 changed tasbuild was using this only in a couple of places extern int autoHoldKey, autoHoldClearKey; extern int frame_display, input_display; int soundo = 1; int srendlinen = 8; int erendlinen = 231; int srendlinep = 0; int erendlinep = 239; //mbg 6/30/06 - indicates that the main loop should close the game as soon as it can bool closeGame = false; // Counts the number of frames that have not been displayed. // Used for the bot, to skip frames (makes things faster). int BotFramesSkipped = 0; // Instantiated FCEUX stuff: bool SingleInstanceOnly=false; // Enable/disable option bool DoInstantiatedExit=false; HWND DoInstantiatedExitWindow; // Internal functions void SetDirs() { int x; static int jlist[14]= { FCEUIOD_ROMS, FCEUIOD_NV, FCEUIOD_STATES, FCEUIOD_FDSROM, FCEUIOD_SNAPS, FCEUIOD_CHEATS, FCEUIOD_MOVIES, FCEUIOD_MEMW, FCEUIOD_BBOT, FCEUIOD_MACRO, FCEUIOD_INPUT, FCEUIOD_LUA, FCEUIOD_AVI, FCEUIOD__COUNT}; // FCEUI_SetSnapName((eoptions & EO_SNAPNAME)!=0); for(x=0; x < sizeof(jlist) / sizeof(*jlist); x++) { FCEUI_SetDirOverride(jlist[x], directory_names[x]); } if(directory_names[13]) { FCEUI_SetBaseDirectory(directory_names[13]); } else { FCEUI_SetBaseDirectory(BaseDirectory); } } /// Creates a directory. /// @param dirname Name of the directory to create. void DirectoryCreator(const char* dirname) { CreateDirectory(dirname, 0); } /// Removes a directory. /// @param dirname Name of the directory to remove. void DirectoryRemover(const char* dirname) { RemoveDirectory(dirname); } /// Used to walk over the default directories array. /// @param callback Callback function that's called for every default directory name. void DefaultDirectoryWalker(void (*callback)(const char*)) { unsigned int curr_dir; for(curr_dir = 0; curr_dir < NUMBER_OF_DEFAULT_DIRECTORIES; curr_dir++) { if(!directory_names[curr_dir]) { sprintf( TempArray, "%s\\%s", directory_names[NUMBER_OF_DEFAULT_DIRECTORIES] ? directory_names[NUMBER_OF_DEFAULT_DIRECTORIES] : BaseDirectory.c_str(), default_directory_names[curr_dir] ); callback(TempArray); } } } /// Remove empty, unused directories. void RemoveDirs() { DefaultDirectoryWalker(DirectoryRemover); } ///Creates the default directories. void CreateDirs() { DefaultDirectoryWalker(DirectoryCreator); } //Fills the BaseDirectory string //TODO: Potential buffer overflow caused by limited size of BaseDirectory? void GetBaseDirectory(void) { char temp[2048]; GetModuleFileName(0, temp, 2048); BaseDirectory = temp; size_t truncate_at = BaseDirectory.find_last_of("\\/"); if(truncate_at != std::string::npos) BaseDirectory = BaseDirectory.substr(0,truncate_at); } int BlockingCheck() { MSG msg; moocow = 1; while( PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ) ) { if( GetMessage( &msg, 0, 0, 0)>0 ) { //other accelerator capable dialogs could be added here extern HWND hwndMemWatch; extern HWND hwndTasEdit; int handled = 0; if(hwndMemWatch) { if(IsChild(hwndMemWatch,msg.hwnd)) handled = TranslateAccelerator(hwndMemWatch,fceu_hAccel,&msg); if(!handled) handled = IsDialogMessage(hwndMemWatch,&msg); } if(RamSearchHWnd) { handled |= IsDialogMessage(RamSearchHWnd, &msg); } if(RamWatchHWnd) { if(IsDialogMessage(RamWatchHWnd, &msg)) { if(msg.message == WM_KEYDOWN) // send keydown messages to the dialog (for accelerators, and also needed for the Alt key to work) SendMessage(RamWatchHWnd, msg.message, msg.wParam, msg.lParam); handled = true; } } if(!handled && hwndTasEdit) { if(IsChild(hwndTasEdit,msg.hwnd)) handled = TranslateAccelerator(hwndTasEdit,fceu_hAccel,&msg); } /* //adelikat - Currently no accel keys are used in the main window. Uncomment this block to activate them. if(!handled) if(msg.hwnd == hAppWnd) { handled = TranslateAccelerator(hAppWnd,fceu_hAccel,&msg); if(handled) { int zzz=9; } } */ if(!handled) { TranslateMessage(&msg); DispatchMessage(&msg); } } } moocow = 0; return exiting ? 0 : 1; } void UpdateRendBounds() { FCEUI_SetRenderedLines(srendlinen, erendlinen, srendlinep, erendlinep); } /// Shows an error message in a message box. ///@param errormsg Text of the error message. void FCEUD_PrintError(const char *errormsg) { AddLogText(errormsg, 1); if(fullscreen) { ShowCursorAbs(1); } MessageBox(0, errormsg, FCEU_NAME" Error", MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TOPMOST); if(fullscreen) { ShowCursorAbs(0); } } ///Generates a compiler identification string. /// @return Compiler identification string const char *FCEUD_GetCompilerString() { return __COMPILER__STRING__; } //Displays the about box void ShowAboutBox() { MessageBox(hAppWnd, FCEUI_GetAboutString(), FCEU_NAME, MB_OK); } //Exits FCE Ultra void DoFCEUExit() { if(exiting) //Eh, oops. I'll need to try to fix this later. return; if (CloseMemoryWatch() && AskSave()) //If user was asked to save changes in the memory watch dialog or ram watch, and chose cancel, don't close FCEUX! { if(goptions & GOO_CONFIRMEXIT) { //Wolfenstein 3D had cute exit messages. const char * const emsg[7]={"Are you sure you want to leave? I'll become lonely!", "A strange game. The only winning move is not to play. How about a nice game of chess?", "If you exit, I'll... EAT YOUR MOUSE.", "You can never really exit, you know.", "E.X.I.T?", "I'm sorry, you missed your exit. There is another one in 19 miles", "Silly Exit Message goes here" }; if(IDYES != MessageBox(hAppWnd, emsg[rand() & 6], "Exit FCE Ultra?", MB_ICONQUESTION | MB_YESNO) ) { return; } } KillDebugger(); //mbg merge 7/19/06 added FCEUI_StopMovie(); FCEUD_AviStop(); #ifdef _S9XLUA_H FCEU_LuaStop(); // kill lua script before the gui dies #endif exiting = 1; closeGame = true;//mbg 6/30/06 - for housekeeping purposes we need to exit after the emulation cycle finishes } } void FCEUD_OnCloseGame() { } //Changes the thread priority of the main thread. void DoPriority() { if(eoptions & EO_HIGHPRIO) { if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)) { AddLogText("Error setting thread priority to THREAD_PRIORITY_HIGHEST.", 1); } } else { if(!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL)) { AddLogText("Error setting thread priority to THREAD_PRIORITY_NORMAL.", 1); } } } int DriverInitialize() { if(soundo) { soundo = InitSound(); } SetVideoMode(fullscreen); InitInputStuff(); /* Initialize DInput interfaces. */ return 1; } static void DriverKill(void) { // Save config file //sprintf(TempArray, "%s/fceux.cfg", BaseDirectory.c_str()); sprintf(TempArray, "%s/%s", BaseDirectory.c_str(),cfgFile.c_str()); SaveConfig(TempArray); DestroyInput(); ResetVideo(); if(soundo) { TrashSoundNow(); } CloseWave(); ByebyeWindow(); } #ifdef _USE_SHARED_MEMORY_ HANDLE mapGameMemBlock; HANDLE mapRAM; void win_AllocBuffers(uint8 **GameMemBlock, uint8 **RAM) { mapGameMemBlock = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE, 0, 131072,"fceu.GameMemBlock"); if(mapGameMemBlock == NULL || GetLastError() == ERROR_ALREADY_EXISTS) *GameMemBlock = (uint8 *) malloc(131072); else if((*GameMemBlock = (uint8 *)MapViewOfFile(mapGameMemBlock, FILE_MAP_WRITE, 0, 0, 0)) == NULL) { CloseHandle(mapGameMemBlock); mapGameMemBlock = NULL; *GameMemBlock = (uint8 *) malloc(131072); } mapRAM = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE, 0, 0x800,"fceu.RAM"); if(mapRAM == NULL || GetLastError() == ERROR_ALREADY_EXISTS) *RAM = (uint8 *) malloc(2048); else { if((*RAM = (uint8 *)MapViewOfFile(mapRAM, FILE_MAP_WRITE, 0, 0, 0)) == NULL) { CloseHandle(mapRAM); mapRAM = NULL; *RAM = (uint8 *) malloc(2048); } } } void win_FreeBuffers(uint8 *GameMemBlock, uint8 *RAM) { //clean up shared memory if(mapRAM) { CloseHandle(mapRAM); mapRAM = NULL; CloseHandle(RAM); } else free(RAM); RAM = NULL; if(mapGameMemBlock) { CloseHandle(mapGameMemBlock); mapGameMemBlock = NULL; CloseHandle(GameMemBlock); } else free(GameMemBlock); GameMemBlock = NULL; } #endif void do_exit() { DriverKill(); timeEndPeriod(1); FCEUI_Kill(); } //Puts the default directory names into the elements of the directory_names array that aren't already defined. //adelikat: commenting out this function, we don't need this. This turns the idea of directory overrides to directory assignment /* void initDirectories() { for (unsigned int i = 0; i < NUMBER_OF_DEFAULT_DIRECTORIES; i++) { if (directory_names[i] == 0) { sprintf( TempArray, "%s\\%s", directory_names[i] ? directory_names[i] : BaseDirectory.c_str(), default_directory_names[i] ); directory_names[i] = (char*)malloc(strlen(TempArray) + 1); strcpy(directory_names[i], TempArray); } } if (directory_names[NUMBER_OF_DIRECTORIES - 1] == 0) { directory_names[NUMBER_OF_DIRECTORIES - 1] = (char*)malloc(BaseDirectory.size() + 1); strcpy(directory_names[NUMBER_OF_DIRECTORIES - 1], BaseDirectory.c_str()); } } */ static BOOL CALLBACK EnumCallbackFCEUXInstantiated(HWND hWnd, LPARAM lParam) { //LPSTR lpClassName = '\0'; std::string TempString; char buf[512]; bool PassedTest=true; GetClassName(hWnd, buf, 511); //Console.WriteLine(lpClassName.ToString()); TempString = buf; if (TempString != "FCEUXWindowClass") return true; //memset(buf, 0, 512 * sizeof(char)); GetWindowText(hWnd, buf, 512 * sizeof(char)); if (hWnd != hAppWnd) { PassedTest = (PassedTest & (buf[0] == 'F')); PassedTest = (PassedTest & (buf[1] == 'C')); PassedTest = (PassedTest & (buf[2] == 'E')); PassedTest = (PassedTest & (buf[3] == 'U')); PassedTest = (PassedTest & (buf[4] == 'X')); PassedTest = (PassedTest & (buf[5] == ' ')); PassedTest = (PassedTest & ((buf[6] >= '2') & (buf[6] <= '9'))); PassedTest = (PassedTest & (buf[7] == '.')); PassedTest = (PassedTest & ((buf[8] >= '1') & (buf[8] <= '9'))); PassedTest = (PassedTest & (buf[9] == '.')); PassedTest = (PassedTest & ((buf[10] >= '4') & (buf[10] <= '9'))); if (PassedTest) { DoInstantiatedExit=true; DoInstantiatedExitWindow = hWnd; } } //printf("[%03i] Found '%s'\n", ++WinCount, buf); return true; } #include "x6502.h" int main(int argc,char *argv[]) { SetThreadAffinityMask(GetCurrentThread(),1); printf("%08x",opsize); char *t; initArchiveSystem(); if(timeBeginPeriod(1) != TIMERR_NOERROR) { AddLogText("Error setting timer granularity to 1ms.", DO_ADD_NEWLINE); } InitCommonControls(); debugSystem = new DebugSystem(); if(!FCEUI_Initialize()) { do_exit(); return 1; } ApplyDefaultCommandMapping(); fceu_hInstance = GetModuleHandle(0); fceu_hAccel = LoadAccelerators(fceu_hInstance,MAKEINTRESOURCE(IDR_ACCELERATOR1)); // Get the base directory GetBaseDirectory(); // Parse the commandline arguments t = ParseArgies(argc, argv); if (ConfigToLoad) cfgFile.assign(ConfigToLoad); //initDirectories(); // Load the config information sprintf(TempArray,"%s\\%s",BaseDirectory.c_str(),cfgFile.c_str()); LoadConfig(TempArray); //Bleh, need to find a better place for this. { pal_emulation = !!pal_emulation; FCEUI_SetVidSystem(pal_emulation); FCEUI_SetGameGenie(genie!=0); fullscreen = !!fullscreen; soundo = !!soundo; frame_display = !!frame_display; allowUDLR = !!allowUDLR; pauseAfterPlayback = !!pauseAfterPlayback; closeFinishedMovie = !!closeFinishedMovie; EnableBackgroundInput = !!EnableBackgroundInput; KeyboardSetBackgroundAccess(EnableBackgroundInput!=0); JoystickSetBackgroundAccess(EnableBackgroundInput!=0); FCEUI_SetSoundVolume(soundvolume); FCEUI_SetSoundQuality(soundquality); FCEUI_SetTriangleVolume(soundTrianglevol); FCEUI_SetSquare1Volume(soundSquare1vol); FCEUI_SetSquare2Volume(soundSquare2vol); FCEUI_SetNoiseVolume(soundNoisevol); FCEUI_SetPCMVolume(soundPCMvol); } //Since a game doesn't have to be loaded before the GUI can be used, make //sure the temporary input type variables are set. ParseGIInput(NULL); // Initialize default directories CreateDirs(); SetDirs(); DoVideoConfigFix(); DoTimingConfigFix(); if(eoptions & EO_CPALETTE) { FCEUI_SetPaletteArray(cpalette); } if(!t) { fullscreen=0; } CreateMainWindow(); // Do single instance coding, since we now know if the user wants it, // and we have a source window to send from // http://wiki.github.com/ffi/ffi/windows-examples if (SingleInstanceOnly) { // Checks window names / hWnds, decides if there's going to be a conflict. EnumDesktopWindows(NULL, EnumCallbackFCEUXInstantiated, (LPARAM)0); if (DoInstantiatedExit) { if(t) { COPYDATASTRUCT cData; DATA tData; sprintf(tData.strFilePath,"%s",t); cData.dwData = 1; cData.cbData = sizeof ( tData ); cData.lpData = &tData; SendMessage(DoInstantiatedExitWindow,WM_COPYDATA,(WPARAM)(HWND)hAppWnd, (LPARAM)(LPVOID) &cData); do_exit(); return 0; } } } if(!InitDInput()) { do_exit(); return 1; } if(!DriverInitialize()) { do_exit(); return 1; } InitSpeedThrottle(); if(t) { ALoad(t); } else if(eoptions & EO_FOAFTERSTART) { LoadNewGamey(hAppWnd, 0); } if(PaletteToLoad) { SetPalette(PaletteToLoad); free(PaletteToLoad); PaletteToLoad = NULL; } if(GameInfo && MovieToLoad) { //switch to readonly mode if the file is an archive if(FCEU_isFileInArchive(MovieToLoad)) replayReadOnlySetting = true; FCEUI_LoadMovie(MovieToLoad, replayReadOnlySetting, false, replayStopFrameSetting!=0); FCEUX_LoadMovieExtras(MovieToLoad); free(MovieToLoad); MovieToLoad = NULL; } if(GameInfo && StateToLoad) { FCEUI_LoadState(StateToLoad); free(StateToLoad); StateToLoad = NULL; } if(GameInfo && LuaToLoad) { FCEU_LoadLuaCode(LuaToLoad); free(LuaToLoad); LuaToLoad = NULL; } //Initiates AVI capture mode, will set up proper settings, and close FCUEX once capturing is finished if(AVICapture && AviToLoad) //Must be used in conjunction with AviToLoad { //We want to disable flags that will pause the emulator PauseAfterLoad = 0; pauseAfterPlayback = 0; KillFCEUXonFrame = AVICapture; } if(AviToLoad) { FCEUI_AviBegin(AviToLoad); free(AviToLoad); AviToLoad = NULL; } if (MemWatchLoadOnStart) CreateMemWatch(); if (PauseAfterLoad) FCEUI_ToggleEmulationPause(); SetAutoFirePattern(AFon, AFoff); UpdateCheckedMenuItems(); doloopy: UpdateFCEUWindow(); if(GameInfo) { while(GameInfo) { uint8 *gfx=0; ///contains framebuffer int32 *sound=0; ///contains sound data buffer int32 ssize=0; ///contains sound samples count if (turbo) { if (!frameSkipCounter) { frameSkipCounter = frameSkipAmt; skippy = 0; } else { frameSkipCounter--; if (muteTurbo) skippy = 2; //If mute turbo is on, we want to bypass sound too, so set it to 2 else skippy = 1; //Else set it to 1 to just frameskip } } else skippy = 0; FCEUI_Emulate(&gfx, &sound, &ssize, skippy); //emulate a single frame FCEUD_Update(gfx, sound, ssize); //update displays and debug tools //mbg 6/30/06 - close game if we were commanded to by calls nested in FCEUI_Emulate() if(closeGame) { FCEUI_CloseGame(); GameInfo = 0; } } //xbsave = NULL; RedrawWindow(hAppWnd,0,0,RDW_ERASE|RDW_INVALIDATE); } Sleep(50); if(!exiting) goto doloopy; DriverKill(); timeEndPeriod(1); FCEUI_Kill(); delete debugSystem; return(0); } void FCEUX_LoadMovieExtras(const char * fname) { UpdateReplayCommentsSubs(fname); } //mbg merge 7/19/06 - the function that contains the code that used to just be UpdateFCEUWindow() and FCEUD_UpdateInput() void _updateWindow() { UpdateFCEUWindow(); PPUViewDoBlit(); UpdateMemoryView(0); UpdateCDLogger(); //UpdateLogWindow(); //adelikat: Moved to FCEUI_Emulate UpdateMemWatch(); NTViewDoBlit(0); UpdateTasEdit(); } void win_debuggerLoop() { //delay until something causes us to unpause. //either a hotkey or a debugger command while(FCEUI_EmulationPaused() && !FCEUI_EmulationFrameStepped()) { Sleep(50); FCEUD_UpdateInput(); _updateWindow(); } int zzz=9; } // Update the game and gamewindow with a new frame void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count) { win_SoundSetScale(fps_scale); //If turboing and mute turbo is true, bypass this //write all the sound we generated. if(soundo && Buffer && Count && !(muteTurbo && turbo)) { win_SoundWriteData(Buffer,Count); //If turboing and mute turbo is true, bypass this } //blit the framebuffer if(XBuf) FCEUD_BlitScreen(XBuf); //update debugging displays _updateWindow(); extern bool JustFrameAdvanced; //MBG TODO - think about this logic //throttle bool throttle = true; if( (eoptions&EO_NOTHROTTLE) ) { if(!soundo) throttle = false; } if(throttle) //if throttling is enabled.. if(!turbo) //and turbo is disabled.. if(!FCEUI_EmulationPaused() ||JustFrameAdvanced ) //then throttle while(SpeedThrottle()) { FCEUD_UpdateInput(); _updateWindow(); } //sleep just to be polite if(!JustFrameAdvanced && FCEUI_EmulationPaused()) { Sleep(50); } //while(EmulationPaused==1 && inDebugger) //{ // Sleep(50); // BlockingCheck(); // FCEUD_UpdateInput(); //should this update the CONTROLS??? or only the hotkeys etc? //} ////so, we're not paused anymore. ////something of a hack, but straightforward: ////if we were paused, but not in the debugger, then unpause ourselves and step. ////this is so that the cpu won't cut off execution due to being paused, but the debugger _will_ ////cut off execution as soon as it makes it into the main cpu cycle loop //if(FCEUI_EmulationPaused() && !inDebugger) { // FCEUI_ToggleEmulationPause(); // FCEUI_Debugger().step = 1; // FCEUD_DebugBreakpoint(); //} //make sure to update the input once per frame FCEUD_UpdateInput(); } static void FCEUD_MakePathDirs(const char *fname) { char path[MAX_PATH]; const char* div = fname; do { const char* fptr = strchr(div, '\\'); if(!fptr) { fptr = strchr(div, '/'); } if(!fptr) { break; } int off = fptr - fname; strncpy(path, fname, off); path[off] = '\0'; mkdir(path); div = fptr + 1; while(div[0] == '\\' || div[0] == '/') { div++; } } while(1); } EMUFILE_FILE* FCEUD_UTF8_fstream(const char *n, const char *m) { if(strchr(m, 'w') || strchr(m, '+')) { FCEUD_MakePathDirs(n); } EMUFILE_FILE *fs = new EMUFILE_FILE(n,m); if(!fs->is_open()) { delete fs; return 0; } else return fs; } FILE *FCEUD_UTF8fopen(const char *n, const char *m) { if(strchr(m, 'w') || strchr(m, '+')) { FCEUD_MakePathDirs(n); } return(fopen(n, m)); } int status_icon = 1; int FCEUD_ShowStatusIcon(void) { return status_icon; } void FCEUD_ToggleStatusIcon(void) { status_icon = !status_icon; UpdateCheckedMenuItems(); } char *GetRomName() { //The purpose of this function is to format the ROM name stored in LoadedRomFName //And return a char array with just the name with path or extension //The purpose of this function is to populate a save as dialog with the ROM name as a default filename extern char LoadedRomFName[2048]; //Contains full path of ROM std::string Rom; //Will contain the formatted path if(GameInfo) //If ROM is loaded { char drv[PATH_MAX], dir[PATH_MAX], name[PATH_MAX], ext[PATH_MAX]; splitpath(LoadedRomFName,drv,dir,name,ext); //Extract components of the ROM path Rom = name; //Pull out the Name only } else Rom = ""; char*mystring = (char*)malloc(2048*sizeof(char)); strcpy(mystring, Rom.c_str()); //Convert string to char* return mystring; }