/* 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 #undef LPCWAVEFORMATEX #include #include //#include //mbg merge 7/17/06 removed #include #include // For directories configuration dialog. #undef uint8 #include "../../types.h" #include "../../fceu.h" #include "../../state.h" #include "ppuview.h" #include "debugger.h" #include "input.h" #include "netplay.h" #include "joystick.h" #include "keyboard.h" #include "cheat.h" #include "debug.h" #include "ppuview.h" #include "ntview.h" #include "memview.h" #include "tracer.h" #include "cdlogger.h" //#include "memwatch.h" //mbg merge 7/19/06 removed-memwatch is gone #include "basicbot.h" #define VNSCLIP ((eoptions&EO_CLIPSIDES)?8:0) #define VNSWID ((eoptions&EO_CLIPSIDES)?240:256) uint8 *xbsave=NULL; int eoptions=EO_BGRUN | EO_FORCEISCALE; void ResetVideo(void); void ShowCursorAbs(int w); void HideFWindow(int h); void FixWXY(int pref); int SetMainWindowStuff(void); int GetClientAbsRect(LPRECT lpRect); void UpdateFCEUWindow(void); HWND hAppWnd=0; HINSTANCE fceu_hInstance; HRESULT ddrval; FCEUGI *GI=0; // cheats, misc, nonvol, states, snaps, ..., base static char *DOvers[6]={0,0,0,0,0,0}; static char *defaultds[5]={"cheats","sav","fcs","snaps","movie"}; static char TempArray[2048]; static char BaseDirectory[2048]; void SetDirs(void) { int x; static int jlist[6]= {FCEUIOD_CHEATS,FCEUIOD_MISC,FCEUIOD_NV,FCEUIOD_STATE,FCEUIOD_SNAPS, FCEUIOD__COUNT}; FCEUI_SetSnapName(eoptions&EO_SNAPNAME); for(x=0;x<6;x++) { FCEUI_SetDirOverride(jlist[x], DOvers[x]); } if(DOvers[5]) FCEUI_SetBaseDirectory(DOvers[5]); else FCEUI_SetBaseDirectory(BaseDirectory); } /* Remove empty, unused directories. */ void RemoveDirs(void) { int x; for(x=0;x<5;x++) if(!DOvers[x]) { sprintf(TempArray,"%s\\%s",DOvers[5]?DOvers[5]:BaseDirectory,defaultds[x]); RemoveDirectory(TempArray); } } void CreateDirs(void) { int x; for(x=0;x<5;x++) if(!DOvers[x]) { sprintf(TempArray,"%s\\%s",DOvers[5]?DOvers[5]:BaseDirectory,defaultds[x]); CreateDirectory(TempArray,0); } } static char *gfsdir=0; void GetBaseDirectory(void) { int x; BaseDirectory[0]=0; GetModuleFileName(0,(LPTSTR)BaseDirectory,2047); for(x=strlen(BaseDirectory);x>=0;x--) { if(BaseDirectory[x]=='\\' || BaseDirectory[x]=='/') {BaseDirectory[x]=0;break;} } } static int exiting=0; static volatile int moocow = 0; int BlockingCheck(void) { MSG msg; moocow = 1; while( PeekMessage( &msg, 0, 0, 0, PM_NOREMOVE ) ) { if( GetMessage( &msg, 0, 0, 0)>0 ) { TranslateMessage(&msg); DispatchMessage(&msg); } } moocow = 0; if(exiting) return(0); return(1); } /* Some timing-related variables (now ignored). */ static int maxconbskip = 32; /* Maximum consecutive blit skips. */ static int ffbskip = 32; /* Blit skips per blit when FF-ing */ static int moviereadonly=1; static int fullscreen=0; static int soundflush=0; static int genie=0; static int palyo=0; static int status_icon=1; static int windowedfailed; static double saspectw=1, saspecth=1; static double winsizemulx=1, winsizemuly=1; static int winwidth,winheight; static int ismaximized = 0; static volatile int nofocus=0; //static volatile int userpause=0; //mbg merge 7/18/06 removed. this has been replaced with FCEU_EmulationPaused stuff static volatile int _userpause=0; //mbg merge 7/18/06 changed tasbuild was using this only in a couple of places #define SO_FORCE8BIT 1 #define SO_SECONDARY 2 #define SO_GFOCUS 4 #define SO_D16VOL 8 #define SO_MUTEFA 16 #define SO_OLDUP 32 #define GOO_DISABLESS 1 /* Disable screen saver when game is loaded. */ #define GOO_CONFIRMEXIT 2 /* Confirmation before exiting. */ #define GOO_POWERRESET 4 /* Confirm on power/reset. */ static uint32 goptions = GOO_DISABLESS; static int soundrate=44100; static int soundbuftime=50; /*static*/ int soundoptions=SO_SECONDARY|SO_GFOCUS; static int soundvolume=100; static int soundquality=0; extern int autoHoldKey, autoHoldClearKey; extern int frame_display, input_display; //mbg merge 7/17/06 did these have to be unsigned? static int srendline,erendline; static int srendlinen=8; static int erendlinen=231; static int srendlinep=0; static int erendlinep=239; static int totallines; static void FixFL(void) { FCEUI_GetCurrentVidSystem(&srendline,&erendline); totallines=erendline-srendline+1; } static void UpdateRendBounds(void) { FCEUI_SetRenderedLines(srendlinen,erendlinen,srendlinep,erendlinep); FixFL(); } static uint8 cpalette[192]; static int vmod = 0; int soundo=1; static int ntsccol=0,ntsctint,ntschue; void FCEUD_PrintError(char *s) { AddLogText(s,1); if(fullscreen) ShowCursorAbs(1); MessageBox(0,s,"FCE Ultra Error",MB_ICONERROR|MB_OK|MB_SETFOREGROUND|MB_TOPMOST); if(fullscreen)ShowCursorAbs(0); } //--------------------------- //mbg merge 6/29/06 - new aboutbox #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 char *FCEUD_GetCompilerString() { return __COMPILER__STRING__; } void ShowAboutBox(void) { MessageBox(hAppWnd,FCEUI_GetAboutString(),FCEU_NAME,MB_OK); } //mbg 6/30/06 - indicates that the main loop should close the game as soon as it can int closeGame = 0; void DoFCEUExit(void) { /* Wolfenstein 3D had cute exit messages. */ char *emsg[4]={"Are you sure you want to leave? I'll become lonely!", "If you exit, I'll... EAT YOUR MOUSE.", "You can never really exit, you know.", "E-x-i-t?" }; KillDebugger(); //mbg merge 7/19/06 added if(exiting) /* Eh, oops. I'll need to try to fix this later. */ return; StopSound(); if(goptions & GOO_CONFIRMEXIT) if(IDYES != MessageBox(hAppWnd,emsg[rand()&3],"Exit FCE Ultra?",MB_ICONQUESTION|MB_YESNO)) return; FCEUI_StopMovie(); FCEUD_AviStop(); exiting=1; closeGame = 1;//mbg 6/30/06 - for housekeeping purposes we need to exit after the emulation cycle finishes } void DoPriority(void) { 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); } } static int changerecursive=0; #include "throttle.cpp" #include "sound.cpp" #include "video.cpp" #include "window.cpp" #include "config.cpp" #include "args.cpp" int DriverInitialize(void) { if(soundo) soundo=InitSound(); SetVideoMode(fullscreen); InitInputStuff(); /* Initialize DInput interfaces. */ return 1; } static void DriverKill(void) { sprintf(TempArray,"%s/fceu98.cfg",BaseDirectory); SaveConfig(TempArray); DestroyInput(); ResetVideo(); if(soundo) TrashSound(); CloseWave(); ByebyeWindow(); } void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count); void ApplyDefaultCommandMapping(void); //mbg merge 7/18/06 - the function that contains the code that used to just be UpdateMemWatch() void _updateMemWatch() { //UpdateMemWatch() //but soon we will do more! } #ifdef _USE_SHARED_MEMORY_ HANDLE mapGameMemBlock; HANDLE mapRAM; HANDLE mapBotInput; uint32 *BotInput; 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) { //mbg 7/38/06 - is this the proper error handling? //do we need to indicate to user somehow that this failed in this emu instance? CloseHandle(mapGameMemBlock); mapGameMemBlock = NULL; *GameMemBlock = (uint8 *) malloc(131072); *RAM = (uint8 *) malloc(2048); } else { *GameMemBlock = (uint8 *)MapViewOfFile(mapGameMemBlock, FILE_MAP_WRITE, 0, 0, 0); // set up shared memory mappings mapRAM = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE, 0, 0x800,"fceu.RAM"); *RAM = (uint8 *)MapViewOfFile(mapRAM, FILE_MAP_WRITE, 0, 0, 0); } // Give RAM pointer to state structure //mbg 7/28/06 - wtf? extern SFORMAT SFCPU[]; SFCPU[6].v = *RAM; //Bot input mapBotInput = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0, 4096, "fceu.BotInput"); BotInput = (uint32 *) MapViewOfFile(mapBotInput, FILE_MAP_WRITE, 0, 0, 0); BotInput[0] = 0; } void win_FreeBuffers(uint8 *GameMemBlock, uint8 *RAM) { //clean up shared memory if(mapRAM) { UnmapViewOfFile(mapRAM); CloseHandle(mapRAM); RAM = NULL; } else { free(RAM); RAM = NULL; } if(mapGameMemBlock) { UnmapViewOfFile(mapGameMemBlock); CloseHandle(mapGameMemBlock); GameMemBlock = NULL; } else { free(GameMemBlock); GameMemBlock = NULL; } UnmapViewOfFile(mapBotInput); CloseHandle(mapBotInput); BotInput = NULL; } #endif int main(int argc,char *argv[]) { char *t; if(timeBeginPeriod(1)!=TIMERR_NOERROR) { AddLogText("Error setting timer granularity to 1ms.",1); } InitCommonControls(); if(!FCEUI_Initialize()) goto doexito; ApplyDefaultCommandMapping(); srand(GetTickCount()); // rand() is used for some GUI sillyness. fceu_hInstance=GetModuleHandle(0); GetBaseDirectory(); sprintf(TempArray,"%s\\fceu98.cfg",BaseDirectory); LoadConfig(TempArray); t=ParseArgies(argc,argv); /* Bleh, need to find a better place for this. */ { palyo&=1; FCEUI_SetVidSystem(palyo); genie&=1; FCEUI_SetGameGenie(genie); fullscreen&=1; soundo&=1; FCEUI_SetSoundVolume(soundvolume); FCEUI_SetSoundQuality(soundquality); } ParseGIInput(NULL); /* Since a game doesn't have to be loaded before the GUI can be used, make sure the temporary input type variables are set. */ CreateDirs(); SetDirs(); DoVideoConfigFix(); DoTimingConfigFix(); if(eoptions&EO_CPALETTE) FCEUI_SetPaletteArray(cpalette); if(!t) fullscreen=0; CreateMainWindow(); if(!InitDInput()) goto doexito; if(!DriverInitialize()) goto doexito; InitSpeedThrottle(); UpdateMenu(); if(t) ALoad(t); else if(eoptions&EO_FOAFTERSTART) LoadNewGamey(hAppWnd, 0); doloopy: UpdateFCEUWindow(); if(GI) { while(GI) { uint8 *gfx=0; int32 *sound=0; int32 ssize=0; #ifdef _USE_SHARED_MEMORY_ UpdateBasicBot(); #endif FCEU_UpdateBot(); FCEUI_Emulate(&gfx, &sound, &ssize, 0); xbsave = gfx; FCEUD_Update(gfx, sound, ssize); //mbg 6/30/06 - close game if we were commanded to by calls nested in FCEUI_Emulate() if(closeGame) { FCEUI_CloseGame(); GI = 0; } //mbg merge 7/19/06 //--------this code was added by tasbuild //it catches a paused condition and /*static int stopCount=0; if(FCEUI_EmulationPaused() & 1) { if(stopCount==0) _updateMemWatch(); stopCount++; if(stopCount > 8) { StopSound(); stopCount = 0; } //if in bot mode, don't idle. eat the CPU up :) //mbg - why should we do this? does bot mode set the paused flag? that doesnt seem right... if(!FCEU_BotMode()) { int notAlternateThrottle = !(soundoptions&SO_OLDUP) && soundo && ((NoWaiting&1)?(256*16):fps_scale) >= 64; if(notAlternateThrottle) Sleep(5); // HACK to fix 100% CPU usage that happens sporadically when paused in background - also, this affects the repeat rate of frame advance and its sound quality else Sleep(1); // lesser, so frame advance repeat doesn't take too long with the alternate throttling } else if(stopCount == 1) { Sleep(0); } } else { //_updateMemWatch(); stopCount=0; }*/ //----------------------------------- } xbsave = NULL; RedrawWindow(hAppWnd,0,0,RDW_ERASE|RDW_INVALIDATE); StopSound(); } Sleep(50); if(!exiting) goto doloopy; doexito: DriverKill(); timeEndPeriod(1); FCEUI_Kill(); return(0); } //mbg merge 7/19/06 - the function that contains the code that used to just be UpdateFCEUWindow() and FCEUD_UpdateInput() void _updateWindow() { UpdateFCEUWindow(); FCEUD_UpdateInput(); PPUViewDoBlit(); UpdateMemoryView(0); UpdateCDLogger(); UpdateLogWindow(); NTViewDoBlit(0); } //void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count) //{ // static int skipcount = 0; // int temp_fps_scale=(NoWaiting&1)?(256*16):fps_scale; // int maxskip = (temp_fps_scale<=256) ? 0 : temp_fps_scale>>8; // // int ocount = Count; // // apply frame scaling to Count // Count = (Count<<8)/temp_fps_scale; // // //Disable sound and throttling for BotMode--we want max speed! // if(FCEU_BotMode()) // { // if(XBuf && (skipcount >= 64)) // { // skipcount = 0; // FCEUD_BlitScreen(XBuf); // } // else // { // skipcount++; // } // UpdateFCEUWindow(); // FCEUD_UpdateInput(); // return; // } // // if(!(soundoptions&SO_OLDUP) && soundo && temp_fps_scale >= 64) // { // // sounds better with FPS scaling, and is much less code than the other version... // // int32 writeSize = GetWriteSound(); // int32 writeCount = Count; ///* // // prevents delay when exiting fast-forward // if((NoWaiting&1) && writeCount>writeSize) // writeCount=writeSize; //*/ // // if(Buffer && (writeCount)) // FCEUD_WriteSoundData(Buffer,temp_fps_scale,MAX(writeSize,writeCount)); // // if(XBuf && (skipcount >= maxskip)) // { // skipcount = 0; // FCEUD_BlitScreen(XBuf); // _updateMemWatch(); // } // else // skipcount++; // // _updateWindow(); // } // else // { // // I don't understand this code, so I kept it around as an option ("old sound update") // // in case it's doing something clever and necessary that I can't fathom // // (oops, also it seems to be important for speeds <25% so it's always used then) // // const int soundScale = !(soundoptions&SO_OLDUP) ? temp_fps_scale : 256; // // if(Count) // { // int32 can=GetWriteSound(); // static int uflow=0; // int32 tmpcan; // extern int FCEUDnetplay; // // // don't underflow when scaling fps // if(can >= GetMaxSound() && fps_scale<=256) uflow=1; // Go into massive underflow mode. // // if(can > Count) can=Count; // else uflow=0; // // FCEUD_WriteSoundData(Buffer,soundScale,can); // // tmpcan = GetWriteSound(); // // don't underflow when scaling fps // if(fps_scale>256 || ((tmpcan < Count*0.90) && !uflow) || (skipcount >= maxskip)) // { // if(XBuf && (skipcount >= maxskip)) // { // skipcount = 0; // FCEUD_BlitScreen(XBuf); // _updateMemWatch(); // } // else // { // skipcount++; // //FCEU_printf("Skipped0"); // // FCEU_PrintError("Skipped0"); // } // Buffer+=can; // Count-=can; // if(Count) // { // if(NoWaiting) // { // can=GetWriteSound(); // if(Count>can) Count=can; // FCEUD_WriteSoundData(Buffer,soundScale,Count); // } // else // { // int cnum=0; // extern int silencer; // while(Count>0) // { // FCEUD_WriteSoundData(Buffer,soundScale,(Count2) // silencer=1; // } // Count -= ocount; // // prevent long updates from interfering with gui responsiveness: // // //mbg merge 7/19/06 // //UpdateFCEUWindow(); // //FCEUD_UpdateInput(); // _updateWindow(); // } // silencer=0; // } // } // } // else // { // skipcount++; // //FCEU_printf("Skipped"); //#ifdef NETWORK // if(!NoWaiting && FCEUDnetplay && (uflow || tmpcan >= (Count * 0.90))) // { // if(Count > tmpcan) Count=tmpcan; // while(tmpcan > 0) // { // //printf("Overwrite: %d\n", (Count <= tmpcan)?Count : tmpcan); // FCEUD_WriteSoundData(Buffer,soundScale,(Count <= tmpcan)?Count : tmpcan); // tmpcan -= Count; // } // } //#endif // } // } // else // { // /* This complex statement deserves some explanation. // Make sure this special speed throttling hasn't been disabled by the user // first. Second, we don't want to throttle the speed if the fast-forward // button is pressed down(or during certain network play conditions). // // Now, if we're at this point, we'll throttle speed if sound is disabled. // Otherwise, it gets a bit more complicated. We'll throttle speed if focus // to FCE Ultra has been lost and we're writing to the primary sound buffer // because our sound code won't block. Blocking does seem to work when // writing to a secondary buffer, so we won't throttle when a secondary // buffer is used. // */ // // //doagain: //mbg merge 6/30/06 // // int skipthis = 0; // // if(!(eoptions&EO_NOTHROTTLE) || fps_scale != 256) // if(!NoWaiting) // if(!soundo || (soundo && nofocus && !(soundoptions&SO_SECONDARY)) || FCEUI_EmulationPaused() ) // skipthis = SpeedThrottle(); // // if(XBuf) // { // if((!skipthis && !NoWaiting) || (skipcount >= maxskip)) // { // FCEUD_BlitScreen(XBuf); // _updateMemWatch(); // skipcount = 0; // } // else // { // skipcount++; // } // } // // //mbg merge 7/19/06 - since tasbuild we have code in main that attempts to do stuff like this // //mbg merge 6/30/06 // //if(FCEUI_EmulationPaused()) // //{ // // StopSound(); // // Sleep(50); // // BlockingCheck(); // // goto doagain; // //} // } // // //mbg merge 7/19/06 // //UpdateFCEUWindow(); // //FCEUD_UpdateInput(); // _updateWindow(); // // } // end of !(old sound code) block //} void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count) { static int skipcount = 0; int temp_fps_scale=(NoWaiting&1)?(256*16):fps_scale; int maxskip = (temp_fps_scale<=256) ? 0 : temp_fps_scale>>8; int ocount = Count; // apply frame scaling to Count Count = (Count<<8)/temp_fps_scale; //mbg merge 7/19/06 - leaving this untouched but untested //Disable sound and throttling for BotMode--we want max speed! if(FCEU_BotMode()) { if(XBuf && (skipcount >= 64)) { skipcount = 0; FCEUD_BlitScreen(XBuf); } else { skipcount++; } UpdateFCEUWindow(); FCEUD_UpdateInput(); return; } //mbg naive code if(soundo && Buffer && Count) { int32 writeSize = GetWriteSound(); int32 writeCount = Count; FCEUD_WriteSoundData(Buffer,temp_fps_scale,MAX(writeSize,writeCount)); } if(XBuf) FCEUD_BlitScreen(XBuf); _updateWindow(); //delay until we unpause while(FCEUI_EmulationPaused()) { Sleep(50); BlockingCheck(); } // if(soundo) //&& temp_fps_scale >= 64 // { // // sounds better with FPS scaling, and is much less code than the other version... // // int32 writeSize = GetWriteSound(); // int32 writeCount = Count; ///* // // prevents delay when exiting fast-forward // if((NoWaiting&1) && writeCount>writeSize) // writeCount=writeSize; //*/ // // if(Buffer && (writeCount)) // FCEUD_WriteSoundData(Buffer,temp_fps_scale,MAX(writeSize,writeCount)); // // if(XBuf && (skipcount >= maxskip)) // { // skipcount = 0; // FCEUD_BlitScreen(XBuf); // _updateMemWatch(); // } // else // skipcount++; // // _updateWindow(); // } //#ifdef NETWORK // if(!NoWaiting && FCEUDnetplay && (uflow || tmpcan >= (Count * 0.90))) // { // if(Count > tmpcan) Count=tmpcan; // while(tmpcan > 0) // { // //printf("Overwrite: %d\n", (Count <= tmpcan)?Count : tmpcan); // FCEUD_WriteSoundData(Buffer,soundScale,(Count <= tmpcan)?Count : tmpcan); // tmpcan -= Count; // } // } //#endif // { // /* This complex statement deserves some explanation. // Make sure this special speed throttling hasn't been disabled by the user // first. Second, we don't want to throttle the speed if the fast-forward // button is pressed down(or during certain network play conditions). // Now, if we're at this point, we'll throttle speed if sound is disabled. // Otherwise, it gets a bit more complicated. We'll throttle speed if focus // to FCE Ultra has been lost and we're writing to the primary sound buffer // because our sound code won't block. Blocking does seem to work when // writing to a secondary buffer, so we won't throttle when a secondary // buffer is used. // */ // //doagain: //mbg merge 6/30/06 // int skipthis = 0; // if(!(eoptions&EO_NOTHROTTLE) || fps_scale != 256) // if(!NoWaiting) // if(!soundo || (soundo && nofocus && !(soundoptions&SO_SECONDARY)) || FCEUI_EmulationPaused() ) // skipthis = SpeedThrottle(); // if(XBuf) // { // if((!skipthis && !NoWaiting) || (skipcount >= maxskip)) // { // FCEUD_BlitScreen(XBuf); // _updateMemWatch(); // skipcount = 0; // } // else // { // skipcount++; // } // } // //mbg merge 7/19/06 - since tasbuild we have code in main that attempts to do stuff like this // //mbg merge 6/30/06 // //if(FCEUI_EmulationPaused()) // //{ // // StopSound(); // // Sleep(50); // // BlockingCheck(); // // goto doagain; // //} // } // //mbg merge 7/19/06 // //UpdateFCEUWindow(); // //FCEUD_UpdateInput(); // _updateWindow(); //} // end of !(old sound code) block } /* void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count) { FCEUD_BlitScreen(XBuf); if(Count && soundo) FCEUD_WriteSoundData(Buffer,Count); 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); } FILE *FCEUD_UTF8fopen(const char *n, const char *m) { if(strchr(m,'w')||strchr(m,'+')) FCEUD_MakePathDirs(n); return(fopen(n,m)); } int FCEUD_ShowStatusIcon(void) { return status_icon; } void FCEUD_ToggleStatusIcon(void) { status_icon=!status_icon; UpdateMenu(); }