/* 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 "state.c" /* Save/Load state AS */ extern char *md5_asciistr(uint8 digest[16]); extern FCEUGI *FCEUGameInfo; extern int EnableRewind; void DSMFix(UINT msg) { switch(msg) { case WM_VSCROLL: case WM_NCRBUTTONDOWN: case WM_NCMBUTTONDOWN: case WM_NCLBUTTONDOWN: case WM_ENTERMENULOOP:StopSound();break; } } static void ConfigGUI(void); static void ConfigTiming(void); static void ConfigPalette(void); static void ConfigDirectories(void); static HMENU fceumenu=0; static int tog=0; static int CheckedAutoFirePattern=40004; static int CheckedAutoFireOffset=40016; static int EnableBackgroundInput=0; void ShowCursorAbs(int w) { static int stat=0; if(w) { if(stat==-1) {stat++; ShowCursor(1);} } else { if(stat==0) {stat--; ShowCursor(0);} } } void CalcWindowSize(RECT *al) { al->left=0; al->right=VNSWID*winsizemulx; al->top=0; al->bottom=totallines*winsizemuly; AdjustWindowRectEx(al,GetWindowLong(hAppWnd,GWL_STYLE),GetMenu(hAppWnd)!=NULL,GetWindowLong(hAppWnd,GWL_EXSTYLE)); al->right-=al->left; al->left=0; al->bottom-=al->top; al->top=0; } void RedoMenuGI(FCEUGI *gi) { int simpled[]={101,111,110,200,201,204,203,141,142,143,151,152,300,40003,40028, 0}; int x; x = 0; while(simpled[x]) { #ifndef FCEUDEF_DEBUGGER if(simpled[x] == 203) EnableMenuItem(fceumenu,simpled[x],MF_BYCOMMAND | MF_GRAYED); else #endif #ifndef _USE_SHARED_MEMORY_ if(simpled[x] == 40002 || simpled[x] == 40003) EnableMenuItem(fceumenu,simpled[x],MF_BYCOMMAND| MF_GRAYED); else #endif EnableMenuItem(fceumenu,simpled[x],MF_BYCOMMAND | (gi?MF_ENABLED:MF_GRAYED)); x++; } } void UpdateMenu(void) { static int *polo[3]={&genie,&palyo,&status_icon}; static int polo2[3]={310,311,303}; int x; for(x=0;x<3;x++) CheckMenuItem(fceumenu,polo2[x],*polo[x]?MF_CHECKED:MF_UNCHECKED); if(eoptions&EO_BGRUN) CheckMenuItem(fceumenu,301,MF_CHECKED); else CheckMenuItem(fceumenu,301,MF_UNCHECKED); if(FCEU_BotMode()) CheckMenuItem(fceumenu,40003, MF_CHECKED); else CheckMenuItem(fceumenu,40003, MF_UNCHECKED); if(GetAutoFireDesynch()) CheckMenuItem(fceumenu,40025, MF_CHECKED); else CheckMenuItem(fceumenu,40025, MF_UNCHECKED); CheckMenuItem(fceumenu,302, EnableBackgroundInput?MF_CHECKED:MF_UNCHECKED); CheckMenuItem(fceumenu,40029, EnableRewind?MF_CHECKED:MF_UNCHECKED); int AutoFirePatternIDs[]={40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,40014,40015,40022,40023,40024,0}; int AutoFireOffsetIDs[]={40016,40017,40018,40019,40020,40021,0}; x = 0; while(AutoFirePatternIDs[x]) { CheckMenuItem(fceumenu,AutoFirePatternIDs[x], AutoFirePatternIDs[x]==CheckedAutoFirePattern?MF_CHECKED:MF_UNCHECKED); x++; } x = 0; while(AutoFireOffsetIDs[x]) { CheckMenuItem(fceumenu,AutoFireOffsetIDs[x], AutoFireOffsetIDs[x]==CheckedAutoFireOffset?MF_CHECKED:MF_UNCHECKED); x++; } } static HMENU recentmenu, recentdmenu; char *rfiles[10]={0,0,0,0,0,0,0,0,0,0}; char *rdirs[10]={0,0,0,0,0,0,0,0,0,0}; void UpdateRMenu(HMENU menu, char **strs, int mitem, int baseid) { MENUITEMINFO moo; int x; moo.cbSize=sizeof(moo); moo.fMask=MIIM_SUBMENU|MIIM_STATE; GetMenuItemInfo(GetSubMenu(fceumenu,0),mitem,FALSE,&moo); moo.hSubMenu=menu; moo.fState=strs[0]?MFS_ENABLED:MFS_GRAYED; SetMenuItemInfo(GetSubMenu(fceumenu,0),mitem,FALSE,&moo); for(x=0;x<10;x++) RemoveMenu(menu,baseid+x,MF_BYCOMMAND); for(x=9;x>=0;x--) { char tmp[128+5]; if(!strs[x]) continue; moo.cbSize=sizeof(moo); moo.fMask=MIIM_DATA|MIIM_ID|MIIM_TYPE; if(strlen(strs[x])<128) { sprintf(tmp,"&%d. %s",(x+1)%10,strs[x]); } else sprintf(tmp,"&%d. %s",(x+1)%10,strs[x]+strlen(strs[x])-127); moo.cch=strlen(tmp); moo.fType=0; moo.wID=baseid+x; moo.dwTypeData=tmp; InsertMenuItem(menu,0,1,&moo); } DrawMenuBar(hAppWnd); } void AddRecent(char *fn) { int x; for(x=0;x<10;x++) if(rfiles[x]) if(!strcmp(rfiles[x],fn)) // Item is already in list. { int y; char *tmp; tmp=rfiles[x]; // Save pointer. for(y=x;y;y--) rfiles[y]=rfiles[y-1]; // Move items down. rfiles[0]=tmp; // Put item on top. UpdateRMenu(recentmenu, rfiles, 102, 600); return; } if(rfiles[9]) free(rfiles[9]); for(x=9;x;x--) rfiles[x]=rfiles[x-1]; rfiles[0]=(char*)malloc(strlen(fn)+1); //mbg merge 7/17/06 added cast strcpy(rfiles[0],fn); UpdateRMenu(recentmenu, rfiles, 102, 600); } void AddRecentDir(char *fn) { int x; for(x=0;x<10;x++) if(rdirs[x]) if(!strcmp(rdirs[x],fn)) // Item is already in list. { int y; char *tmp; tmp=rdirs[x]; // Save pointer. for(y=x;y;y--) rdirs[y]=rdirs[y-1]; // Move items down. rdirs[0]=tmp; // Put item on top. UpdateRMenu(recentdmenu, rdirs, 103, 700); return; } if(rdirs[9]) free(rdirs[9]); for(x=9;x;x--) rdirs[x]=rdirs[x-1]; rdirs[0]=(char *)malloc(strlen(fn)+1); //mbg merge 7/17/06 added cast strcpy(rdirs[0],fn); UpdateRMenu(recentdmenu, rdirs, 103, 700); } void HideMenu(int h) { if(h) { SetMenu(hAppWnd,0); } else { SetMenu(hAppWnd,fceumenu); } } static LONG WindowXC=1<<30,WindowYC; void HideFWindow(int h) { LONG desa; if(h) /* Full-screen. */ { RECT bo; GetWindowRect(hAppWnd,&bo); WindowXC=bo.left; WindowYC=bo.top; SetMenu(hAppWnd,0); desa=WS_POPUP|WS_CLIPSIBLINGS; } else { desa=WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS; HideMenu(tog); /* Stupid DirectDraw bug(I think?) requires this. Need to investigate it. */ SetWindowPos(hAppWnd,HWND_NOTOPMOST,0,0,0,0,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOREPOSITION|SWP_NOSIZE); } SetWindowLong(hAppWnd,GWL_STYLE,desa|(GetWindowLong(hAppWnd,GWL_STYLE)&WS_VISIBLE)); SetWindowPos(hAppWnd,0,0,0,0,0,SWP_FRAMECHANGED|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOREPOSITION|SWP_NOSIZE|SWP_NOZORDER); } void ToggleHideMenu(void) { extern FCEUGI *FCEUGameInfo; if(!fullscreen && (FCEUGameInfo || tog)) { tog^=1; HideMenu(tog); SetMainWindowStuff(); } } void FCEUD_HideMenuToggle(void) { ToggleHideMenu(); } static void ALoad(char *nameo) { if((GI=FCEUI_LoadGame(nameo,1))) { palyo=FCEUI_GetCurrentVidSystem(0,0); UpdateMenu(); FixFL(); SetMainWindowStuff(); AddRecent(nameo); RefreshThrottleFPS(); if(eoptions&EO_HIDEMENU && !tog) ToggleHideMenu(); if(eoptions&EO_FSAFTERLOAD) SetFSVideoMode(); } else StopSound(); ParseGIInput(GI); RedoMenuGI(GI); } void LoadNewGamey(HWND hParent, char *initialdir) { const char filter[]="All usable files(*.nes,*.nsf,*.fds,*.unf,*.zip,*.gz)\0*.nes;*.nsf;*.fds;*.unf;*.zip;*.gz\0All non-compressed usable files(*.nes,*.nsf,*.fds,*.unf)\0*.nes;*.nsf;*.fds;*.unf\0All files (*.*)\0*.*\0"; char nameo[2048]; OPENFILENAME ofn; memset(&ofn,0,sizeof(ofn)); ofn.lStructSize=sizeof(ofn); ofn.hInstance=fceu_hInstance; ofn.lpstrTitle="FCE Ultra Open File..."; ofn.lpstrFilter=filter; nameo[0]=0; ofn.hwndOwner=hParent; ofn.lpstrFile=nameo; ofn.nMaxFile=256; ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; //OFN_EXPLORER|OFN_ENABLETEMPLATE|OFN_ENABLEHOOK; ofn.lpstrInitialDir=initialdir?initialdir:gfsdir; if(GetOpenFileName(&ofn)) { char *tmpdir; if((tmpdir=(char *)malloc(ofn.nFileOffset+1))) //mbg merge 7/17/06 added cast { strncpy(tmpdir,ofn.lpstrFile,ofn.nFileOffset); tmpdir[ofn.nFileOffset]=0; AddRecentDir(tmpdir); if(!initialdir) // Prevent setting the File->Open default // directory when a "Recent Directory" is selected. { if(gfsdir) free(gfsdir); gfsdir = tmpdir; } else free(tmpdir); } ALoad(nameo); } } static uint32 mousex,mousey,mouseb; void GetMouseData(uint32 *md) { if(FCEUI_IsMovieActive()<0) return; md[0]=mousex; md[1]=mousey; if(!fullscreen) { if(ismaximized) { RECT t; GetClientRect(hAppWnd, &t); md[0] = md[0] * VNSWID / (t.right?t.right:1); md[1] = md[1] * totallines / (t.bottom?t.bottom:1); } else { md[0]/=winsizemulx; md[1]/=winsizemuly; } md[0]+=VNSCLIP; } md[1]+=srendline; md[2]=((mouseb==MK_LBUTTON)?1:0)|((mouseb==MK_RBUTTON)?2:0); } //static int sizchange=0; static int vchanged=0; extern void RestartMovieOrReset(int pow); int KeyboardSetBackgroundAccess(int on); //mbg merge 7/17/06 YECH had to add void SetJoystickBackgroundAccess(int background); //mbg merge 7/17/06 YECH had to add void ShowNetplayConsole(void); //mbg merge 7/17/06 YECH had to add int FCEUMOV_IsPlaying(void); //mbg merge 7/17/06 YECH had to add void DoPPUView();//mbg merge 7/19/06 yech had to add void MapInput(void); LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { DSMFix(msg); switch(msg) { case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: mouseb=wParam; goto proco; case WM_MOUSEMOVE: { mousex=LOWORD(lParam); mousey=HIWORD(lParam); } goto proco; case WM_ERASEBKGND: if(xbsave) return(0); else goto proco; case WM_PAINT:if(xbsave) { PAINTSTRUCT ps; BeginPaint(hWnd,&ps); FCEUD_BlitScreen(xbsave); EndPaint(hWnd,&ps); return(0); } goto proco; case WM_SIZE: if(!fullscreen && !changerecursive) switch(wParam) { case SIZE_MAXIMIZED: ismaximized = 1;SetMainWindowStuff();break; case SIZE_RESTORED: ismaximized = 0;SetMainWindowStuff();break; } break; case WM_SIZING: { RECT *wrect=(RECT *)lParam; RECT srect; int h=wrect->bottom-wrect->top; int w=wrect->right-wrect->left; int how; if(wParam == WMSZ_BOTTOM || wParam == WMSZ_TOP) how = 2; else if(wParam == WMSZ_LEFT || wParam == WMSZ_RIGHT) how = 1; else if(wParam == WMSZ_BOTTOMLEFT || wParam == WMSZ_BOTTOMRIGHT || wParam == WMSZ_TOPRIGHT || wParam == WMSZ_TOPLEFT) how = 3; if(how & 1) winsizemulx*= (double)w/winwidth; if(how & 2) winsizemuly*= (double)h/winheight; if(how & 1) FixWXY(0); else FixWXY(1); CalcWindowSize(&srect); winwidth=srect.right; winheight=srect.bottom; wrect->right = wrect->left + srect.right; wrect->bottom = wrect->top + srect.bottom; } //sizchange=1; //break; goto proco; case WM_DISPLAYCHANGE: if(!fullscreen && !changerecursive) vchanged=1; goto proco; case WM_DROPFILES: { UINT len; char *ftmp; len=DragQueryFile((HDROP)wParam,0,0,0)+1; //mbg merge 7/17/06 changed (HANDLE) to (HDROP) if((ftmp=(char*)malloc(len))) //mbg merge 7/17/06 added cast { DragQueryFile((HDROP)wParam,0,ftmp,len); //mbg merge 7/17/06 changed (HANDLE) to (HDROP) ALoad(ftmp); free(ftmp); } } break; case WM_COMMAND: if(!(wParam>>16)) { wParam&=0xFFFF; if(wParam>=600 && wParam<=609) // Recent files { if(rfiles[wParam-600]) ALoad(rfiles[wParam-600]); } else if(wParam >= 700 && wParam <= 709) // Recent dirs { if(rdirs[wParam-700]) LoadNewGamey(hWnd, rdirs[wParam - 700]); } switch(wParam) { //------- //mbg merge 7/18/06 added XD tools case ID_DEBUG_DEBUGGER: DoDebug(0); break; case ID_DEBUG_PPUVIEWER: DoPPUView(); break; case ID_DEBUG_NAMETABLEVIEWER: DoNTView(); break; case ID_DEBUG_HEXEDITOR: DoMemView(); break; case ID_DEBUG_TRACELOGGER: DoTracer(); break; case ID_DEBUG_GAMEGENIEDECODER: DoGGConv(); break; case ID_DEBUG_CDLOGGER: DoCDLogger(); break; case 40004: SetAutoFirePattern(1,1); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40005: SetAutoFirePattern(1,2); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40006: SetAutoFirePattern(1,3); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40007: SetAutoFirePattern(1,4); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40008: SetAutoFirePattern(1,5); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40009: SetAutoFirePattern(2,1); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40010: SetAutoFirePattern(2,2); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40011: SetAutoFirePattern(2,3); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40012: SetAutoFirePattern(2,4); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40013: SetAutoFirePattern(3,1); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40014: SetAutoFirePattern(3,2); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40015: SetAutoFirePattern(3,3); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40022: SetAutoFirePattern(4,1); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40023: SetAutoFirePattern(4,2); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40024: SetAutoFirePattern(5,1); CheckedAutoFirePattern = wParam; UpdateMenu(); break; case 40016: case 40017: case 40018: case 40019: case 40020: case 40021: SetAutoFireOffset(wParam - 40016); CheckedAutoFireOffset = wParam; UpdateMenu(); break; case 40025: SetAutoFireDesynch(GetAutoFireDesynch()^1); UpdateMenu(); break; case 300:ToggleHideMenu();break; case 301: eoptions^=EO_BGRUN; if((eoptions & EO_BGRUN) == 0) { EnableBackgroundInput = 0; KeyboardSetBackgroundAccess(EnableBackgroundInput); SetJoystickBackgroundAccess(EnableBackgroundInput); } UpdateMenu(); break; case 302:EnableBackgroundInput ^= 1; eoptions |= EO_BGRUN*EnableBackgroundInput; KeyboardSetBackgroundAccess(EnableBackgroundInput); SetJoystickBackgroundAccess(EnableBackgroundInput); UpdateMenu(); break; case 40029: EnableRewind^= 1; UpdateMenu(); break; case 303:status_icon=!status_icon;UpdateMenu();break; case 310:genie^=1;FCEUI_SetGameGenie(genie);UpdateMenu();break; case 311:palyo^=1; FCEUI_SetVidSystem(palyo); RefreshThrottleFPS(); UpdateMenu(); FixFL(); // DoVideoConfigFix(); SetMainWindowStuff(); break; case 40003: FCEU_SetBotMode(1^FCEU_BotMode()); UpdateMenu(); break; case 40002: CreateBasicBot();break; // case 40028: DoMemmo(0); break; //mbg merge 7/18/06 removed as part of old debugger case 320:StopSound();ConfigDirectories();break; case 327:StopSound();ConfigGUI();break; case 321:StopSound();ConfigInput(hWnd);break; case 322:ConfigTiming();break; case 323:StopSound();ShowNetplayConsole();break; case 324:StopSound();ConfigPalette();break; case 325:StopSound();ConfigSound();break; case 326:ConfigVideo();break; case 328:MapInput();break; case 200:RestartMovieOrReset(0);break; case 201:RestartMovieOrReset(1);break; case 40026: FCEUI_FDSSelect();break; case 40001: FCEUI_FDSInsert();break; case 40027: FCEUI_VSUniCoin();break; #ifdef FCEUDEF_DEBUGGER //case 203:BeginDSeq(hWnd);break; //mbg merge 7/18/06 removed as part of old debugger #endif //case 204:ConfigAddCheat(hWnd);break; //mbg merge TODO 7/17/06 - had to remove this //mbg merge TODO 7/17/06 - had to remove this //case 205:CreateMemWatch(hWnd);break; case 100:StopSound(); LoadNewGamey(hWnd, 0); break; case 101:if(GI) { #ifdef FCEUDEF_DEBUGGER //KillDebugger(); //mbg merge 7/18/06 removed as part of old debugger #endif FCEUI_CloseGame(); GI=0; RedoMenuGI(GI); } break; case 110:FCEUD_SaveStateAs();break; case 111:FCEUD_LoadStateFrom();break; case 40120: //mbg merge 7/18/06 changed ID from 120 { MENUITEMINFO mi; char *str; StopSound(); if(CreateSoundSave()) str="Stop Sound Logging"; else str="Log Sound As..."; memset(&mi,0,sizeof(mi)); mi.fMask=MIIM_DATA|MIIM_TYPE; mi.cbSize=sizeof(mi); GetMenuItemInfo(fceumenu,120,0,&mi); mi.fMask=MIIM_DATA|MIIM_TYPE; mi.cbSize=sizeof(mi); mi.dwTypeData=str; mi.cch=strlen(str); SetMenuItemInfo(fceumenu,120,0,&mi); } break; case 130:DoFCEUExit();break; case 141:FCEUD_MovieRecordTo();break; case 142:FCEUD_MovieReplayFrom();break; case 143:FCEUI_StopMovie();break; case 151:FCEUD_AviRecordTo();break; case 152:FCEUD_AviStop();break; case 400:StopSound();ShowAboutBox();break; case 401:MakeLogWindow();break; } } break; case WM_SYSCOMMAND: if(GI && wParam == SC_SCREENSAVE && (goptions & GOO_DISABLESS)) return(0); if(wParam==SC_KEYMENU) { if(GI && InputType[2]==SIFC_FKB && cidisabled) break; if(lParam == VK_RETURN || fullscreen || tog) break; } goto proco; case WM_SYSKEYDOWN: if(GI && InputType[2]==SIFC_FKB && cidisabled) break; /* Hopefully this won't break DInput... */ if(fullscreen || tog) { if(wParam==VK_MENU) break; } if(wParam==VK_F10) { return 0; /* if(!moocow) FCEUD_PrintError("Iyee"); if(!(lParam&0x40000000)) FCEUI_ResetNES(); break; */ } if(wParam == VK_RETURN) { if(!(lParam&(1<<30))) { UpdateMenu(); changerecursive=1; if(!SetVideoMode(fullscreen^1)) SetVideoMode(fullscreen); changerecursive=0; } break; } goto proco; case WM_KEYDOWN: if(GI) { /* Only disable command keys if a game is loaded(and the other conditions are right, of course). */ if(InputType[2]==SIFC_FKB) { if(wParam==VK_SCROLL) { cidisabled^=1; FCEUI_DispMessage("Family Keyboard %sabled.",cidisabled?"en":"dis"); } if(cidisabled) break; /* Hopefully this won't break DInput... */ } } /* if(!(lParam&0x40000000)) switch( wParam ) { case VK_F11:FCEUI_PowerNES();break; case VK_F12:DoFCEUExit();break; //case VK_F2:userpause^=1;break; case VK_F3:ToggleHideMenu();break; } */ goto proco; case WM_CLOSE: case WM_DESTROY: case WM_QUIT:DoFCEUExit();break; case WM_ACTIVATEAPP: if((BOOL)wParam) { nofocus=0; } else { nofocus=1; } goto proco; case WM_ENTERMENULOOP: EnableMenuItem(fceumenu,143,MF_BYCOMMAND | (FCEUI_IsMovieActive()?MF_ENABLED:MF_GRAYED)); EnableMenuItem(fceumenu,152,MF_BYCOMMAND | (FCEUI_AviIsRecording()?MF_ENABLED:MF_GRAYED)); default: proco: return DefWindowProc(hWnd,msg,wParam,lParam); } return 0; } void FixWXY(int pref) { if(eoptions&EO_FORCEASPECT) { /* First, make sure the ratio is valid, and if it's not, change it so that it doesn't break everything. */ if(saspectw < 0.01) saspectw = 0.01; if(saspecth < 0.01) saspecth = 0.01; if((saspectw / saspecth) > 100) saspecth = saspectw; if((saspecth / saspectw) > 100) saspectw = saspecth; if((saspectw / saspecth) < 0.1) saspecth = saspectw; if((saspecth / saspectw) > 0.1) saspectw = saspecth; if(!pref) { winsizemuly = winsizemulx * 256 / 240 * 3 / 4 * saspectw / saspecth; } else { winsizemulx = winsizemuly * 240 / 256 * 4 / 3 * saspecth / saspectw; } } if(winspecial) { int mult; if(winspecial == 1 || winspecial == 2) mult = 2; else mult = 3; if(winsizemulx < mult) { if(eoptions&EO_FORCEASPECT) winsizemuly *= mult / winsizemulx; winsizemulx = mult; } if(winsizemuly < mult) { if(eoptions&EO_FORCEASPECT) winsizemulx *= mult / winsizemuly; winsizemuly = mult; } } if(winsizemulx<0.1) winsizemulx=0.1; if(winsizemuly<0.1) winsizemuly=0.1; if(eoptions & EO_FORCEISCALE) { int x,y; x = winsizemulx * 2; y = winsizemuly * 2; x = (x>>1) + (x&1); y = (y>>1) + (y&1); if(!x) x=1; if(!y) y=1; winsizemulx = x; winsizemuly = y; } if(winsizemulx > 100) winsizemulx = 100; if(winsizemuly > 100) winsizemuly = 100; } void UpdateFCEUWindow(void) { //int w,h; //mbg merge 7/17/06 removed // RECT wrect; //mbg merge 7/17/06 removed if(vchanged && !fullscreen && !changerecursive && !nofocus) { SetVideoMode(0); vchanged=0; } BlockingCheck(); //mbg merge 7/18/06 removed as part of old debugger //#ifdef FCEUDEF_DEBUGGER //UpdateDebugger(); //#endif if(!(eoptions&EO_BGRUN)) while(nofocus) { StopSound(); Sleep(75); BlockingCheck(); } //mbg merge 7/19/06 removing this since I think its not used //if(_userpause) //mbg merge 7/18/06 this changed. even though theres nothing setting this.. //{ // StopSound(); // while(_userpause) //mbg merge 7/18/06 this changed. even though theres nothing setting this.. // { // Sleep(50); // BlockingCheck(); // } //} } void ByebyeWindow(void) { SetMenu(hAppWnd,0); DestroyMenu(fceumenu); DestroyWindow(hAppWnd); } int CreateMainWindow(void) { WNDCLASSEX winclass; RECT tmp; memset(&winclass,0,sizeof(winclass)); winclass.cbSize=sizeof(WNDCLASSEX); winclass.style=CS_OWNDC|CS_HREDRAW|CS_VREDRAW|CS_SAVEBITS; winclass.lpfnWndProc=AppWndProc; winclass.cbClsExtra=0; winclass.cbWndExtra=0; winclass.hInstance=fceu_hInstance; winclass.hIcon=LoadIcon(fceu_hInstance, "ICON_1"); winclass.hIconSm=LoadIcon(fceu_hInstance, "ICON_1"); winclass.hCursor=LoadCursor(NULL, IDC_ARROW); winclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //mbg merge 7/17/06 added cast //winclass.lpszMenuName="FCEUMENU"; winclass.lpszClassName="FCEULTRA"; if(!RegisterClassEx(&winclass)) return FALSE; AdjustWindowRectEx(&tmp,WS_OVERLAPPEDWINDOW,1,0); fceumenu=LoadMenu(fceu_hInstance,"FCEUMENU"); recentmenu=CreateMenu(); recentdmenu = CreateMenu(); UpdateRMenu(recentmenu, rfiles, 102, 600); UpdateRMenu(recentdmenu, rdirs, 103, 700); RedoMenuGI(NULL); hAppWnd = CreateWindowEx(0,"FCEULTRA","FCE Ultra", WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS, /* Style */ CW_USEDEFAULT,CW_USEDEFAULT,256,240, /* X,Y ; Width, Height */ NULL,fceumenu,fceu_hInstance,NULL ); DragAcceptFiles(hAppWnd, 1); SetMainWindowStuff(); return 1; } int SetMainWindowStuff(void) { RECT tmp; GetWindowRect(hAppWnd,&tmp); if(ismaximized) { winwidth=tmp.right - tmp.left; winheight=tmp.bottom - tmp.top; ShowWindow(hAppWnd, SW_SHOWMAXIMIZED); } else { RECT srect; if(WindowXC!=(1<<30)) { /* Subtracting and adding for if(eoptions&EO_USERFORCE) below. */ tmp.bottom-=tmp.top; tmp.bottom+=WindowYC; tmp.right-=tmp.left; tmp.right+=WindowXC; tmp.left=WindowXC; tmp.top=WindowYC; WindowXC=1<<30; } CalcWindowSize(&srect); SetWindowPos(hAppWnd,HWND_TOP,tmp.left,tmp.top,srect.right,srect.bottom,SWP_SHOWWINDOW); winwidth=srect.right; winheight=srect.bottom; ShowWindow(hAppWnd, SW_SHOWNORMAL); } return 1; } int GetClientAbsRect(LPRECT lpRect) { POINT point; point.x=point.y=0; if(!ClientToScreen(hAppWnd,&point)) return 0; lpRect->top=point.y; lpRect->left=point.x; if(ismaximized) { RECT al; GetClientRect(hAppWnd, &al); lpRect->right = point.x + al.right; lpRect->bottom = point.y + al.bottom; } else { lpRect->right=point.x+VNSWID*winsizemulx; lpRect->bottom=point.y+totallines*winsizemuly; } return 1; } int LoadPaletteFile(void) { FILE *fp; const char filter[]="All usable files(*.pal)\0*.pal\0All files (*.*)\0*.*\0"; char nameo[2048]; OPENFILENAME ofn; memset(&ofn,0,sizeof(ofn)); ofn.lStructSize=sizeof(ofn); ofn.hInstance=fceu_hInstance; ofn.lpstrTitle="FCE Ultra Open Palette File..."; ofn.lpstrFilter=filter; nameo[0]=0; ofn.lpstrFile=nameo; ofn.nMaxFile=256; ofn.Flags=OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; ofn.lpstrInitialDir=0; if(GetOpenFileName(&ofn)) { if((fp=FCEUD_UTF8fopen(nameo,"rb"))) { fread(cpalette,1,192,fp); fclose(fp); FCEUI_SetPaletteArray(cpalette); eoptions|=EO_CPALETTE; return(1); } else FCEUD_PrintError("Error opening palette file!"); } return(0); } static HWND pwindow; static BOOL CALLBACK PaletteConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { DSMFix(uMsg); switch(uMsg) { case WM_INITDIALOG: if(ntsccol) CheckDlgButton(hwndDlg,100,BST_CHECKED); SendDlgItemMessage(hwndDlg,500,TBM_SETRANGE,1,MAKELONG(0,128)); SendDlgItemMessage(hwndDlg,501,TBM_SETRANGE,1,MAKELONG(0,128)); FCEUI_GetNTSCTH(&ntsctint,&ntschue); SendDlgItemMessage(hwndDlg,500,TBM_SETPOS,1,ntsctint); SendDlgItemMessage(hwndDlg,501,TBM_SETPOS,1,ntschue); EnableWindow(GetDlgItem(hwndDlg,201),(eoptions&EO_CPALETTE)?1:0); break; case WM_HSCROLL: ntsctint=SendDlgItemMessage(hwndDlg,500,TBM_GETPOS,0,(LPARAM)(LPSTR)0); ntschue=SendDlgItemMessage(hwndDlg,501,TBM_GETPOS,0,(LPARAM)(LPSTR)0); FCEUI_SetNTSCTH(ntsccol,ntsctint,ntschue); break; case WM_CLOSE: case WM_QUIT: goto gornk; case WM_COMMAND: if(!(wParam>>16)) switch(wParam&0xFFFF) { case 100:ntsccol^=1;FCEUI_SetNTSCTH(ntsccol,ntsctint,ntschue);break; case 200: StopSound(); if(LoadPaletteFile()) EnableWindow(GetDlgItem(hwndDlg,201),1); break; case 201:FCEUI_SetPaletteArray(0); eoptions&=~EO_CPALETTE; EnableWindow(GetDlgItem(hwndDlg,201),0); break; case 1: gornk: DestroyWindow(hwndDlg); pwindow=0; // Yay for user race conditions. break; } } return 0; } static void ConfigPalette(void) { if(!pwindow) pwindow=CreateDialog(fceu_hInstance,"PALCONFIG",0,PaletteConCallB); else SetFocus(pwindow); } static BOOL CALLBACK TimingConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { int x; switch(uMsg) { case WM_INITDIALOG: if(eoptions&EO_HIGHPRIO) CheckDlgButton(hwndDlg,105,BST_CHECKED); if(eoptions&EO_NOTHROTTLE) CheckDlgButton(hwndDlg,101,BST_CHECKED); for(x=0;x<10;x++) { char buf[8]; sprintf(buf,"%d",x); SendDlgItemMessage(hwndDlg,110,CB_ADDSTRING,0,(LPARAM)(LPSTR)buf); SendDlgItemMessage(hwndDlg,111,CB_ADDSTRING,0,(LPARAM)(LPSTR)buf); } SendDlgItemMessage(hwndDlg,110,CB_SETCURSEL,maxconbskip,(LPARAM)(LPSTR)0); SendDlgItemMessage(hwndDlg,111,CB_SETCURSEL,ffbskip,(LPARAM)(LPSTR)0); break; case WM_CLOSE: case WM_QUIT: goto gornk; case WM_COMMAND: if(!(wParam>>16)) switch(wParam&0xFFFF) { case 1: gornk: if(IsDlgButtonChecked(hwndDlg,105)==BST_CHECKED) eoptions|=EO_HIGHPRIO; else eoptions&=~EO_HIGHPRIO; if(IsDlgButtonChecked(hwndDlg,101)==BST_CHECKED) eoptions|=EO_NOTHROTTLE; else eoptions&=~EO_NOTHROTTLE; maxconbskip=SendDlgItemMessage(hwndDlg,110,CB_GETCURSEL,0,(LPARAM)(LPSTR)0); ffbskip=SendDlgItemMessage(hwndDlg,111,CB_GETCURSEL,0,(LPARAM)(LPSTR)0); EndDialog(hwndDlg,0); break; } } return 0; } void DoTimingConfigFix(void) { DoPriority(); } static void ConfigTiming(void) { DialogBox(fceu_hInstance,"TIMINGCONFIG",hAppWnd,TimingConCallB); DoTimingConfigFix(); } static BOOL CALLBACK GUIConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: if(eoptions&EO_FOAFTERSTART) CheckDlgButton(hwndDlg,102,BST_CHECKED); if(eoptions&EO_HIDEMENU) CheckDlgButton(hwndDlg,104,BST_CHECKED); if(goptions & GOO_CONFIRMEXIT) CheckDlgButton(hwndDlg,110,BST_CHECKED); if(goptions & GOO_DISABLESS) CheckDlgButton(hwndDlg,111,BST_CHECKED); break; case WM_CLOSE: case WM_QUIT: goto gornk; case WM_COMMAND: if(!(wParam>>16)) switch(wParam&0xFFFF) { case 1: gornk: if(IsDlgButtonChecked(hwndDlg,102)==BST_CHECKED) eoptions|=EO_FOAFTERSTART; else eoptions&=~EO_FOAFTERSTART; if(IsDlgButtonChecked(hwndDlg,104)==BST_CHECKED) eoptions|=EO_HIDEMENU; else eoptions&=~EO_HIDEMENU; goptions &= ~(GOO_CONFIRMEXIT | GOO_DISABLESS); if(IsDlgButtonChecked(hwndDlg,110)==BST_CHECKED) goptions |= GOO_CONFIRMEXIT; if(IsDlgButtonChecked(hwndDlg,111)==BST_CHECKED) goptions |= GOO_DISABLESS; EndDialog(hwndDlg,0); break; } } return 0; } static void ConfigGUI(void) { DialogBox(fceu_hInstance,"GUICONFIG",hAppWnd,GUIConCallB); } static int BrowseForFolder(HWND hParent, char *htext, char *buf) { BROWSEINFO bi; LPCITEMIDLIST pidl; int ret=1; buf[0]=0; memset(&bi,0,sizeof(bi)); bi.hwndOwner=hParent; bi.lpszTitle=htext; bi.ulFlags=BIF_RETURNONLYFSDIRS; if(FAILED(CoInitialize(0))) return(0); if(!(pidl=SHBrowseForFolder(&bi))) { ret=0; goto end1; } if(!SHGetPathFromIDList(pidl,buf)) { ret=0; goto end2; } end2: /* This probably isn't the best way to free the memory... */ CoTaskMemFree((PVOID)pidl); end1: CoUninitialize(); return(ret); } static BOOL CALLBACK DirConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { int x; switch(uMsg){ case WM_INITDIALOG: SetDlgItemText(hwndDlg,65508,"The settings in the \"Individual Directory Overrides\" group will override the settings in the \"Base Directory Override\" group. To delete an override, delete the text from the text edit control. Note that the directory the configuration file is in cannot be overridden"); for(x=0;x<6;x++) SetDlgItemText(hwndDlg,100+x,DOvers[x]); if(eoptions&EO_SNAPNAME) CheckDlgButton(hwndDlg,300,BST_CHECKED); break; case WM_CLOSE: case WM_QUIT: goto gornk; case WM_COMMAND: if(!(wParam>>16)) { if((wParam&0xFFFF)>=200 && (wParam&0xFFFF)<=205) { static char *helpert[6]={"Cheats","Miscellaneous","Nonvolatile Game Data","Save States","Screen Snapshots","Base Directory"}; char name[MAX_PATH]; if(BrowseForFolder(hwndDlg,helpert[((wParam&0xFFFF)-200)],name)) SetDlgItemText(hwndDlg,100+((wParam&0xFFFF)-200),name); } else switch(wParam&0xFFFF) { case 1: gornk: if(IsDlgButtonChecked(hwndDlg,300)==BST_CHECKED) eoptions|=EO_SNAPNAME; else eoptions&=~EO_SNAPNAME; RemoveDirs(); // Remove empty directories. for(x=0;x<6;x++) { LONG len; len=SendDlgItemMessage(hwndDlg,100+x,WM_GETTEXTLENGTH,0,0); if(len<=0) { if(DOvers[x]) free(DOvers[x]); DOvers[x]=0; continue; } len++; // Add 1 for null character. if(!(DOvers[x]=(char*)malloc(len))) //mbg merge 7/17/06 added cast continue; if(!GetDlgItemText(hwndDlg,100+x,DOvers[x],len)) { free(DOvers[x]); DOvers[x]=0; continue; } } CreateDirs(); // Create needed directories. SetDirs(); // Set the directories in the core. EndDialog(hwndDlg,0); break; } } } return 0; } static void ConfigDirectories(void) { DialogBox(fceu_hInstance,"DIRCONFIG",hAppWnd,DirConCallB); } static int ReplayDialogReadOnlyStatus = 0; static int ReplayDialogStopFrame = 0; static char* GetReplayPath(HWND hwndDlg) { char* fn=0; char szChoice[MAX_PATH]; LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0); LONG lCount = SendDlgItemMessage(hwndDlg, 200, CB_GETCOUNT, 0, 0); // NOTE: lCount-1 is the "Browse..." list item if(lIndex != CB_ERR && lIndex != lCount-1) { LONG lStringLength = SendDlgItemMessage(hwndDlg, 200, CB_GETLBTEXTLEN, (WPARAM)lIndex, 0); if(lStringLength < MAX_PATH) { char szDrive[MAX_PATH]={0}; char szDirectory[MAX_PATH]={0}; char szFilename[MAX_PATH]={0}; char szExt[MAX_PATH]={0}; char szTemp[MAX_PATH]={0}; SendDlgItemMessage(hwndDlg, 200, CB_GETLBTEXT, (WPARAM)lIndex, (LPARAM)szTemp); if(szTemp[0] && szTemp[1]!=':') sprintf(szChoice, ".\\%s", szTemp); else strcpy(szChoice, szTemp); SetCurrentDirectory(BaseDirectory); _splitpath(szChoice, szDrive, szDirectory, szFilename, szExt); if(szDrive[0]=='\0' && szDirectory[0]=='\0') fn=FCEU_MakePath(FCEUMKF_MOVIE, szChoice); // need to make a full path else fn=strdup(szChoice); // given a full path } } return fn; } static char* GetRecordPath(HWND hwndDlg) { char* fn=0; char szChoice[MAX_PATH]; char szDrive[MAX_PATH]={0}; char szDirectory[MAX_PATH]={0}; char szFilename[MAX_PATH]={0}; char szExt[MAX_PATH]={0}; GetDlgItemText(hwndDlg, 200, szChoice, sizeof(szChoice)); _splitpath(szChoice, szDrive, szDirectory, szFilename, szExt); if(szDrive[0]=='\0' && szDirectory[0]=='\0') fn=FCEU_MakePath(FCEUMKF_MOVIE, szChoice); // need to make a full path else fn=strdup(szChoice); // given a full path return fn; } static char* GetSavePath(HWND hwndDlg) { char* fn=0; char szDrive[MAX_PATH]={0}; char szDirectory[MAX_PATH]={0}; char szFilename[MAX_PATH]={0}; char szExt[MAX_PATH]={0}; LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0); LONG lStringLength = SendDlgItemMessage(hwndDlg, 301, CB_GETLBTEXTLEN, (WPARAM)lIndex, 0); fn = (char*)malloc(lStringLength); SendDlgItemMessage(hwndDlg, 301, CB_GETLBTEXT, (WPARAM)lIndex, (LPARAM)fn); _splitpath(fn, szDrive, szDirectory, szFilename, szExt); if(szDrive[0]=='\0' && szDirectory[0]=='\0') { char* newfn=FCEU_MakePath(FCEUMKF_MOVIE, fn); // need to make a full path free(fn); fn=newfn; } return fn; } // C:\fceu\movies\bla.fcm + C:\fceu\fceu\ -> C:\fceu\movies\bla.fcm // movies\bla.fcm + fceu\ -> movies\bla.fcm // C:\fceu\movies\bla.fcm + C:\fceu\ -> movies\bla.fcm void AbsoluteToRelative(char *const dst, const char *const dir, const char *const root) { int i, igood=0; for(i = 0 ; ; i++) { int a = tolower(dir[i]); int b = tolower(root[i]); if(a == '/' || a == '\0' || a == '.') a = '\\'; if(b == '/' || b == '\0' || b == '.') b = '\\'; if(a != b) { igood = 0; break; } if(a == '\\') igood = i+1; if(!dir[i] || !root[i]) break; } // if(igood) // sprintf(dst, ".\\%s", dir + igood); // else strcpy(dst, dir + igood); } extern int movieConvertOffset1, movieConvertOffset2,movieConvertOK; static int movieHackType=3; static void UpdateReplayDialog(HWND hwndDlg) { movieConvertOffset1=0, movieConvertOffset2=0,movieConvertOK=0; int doClear=1; char *fn=GetReplayPath(hwndDlg); // remember the previous setting for the read-only checkbox if(IsWindowEnabled(GetDlgItem(hwndDlg, 201))) ReplayDialogReadOnlyStatus = (SendDlgItemMessage(hwndDlg, 201, BM_GETCHECK, 0, 0) == BST_CHECKED) ? 1 : 0; if(fn) { MOVIE_INFO info; char metadata[MOVIE_MAX_METADATA]; char rom_name[MAX_PATH]; memset(&info, 0, sizeof(info)); info.metadata = metadata; info.metadata_size = sizeof(metadata); info.name_of_rom_used = rom_name; info.name_of_rom_used_size = sizeof(rom_name); if(FCEUI_MovieGetInfo(fn, &info)) { #define MOVIE_FLAG_NOSYNCHACK (1<<4) // set in newer version, used for old movie compatibility extern int resetDMCacc; extern int justAutoConverted; int noNoSyncHack=!(info.flags&MOVIE_FLAG_NOSYNCHACK) && resetDMCacc; EnableWindow(GetDlgItem(hwndDlg,1000),justAutoConverted || noNoSyncHack); EnableWindow(GetDlgItem(hwndDlg,1001),justAutoConverted || noNoSyncHack); if(justAutoConverted) { // use values as nesmock offsets if(movieHackType != 0) { movieHackType=0; SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)"2"); SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)"0"); SendDlgItemMessage(hwndDlg, 2000, WM_SETTEXT, 0,(LPARAM)"Offset:"); SendDlgItemMessage(hwndDlg, 2001, WM_SETTEXT, 0,(LPARAM)"from"); } } else if(noNoSyncHack) { // use values as sound reset hack values if(movieHackType != 1) { movieHackType=1; // extern int32 DMCacc; // extern int8 DMCBitCount; // char str[256]; // sprintf(str, "%d", DMCacc); // SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)str); // sprintf(str, "%d", DMCBitCount); // SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)str); SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)"8"); SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)"0"); SendDlgItemMessage(hwndDlg, 2000, WM_SETTEXT, 0,(LPARAM)"Missing data: acc="); SendDlgItemMessage(hwndDlg, 2001, WM_SETTEXT, 0,(LPARAM)"bc="); } } else if(movieHackType != 2) { movieHackType=2; SendDlgItemMessage(hwndDlg, 1000, WM_SETTEXT, 0,(LPARAM)""); SendDlgItemMessage(hwndDlg, 1001, WM_SETTEXT, 0,(LPARAM)""); SendDlgItemMessage(hwndDlg, 2000, WM_SETTEXT, 0,(LPARAM)""); SendDlgItemMessage(hwndDlg, 2001, WM_SETTEXT, 0,(LPARAM)""); } /* { // select away to autoconverted movie... but actually we don't want to do that now that there's an offset setting in the dialog extern char lastMovieInfoFilename [512]; char relative[MAX_PATH]; AbsoluteToRelative(relative, lastMovieInfoFilename, BaseDirectory); LONG lOtherIndex = SendDlgItemMessage(hwndDlg, 200, CB_FINDSTRING, (WPARAM)-1, (LPARAM)relative); if(lOtherIndex != CB_ERR) { // select already existing string SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lOtherIndex, 0); } else { LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0); SendDlgItemMessage(hwndDlg, 200, CB_INSERTSTRING, lIndex, (LPARAM)relative); SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lIndex, 0); } // restore focus to the dialog // SetFocus(GetDlgItem(hwndDlg, 200)); }*/ char tmp[256]; uint32 div; sprintf(tmp, "%lu", info.num_frames); SetWindowTextA(GetDlgItem(hwndDlg,301), tmp); // frames SetDlgItemText(hwndDlg,1003,tmp); div = (FCEUI_GetCurrentVidSystem(0,0)) ? 50 : 60; // PAL timing info.num_frames += (div>>1); // round up sprintf(tmp, "%02d:%02d:%02d", (info.num_frames/(div*60*60)), (info.num_frames/(div*60))%60, (info.num_frames/div) % 60); SetWindowTextA(GetDlgItem(hwndDlg,300), tmp); // length sprintf(tmp, "%lu", info.rerecord_count); SetWindowTextA(GetDlgItem(hwndDlg,302), tmp); // rerecord { // convert utf8 metadata to windows widechar WCHAR wszMeta[MOVIE_MAX_METADATA]; if(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, metadata, -1, wszMeta, MOVIE_MAX_METADATA)) { if(wszMeta[0]) SetWindowTextW(GetDlgItem(hwndDlg,303), wszMeta); // metadata else SetWindowTextW(GetDlgItem(hwndDlg,303), L"(this movie has no author info)"); // metadata } } EnableWindow(GetDlgItem(hwndDlg,201),(info.read_only)? FALSE : TRUE); // disable read-only checkbox if the file access is read-only SendDlgItemMessage(hwndDlg,201,BM_SETCHECK,info.read_only ? BST_CHECKED : (ReplayDialogReadOnlyStatus ? BST_CHECKED : BST_UNCHECKED), 0); SetWindowText(GetDlgItem(hwndDlg,306),(info.flags & MOVIE_FLAG_FROM_RESET) ? "Reset or Power-On" : "Savestate"); if(info.movie_version > 1) { char emuStr[128]; SetWindowText(GetDlgItem(hwndDlg,304),info.name_of_rom_used); SetWindowText(GetDlgItem(hwndDlg,305),md5_asciistr(info.md5_of_rom_used)); if(info.emu_version_used > 64) sprintf(emuStr, "FCEU %d.%02d.%02d%s", info.emu_version_used/10000, (info.emu_version_used/100)%100, (info.emu_version_used)%100, info.emu_version_used < 9813 ? " (blip)" : ""); else { if(info.emu_version_used == 1) strcpy(emuStr, "Famtasia"); else if(info.emu_version_used == 2) strcpy(emuStr, "Nintendulator"); else if(info.emu_version_used == 3) strcpy(emuStr, "VirtuaNES"); else { strcpy(emuStr, "(unknown)"); char* dot = strrchr(fn,'.'); if(dot) { if(!stricmp(dot,".fmv")) strcpy(emuStr, "Famtasia? (unknown version)"); else if(!stricmp(dot,".nmv")) strcpy(emuStr, "Nintendulator? (unknown version)"); else if(!stricmp(dot,".vmv")) strcpy(emuStr, "VirtuaNES? (unknown version)"); else if(!stricmp(dot,".fcm")) strcpy(emuStr, "FCEU? (unknown version)"); } } } SetWindowText(GetDlgItem(hwndDlg,307),emuStr); } else { SetWindowText(GetDlgItem(hwndDlg,304),"unknown"); SetWindowText(GetDlgItem(hwndDlg,305),"unknown"); SetWindowText(GetDlgItem(hwndDlg,307),"FCEU 0.98.10 (blip)"); } SetWindowText(GetDlgItem(hwndDlg,308),md5_asciistr(FCEUGameInfo->MD5)); EnableWindow(GetDlgItem(hwndDlg,1),TRUE); // enable OK doClear = 0; } free(fn); } else { EnableWindow(GetDlgItem(hwndDlg,1000),FALSE); EnableWindow(GetDlgItem(hwndDlg,1001),FALSE); } if(doClear) { SetWindowText(GetDlgItem(hwndDlg,300),""); SetWindowText(GetDlgItem(hwndDlg,301),""); SetWindowText(GetDlgItem(hwndDlg,302),""); SetWindowText(GetDlgItem(hwndDlg,303),""); SetWindowText(GetDlgItem(hwndDlg,304),""); SetWindowText(GetDlgItem(hwndDlg,305),""); SetWindowText(GetDlgItem(hwndDlg,306),"Nothing (invalid movie)"); SetWindowText(GetDlgItem(hwndDlg,307),""); SetWindowText(GetDlgItem(hwndDlg,308),md5_asciistr(FCEUGameInfo->MD5)); SetDlgItemText(hwndDlg,1003,""); EnableWindow(GetDlgItem(hwndDlg,201),FALSE); SendDlgItemMessage(hwndDlg,201,BM_SETCHECK,BST_UNCHECKED,0); EnableWindow(GetDlgItem(hwndDlg,1),FALSE); } } #define MAX(x,y) ((x)<(y)?(y):(x)) #define MIN(x,y) ((x)>(y)?(y):(x)) static BOOL CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { movieHackType=3; SendDlgItemMessage(hwndDlg, 201, BM_SETCHECK, moviereadonly?BST_CHECKED:BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, 1002,BM_SETCHECK, BST_UNCHECKED, 0); char* findGlob[2] = {FCEU_MakeFName(FCEUMKF_MOVIEGLOB, 0, 0), FCEU_MakeFName(FCEUMKF_MOVIEGLOB2, 0, 0)}; extern int suppress_scan_chunks; suppress_scan_chunks=1; int i=0, j=0; for(j=0;j<2;j++) { char* temp=0; do { temp=strchr(findGlob[j],'/'); if(temp) *temp = '\\'; } while(temp); // disabled because... apparently something is case sensitive?? // for(i=1;iMD5)); if(fcm) strcpy(md52, md5_asciistr(info.md5_of_rom_used)); if(!fcm || strcmp(md51, md52)) { if(fcm) { unsigned int k, count1=0, count2=0; //mbg merge 7/17/06 changed to uint for(k=0;k0) SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, i-1, 0); SendDlgItemMessage(hwndDlg, 200, CB_INSERTSTRING, i++, (LPARAM)"Browse..."); UpdateReplayDialog(hwndDlg); } SetFocus(GetDlgItem(hwndDlg, 200)); return FALSE; case WM_COMMAND: if(HIWORD(wParam) == CBN_SELCHANGE) { UpdateReplayDialog(hwndDlg); } else if(HIWORD(wParam) == CBN_CLOSEUP) { LONG lCount = SendDlgItemMessage(hwndDlg, 200, CB_GETCOUNT, 0, 0); LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0); if (lIndex != CB_ERR && lIndex == lCount-1) SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDOK, 0); // send an OK notification to open the file browser } else { int wID = LOWORD(wParam); switch(wID) { case IDOK: { LONG lCount = SendDlgItemMessage(hwndDlg, 200, CB_GETCOUNT, 0, 0); LONG lIndex = SendDlgItemMessage(hwndDlg, 200, CB_GETCURSEL, 0, 0); if(lIndex != CB_ERR) { if(lIndex == lCount-1) { // pop open a file browser... char *pn=FCEU_GetPath(FCEUMKF_MOVIE); char szFile[MAX_PATH]={0}; OPENFILENAME ofn; //int nRet; //mbg merge 7/17/06 removed memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndDlg; ofn.lpstrFilter = "Supported Movie Files (*.fcm|*.fmv|*.nmv|*.vmv)\0*.fcm;*.fmv;*.nmv;*.vmv\0FCEU Movie Files (*.fcm)\0*.fcm\0Famtasia Movie Files (*.fmv)\0*.fmv\0Nintendulator Movie Files (*.nmv)\0*.nmv\0VirtuaNES Movie Files (*.vmv)\0*.vmv\0All files(*.*)\0*.*\0\0"; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrInitialDir = pn; ofn.Flags = OFN_NOCHANGEDIR | OFN_HIDEREADONLY; ofn.lpstrDefExt = "fcm"; ofn.lpstrTitle = "Replay Movie from File"; if(GetOpenFileName(&ofn)) { char relative[MAX_PATH]; AbsoluteToRelative(relative, szFile, BaseDirectory); LONG lOtherIndex = SendDlgItemMessage(hwndDlg, 200, CB_FINDSTRING, (WPARAM)-1, (LPARAM)relative); if(lOtherIndex != CB_ERR) { // select already existing string SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lOtherIndex, 0); } else { SendDlgItemMessage(hwndDlg, 200, CB_INSERTSTRING, lIndex, (LPARAM)relative); SendDlgItemMessage(hwndDlg, 200, CB_SETCURSEL, lIndex, 0); } // restore focus to the dialog SetFocus(GetDlgItem(hwndDlg, 200)); UpdateReplayDialog(hwndDlg); // if (ofn.Flags & OFN_READONLY) // SendDlgItemMessage(hwndDlg, 201, BM_SETCHECK, BST_CHECKED, 0); // else // SendDlgItemMessage(hwndDlg, 201, BM_SETCHECK, BST_UNCHECKED, 0); } free(pn); } else { // user had made their choice // TODO: warn the user when they open a movie made with a different ROM char* fn=GetReplayPath(hwndDlg); //char TempArray[16]; //mbg merge 7/17/06 removed ReplayDialogReadOnlyStatus = (SendDlgItemMessage(hwndDlg, 201, BM_GETCHECK, 0, 0) == BST_CHECKED) ? 1 : 0; char offset1Str[32]={0}; char offset2Str[32]={0}; SendDlgItemMessage(hwndDlg, 1003, WM_GETTEXT, (WPARAM)32, (LPARAM)offset1Str); ReplayDialogStopFrame = (SendDlgItemMessage(hwndDlg, 1002, BM_GETCHECK,0,0) == BST_CHECKED)? strtol(offset1Str,0,10):0; SendDlgItemMessage(hwndDlg, 1000, WM_GETTEXT, (WPARAM)32, (LPARAM)offset1Str); SendDlgItemMessage(hwndDlg, 1001, WM_GETTEXT, (WPARAM)32, (LPARAM)offset2Str); movieConvertOffset1=strtol(offset1Str,0,10); movieConvertOffset2=strtol(offset2Str,0,10); movieConvertOK=1; EndDialog(hwndDlg, (INT_PTR)fn); } } } return TRUE; case IDCANCEL: EndDialog(hwndDlg, 0); return TRUE; } } case WM_CTLCOLORSTATIC: if((HWND)lParam == GetDlgItem(hwndDlg, 308)) { // draw the md5 sum in red if it's different from the md5 of the rom used in the replay HDC hdcStatic = (HDC)wParam; char szMd5Text[35]; GetDlgItemText(hwndDlg, 305, szMd5Text, 35); if(!strlen(szMd5Text) || !strcmp(szMd5Text, "unknown") || !strcmp(szMd5Text, "00000000000000000000000000000000") || !strcmp(szMd5Text, md5_asciistr(FCEUGameInfo->MD5))) SetTextColor(hdcStatic, RGB(0,0,0)); // use black color for a match (or no comparison) else SetTextColor(hdcStatic, RGB(255,0,0)); // use red for a mismatch SetBkMode(hdcStatic, TRANSPARENT); return (LONG)GetStockObject(NULL_BRUSH); } else return FALSE; } return FALSE; }; void FCEUD_MovieReplayFrom(void) { char* fn; StopSound(); fn=(char*)DialogBox(fceu_hInstance, "IDD_REPLAYINP", hAppWnd, ReplayDialogProc); if(fn) { FCEUI_LoadMovie(fn, ReplayDialogReadOnlyStatus, ReplayDialogStopFrame); free(fn); palyo=FCEUI_GetCurrentVidSystem(0,0); UpdateMenu(); FixFL(); SetMainWindowStuff(); RefreshThrottleFPS(); extern int movie_readonly; moviereadonly = movie_readonly; // for prefs } } static void UpdateRecordDialogPath(HWND hwndDlg, const char* fname) { char* baseMovieDir = FCEU_GetPath(FCEUMKF_MOVIE); char* fn=0; // display a shortened filename if the file exists in the base movie directory if(!strncmp(fname, baseMovieDir, strlen(baseMovieDir))) { char szDrive[MAX_PATH]={0}; char szDirectory[MAX_PATH]={0}; char szFilename[MAX_PATH]={0}; char szExt[MAX_PATH]={0}; _splitpath(fname, szDrive, szDirectory, szFilename, szExt); fn=(char*)malloc(strlen(szFilename)+strlen(szExt)+1); _makepath(fn, "", "", szFilename, szExt); } else fn=strdup(fname); if(fn) { SetWindowText(GetDlgItem(hwndDlg,200),fn); // FIXME: make utf-8? free(fn); } } static void UpdateRecordDialog(HWND hwndDlg) { int enable=0; char* fn=0; fn=GetRecordPath(hwndDlg); if(fn) { if(access(fn, F_OK) || !access(fn, W_OK)) { LONG lCount = SendDlgItemMessage(hwndDlg, 301, CB_GETCOUNT, 0, 0); LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0); if(lIndex != lCount-1) { enable=1; } } free(fn); } EnableWindow(GetDlgItem(hwndDlg,1),enable ? TRUE : FALSE); } struct CreateMovieParameters { char* szFilename; // on Dialog creation, this is the default filename to display. On return, this is the filename that the user chose. int recordFrom; // 0 = "Power-On", 1 = "Reset", 2 = "Now", 3+ = savestate file in szSavestateFilename char* szSavestateFilename; WCHAR metadata[MOVIE_MAX_METADATA]; }; static BOOL CALLBACK RecordDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { static struct CreateMovieParameters* p = NULL; switch(uMsg) { case WM_INITDIALOG: p = (struct CreateMovieParameters*)lParam; UpdateRecordDialogPath(hwndDlg, p->szFilename); free(p->szFilename); /* Populate the "record from..." dialog */ { char* findGlob=FCEU_MakeFName(FCEUMKF_STATEGLOB, 0, 0); WIN32_FIND_DATA wfd; HANDLE hFind; int i=0; SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Start"); SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Reset"); SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Now"); memset(&wfd, 0, sizeof(wfd)); hFind = FindFirstFile(findGlob, &wfd); if(hFind != INVALID_HANDLE_VALUE) { do { if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) continue; if (strlen(wfd.cFileName) < 4 || !strcmp(wfd.cFileName + (strlen(wfd.cFileName) - 4), ".fcm")) continue; SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)wfd.cFileName); } while(FindNextFile(hFind, &wfd)); FindClose(hFind); } free(findGlob); SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, i++, (LPARAM)"Browse..."); SendDlgItemMessage(hwndDlg, 301, CB_SETCURSEL, 0, 0); // choose "from reset" as a default } UpdateRecordDialog(hwndDlg); return TRUE; case WM_COMMAND: if(HIWORD(wParam) == CBN_SELCHANGE) { LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0); if(lIndex == CB_ERR) { // fix listbox selection SendDlgItemMessage(hwndDlg, 301, CB_SETCURSEL, (WPARAM)0, 0); } UpdateRecordDialog(hwndDlg); return TRUE; } else if(HIWORD(wParam) == CBN_CLOSEUP) { LONG lCount = SendDlgItemMessage(hwndDlg, 301, CB_GETCOUNT, 0, 0); LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0); if (lIndex != CB_ERR && lIndex == lCount-1) { OPENFILENAME ofn; char szChoice[MAX_PATH]={0}; // pop open a file browser to choose the savestate memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndDlg; ofn.lpstrFilter = "FCE Ultra Save State(*.fc?)\0*.fc?\0\0"; ofn.lpstrFile = szChoice; ofn.lpstrDefExt = "fcs"; ofn.nMaxFile = MAX_PATH; if(GetOpenFileName(&ofn)) { SendDlgItemMessage(hwndDlg, 301, CB_INSERTSTRING, lIndex, (LPARAM)szChoice); SendDlgItemMessage(hwndDlg, 301, CB_SETCURSEL, (WPARAM)lIndex, 0); } else UpdateRecordDialog(hwndDlg); } return TRUE; } else if(HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == 200) { UpdateRecordDialog(hwndDlg); } else { switch(LOWORD(wParam)) { case IDOK: { LONG lIndex = SendDlgItemMessage(hwndDlg, 301, CB_GETCURSEL, 0, 0); p->szFilename = GetRecordPath(hwndDlg); GetDlgItemTextW(hwndDlg,300,p->metadata,MOVIE_MAX_METADATA); p->recordFrom = (int)lIndex; if(lIndex>=3) p->szSavestateFilename = GetSavePath(hwndDlg); EndDialog(hwndDlg, 1); } return TRUE; case IDCANCEL: EndDialog(hwndDlg, 0); return TRUE; case 201: { OPENFILENAME ofn; char szChoice[MAX_PATH]={0}; // browse button memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndDlg; ofn.lpstrFilter = "FCE Ultra Movie File(*.fcm)\0*.fcm\0All files(*.*)\0*.*\0\0"; ofn.lpstrFile = szChoice; ofn.lpstrDefExt = "fcm"; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if(GetSaveFileName(&ofn)) UpdateRecordDialogPath(hwndDlg,szChoice); } return TRUE; } } } return FALSE; } void FCEUD_MovieRecordTo(void) { struct CreateMovieParameters p; p.szFilename=FCEUI_MovieGetCurrentName(0); StopSound(); if(DialogBoxParam(fceu_hInstance,"IDD_RECORDINP",hAppWnd,RecordDialogProc,(LPARAM)&p)) { // turn WCHAR into UTF8 char meta[MOVIE_MAX_METADATA<<2]; WideCharToMultiByte(CP_UTF8, 0, p.metadata, -1, meta, sizeof(meta), NULL, NULL); if(p.recordFrom >= 3) { // attempt to load the savestate // FIXME: pop open a messagebox if this fails FCEUI_LoadState(p.szSavestateFilename); { extern int loadStateFailed; if(loadStateFailed) { char str [1024]; sprintf(str, "Failed to load save state \"%s\".\nRecording from current state instead...", p.szSavestateFilename); FCEUD_PrintError(str); } } free(p.szSavestateFilename); } FCEUI_SaveMovie(p.szFilename, (p.recordFrom==0) ? MOVIE_FLAG_FROM_POWERON : ((p.recordFrom==1) ? MOVIE_FLAG_FROM_RESET : 0), meta); } free(p.szFilename); } void FCEUD_AviRecordTo(void) { OPENFILENAME ofn; char szChoice[MAX_PATH]; if(FCEUMOV_IsPlaying()) { extern char curMovieFilename[]; strcpy(szChoice, curMovieFilename); char* dot=strrchr(szChoice,'.'); if(dot) *dot='\0'; strcat(szChoice,".avi"); } else { extern char FileBase[]; sprintf(szChoice, "%s.avi", FileBase); } StopSound(); // avi record file browser memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hAppWnd; ofn.lpstrFilter = "AVI Files (*.avi)\0*.avi\0\0"; ofn.lpstrFile = szChoice; ofn.lpstrDefExt = "avi"; ofn.lpstrTitle = "Save AVI as"; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if(GetSaveFileName(&ofn)) { FCEUI_AviBegin(szChoice); } } void FCEUD_AviStop(void) { FCEUI_AviEnd(); } void FCEUD_CmdOpen(void) { StopSound(); LoadNewGamey(hAppWnd, 0); }