/* 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 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) { 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; 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; #endif case 204:ConfigAddCheat(hWnd);break; //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(); #endif FCEUI_CloseGame(); GI=0; RedoMenuGI(GI); } break; case 110:FCEUD_SaveStateAs();break; case 111:FCEUD_LoadStateFrom();break; case 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(); #ifdef FCEUDEF_DEBUGGER UpdateDebugger(); #endif if(!(eoptions&EO_BGRUN)) while(nofocus) { StopSound(); Sleep(75); BlockingCheck(); } if(userpause) { StopSound(); while(userpause) { 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: 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); }