void FCEUSS_CheckStates(void) { FILE *st=NULL; char *fn; int ssel; for(ssel=0;ssel<10;ssel++) { st=FCEUD_UTF8fopen(fn=FCEU_MakeFName(FCEUMKF_STATE,ssel,0),"rb"); free(fn); if(st) { SaveStateStatus[ssel]=1; fclose(st); } else SaveStateStatus[ssel]=0; } CurrentState=0; StateShow=0; }
void FCEU_LoadGamePalette(void) { uint8 ptmp[192]; FILE *fp; char *fn; ipalette = 0; fn = FCEU_MakeFName(FCEUMKF_PALETTE, 0, 0); if ((fp = FCEUD_UTF8fopen(fn, "rb"))) { int x; fread(ptmp, 1, 192, fp); fclose(fp); for (x = 0; x < 64; x++) { palettei[x].r = ptmp[x + x + x]; palettei[x].g = ptmp[x + x + x + 1]; palettei[x].b = ptmp[x + x + x + 2]; } ipalette = 1; } free(fn); }
//Show the record movie dialog and record a movie. void FCEUD_MovieRecordTo() { if (RA_HardcoreModeIsActive()) { MessageBox(nullptr, ("Hardcore Mode is active. Movie Recording/Playback is disabled."), ("Warning"), MB_OK); return; } if (!GameInfo) return; static struct CreateMovieParameters p; p.szFilename = strdup(FCEU_MakeFName(FCEUMKF_MOVIE,0,0).c_str()); if(p.recordFrom >= 2) p.recordFrom=1; if(DialogBoxParam(fceu_hInstance, "IDD_RECORDINP", hAppWnd, RecordDialogProc, (LPARAM)&p)) { if(p.recordFrom >= 2) { // attempt to load the savestate // FIXME: pop open a messagebox if this fails FCEUI_LoadState(p.szSavestateFilename.c_str()); { extern int loadStateFailed; if(loadStateFailed) { char str [1024]; sprintf(str, "Failed to load save state \"%s\".\nRecording from current state instead...", p.szSavestateFilename.c_str()); FCEUD_PrintError(str); } } } EMOVIE_FLAG flags = MOVIE_FLAG_NONE; if(p.recordFrom == 0) flags = MOVIE_FLAG_FROM_POWERON; FCEUI_SaveMovie(p.szFilename.c_str(), flags, p.authorName); } }
int SaveSnapshot(void) { char *fn=0; int totallines=FSettings.LastSLine-FSettings.FirstSLine+1; int x,u,y; FILE *pp=NULL; uint8 *compmem=NULL; unsigned long compmemsize=totallines*263+12; if(!(compmem=FCEU_malloc(compmemsize))) return 0; for(u=0;u<999;u++) { pp=fopen((fn=FCEU_MakeFName(FCEUMKF_SNAP,u,"png")),"rb"); if(pp==NULL) break; fclose(pp); } if(!(pp=fopen(fn,"wb"))) return 0; { static uint8 header[8]={137,80,78,71,13,10,26,10}; if(fwrite(header,8,1,pp)!=1) goto PNGerr; } { uint8 chunko[13]; chunko[0]=chunko[1]=chunko[3]=0; chunko[2]=0x1; // Width of 256 chunko[4]=chunko[5]=chunko[6]=0; chunko[7]=totallines; // Height chunko[8]=8; // bit depth chunko[9]=3; // Color type; indexed 8-bit chunko[10]=0; // compression: deflate chunko[11]=0; // Basic adapative filter set(though none are used). chunko[12]=0; // No interlace. if(!WritePNGChunk(pp,13,"IHDR",chunko)) goto PNGerr; } { char pdata[256*3]; //void FCEUD_GetPalette(uint8 i,uint8 *r, unsigned char *g, unsigned char *b); for(x=0;x<256;x++) FCEUD_GetPalette(x,(uint8*)(pdata+x*3),(unsigned char*)(pdata+x*3+1),(unsigned char*)(pdata+x*3+2)); // static int WritePNGChunk(FILE *fp, uint32 size, char *type, uint8 *data) if(!WritePNGChunk(pp,256*3,"PLTE",(uint8 *)pdata)) goto PNGerr; } { uint8 *tmp=XBuf+FSettings.FirstSLine*272+8; uint8 *dest,*mal,*mork; /* If memory couldn't be allocated, just use XBuf(screen contents will be corrupted for one frame, though. */ if(!(mal=mork=dest=malloc((totallines<<8)+totallines))) mork=dest=XBuf; for(y=0;y<totallines;y++) { *dest=0; // No filter. dest++; for(x=256;x;x--,tmp++,dest++) *dest=*tmp; tmp+=16; } if(compress(compmem,&compmemsize,mork,(totallines<<8)+totallines)!=Z_OK) { if(mal) free(mal); goto PNGerr; } if(mal) free(mal); if(!WritePNGChunk(pp,compmemsize,"IDAT",compmem)) goto PNGerr; } if(!WritePNGChunk(pp,0,"IEND",0)) goto PNGerr; free(compmem); fclose(pp); #ifdef GP2X sync(); #endif return u+1; PNGerr: if(compmem) free(compmem); if(pp) fclose(pp); return(0); }
FCEUGI *FCEUI_LoadGame(const char *name) { FCEUFILE *fp; char *ipsfn; ResetGameLoaded(); FCEUGameInfo = malloc(sizeof(FCEUGI)); memset(FCEUGameInfo, 0, sizeof(FCEUGI)); FCEUGameInfo->soundchan = 0; FCEUGameInfo->soundrate = 0; FCEUGameInfo->name=0; FCEUGameInfo->type=GIT_CART; FCEUGameInfo->vidsys=GIV_USER; FCEUGameInfo->input[0]=FCEUGameInfo->input[1]=-1; FCEUGameInfo->inputfc=-1; FCEUGameInfo->cspecial=0; FCEU_printf("Loading %s...\n\n",name); GetFileBase(name); ipsfn=FCEU_MakeFName(FCEUMKF_IPS,0,0); fp=FCEU_fopen(name,ipsfn,"rb",0); free(ipsfn); if(!fp) { FCEU_PrintError("Error opening \"%s\"!",name); return 0; } if(iNESLoad(name,fp)) goto endlseq; if(NSFLoad(fp)) goto endlseq; if(UNIFLoad(name,fp)) goto endlseq; if(FDSLoad(name,fp)) goto endlseq; FCEU_PrintError("An error occurred while loading the file."); FCEU_fclose(fp); return 0; endlseq: FCEU_fclose(fp); FCEU_ResetVidSys(); if(FCEUGameInfo->type!=GIT_NSF) if(FSettings.GameGenie) OpenGenie(); PowerNES(); FCEUSS_CheckStates(); FCEUMOV_CheckMovies(); if(FCEUGameInfo->type!=GIT_NSF) { FCEU_LoadGamePalette(); FCEU_LoadGameCheats(0); } FCEU_ResetPalette(); FCEU_ResetMessages(); // Save state, status messages, etc. return(FCEUGameInfo); }
void NetplayUpdate(uint8 *joyp) { static uint8 buf[5]; /* 4 play states, + command/extra byte */ static uint8 joypb[4]; memcpy(joypb,joyp,4); /* This shouldn't happen, but just in case. 0xFF is used as a command escape elsewhere. */ if(joypb[0] == 0xFF) joypb[0] = 0xF; #ifdef NETWORK if(!netdcount) if(!FCEUD_SendData(joypb,numlocal)) { NetError(); return; } if(!netdcount) do { if(!FCEUD_RecvData(buf,5)) { NetError(); return; } switch(buf[4]) { default: FCEU_DoSimpleCommand(buf[4]);break; case FCEUNPCMD_TEXT: { uint8 *tbuf; uint32 len = FCEU_de32lsb(buf); if(len > 100000) // Insanity check! { NetError(); return; } tbuf = malloc(len + 1); tbuf[len] = 0; if(!FCEUD_RecvData(tbuf, len)) { NetError(); free(tbuf); return; } FCEUD_NetplayText(tbuf); free(tbuf); } break; case FCEUNPCMD_SAVESTATE: { char *fn; FILE *fp; /* Send the cheats first, then the save state, since there might be a frame or two in between the two sendfile commands on the server side. */ fn = FCEU_MakeFName(FCEUMKF_CHEAT,0,0); //if(! FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn); // { // free(fn); // return; // } free(fn); if(!FCEUnetplay) return; fn = FCEU_MakeFName(FCEUMKF_NPTEMP,0,0); fp = fopen(fn, "wb"); if(FCEUSS_SaveFP(fp)) { fclose(fp); if(!FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn)) { unlink(fn); free(fn); return; } unlink(fn); free(fn); } else { fclose(fp); FCEUD_PrintError("File error. (K)ill, (M)aim, (D)estroy? Now!"); unlink(fn); free(fn); return; } } break; case FCEUNPCMD_LOADCHEATS: { FILE *fp = FetchFile(FCEU_de32lsb(buf)); if(!fp) return; FCEU_FlushGameCheats(0,1); FCEU_LoadGameCheats(fp); } break; case FCEUNPCMD_LOADSTATE: { FILE *fp = FetchFile(FCEU_de32lsb(buf)); if(!fp) return; if(FCEUSS_LoadFP(fp)) { fclose(fp); FCEU_DispMessage("Remote state loaded."); } else FCEUD_PrintError("File error. (K)ill, (M)aim, (D)estroy?"); } break; } } while(buf[4]); #endif netdcount=(netdcount+1)%netdivisor; memcpy(netjoy,buf,4); *(uint32 *)joyp=*(uint32 *)netjoy; }
void FCEUI_SaveMovie(char *fname, uint8 flags, const char* metadata) { FILE *fp; char *fn; int poweron=0; uint8 padding[4] = {0,0,0,0}; int n_padding; FCEUI_StopMovie(); char origname[512]; if(fname) { fp = FCEUD_UTF8fopen(fname, "wb"); strcpy(origname,fname); } else { fp=FCEUD_UTF8fopen(fn=FCEU_MakeFName(FCEUMKF_MOVIE,CurrentMovie,0),"wb"); strcpy(origname,fn); free(fn); } if(!fp) return; // don't need the movieSyncHackOn sync hack for newly recorded movies flags |= MOVIE_FLAG_NOSYNCHACK; resetDMCacc=movieSyncHackOn=0; // add PAL flag if(FCEUI_GetCurrentVidSystem(0,0)) flags |= MOVIE_FLAG_PAL; if(flags & MOVIE_FLAG_FROM_POWERON) { poweron=1; flags &= ~MOVIE_FLAG_FROM_POWERON; flags |= MOVIE_FLAG_FROM_RESET; } // write header write32le(MOVIE_MAGIC, fp); write32le(MOVIE_VERSION, fp); fputc(flags, fp); fputc(0, fp); // reserved fputc(0, fp); // reserved fputc(0, fp); // reserved write32le(0, fp); // leave room for length frames write32le(0, fp); // leave room for rerecord count write32le(0, fp); // leave room for movie data size write32le(0, fp); // leave room for savestate_offset write32le(0, fp); // leave room for offset_to_controller_data fwrite(FCEUGameInfo->MD5, 1, 16, fp); // write ROM checksum write32le(FCEU_VERSION_NUMERIC, fp); // write emu version used fputs(FileBase, fp); // write ROM name used fputc(0, fp); if(metadata) { if(strlen(metadata) < MOVIE_MAX_METADATA) fputs(metadata, fp); else fwrite(metadata, 1, MOVIE_MAX_METADATA-1, fp); } fputc(0, fp); // add padding n_padding = (4 - (ftell(fp) & 0x3)) & 0x3; fwrite(padding, 1, n_padding, fp); if(flags & MOVIE_FLAG_FROM_RESET) { if(poweron) { // make a for-movie-recording power-on clear the game's save data, too // (note: FCEU makes a save state immediately after this and that loads that on movie playback) extern char lastLoadedGameName [2048]; extern int disableBatteryLoading, suppressAddPowerCommand; suppressAddPowerCommand=1; disableBatteryLoading=1; suppressMovieStop=1; { // NOTE: this will NOT write an FCEUNPCMD_POWER into the movie file FCEUGI * gi = FCEUI_LoadGame(lastLoadedGameName); if(!gi) PowerNES(); // and neither will this, if it can even happen } suppressMovieStop=0; disableBatteryLoading=0; suppressAddPowerCommand=0; } } savestate_offset = ftell(fp); FCEUSS_SaveFP(fp); fseek(fp, 0, SEEK_END); ResetInputTypes(); // add padding n_padding = (4 - (ftell(fp) & 0x3)) & 0x3; fwrite(padding, 1, n_padding, fp); firstframeoffset = ftell(fp); // finish header fseek(fp, 24, SEEK_SET); // offset_to_savestate offset write32le(savestate_offset, fp); write32le(firstframeoffset, fp); fseek(fp, firstframeoffset, SEEK_SET); // set recording flag current=CurrentMovie; movie_readonly = 0; frameptr = 0; framecount = 0; rerecord_count = 0; slots[current] = fp; memset(joop,0,sizeof(joop)); current++; framets=0; nextd = -1; // trigger a reset if(flags & MOVIE_FLAG_FROM_RESET) { if(poweron) { PowerNES(); // NOTE: this will write an FCEUNPCMD_POWER into the movie file } else ResetNES(); // NOTE: this will write an FCEUNPCMD_RESET into the movie file } if(!fname) FCEUI_SelectMovie(CurrentMovie,1); /* Quick hack to display status. */ else FCEU_DispMessage("Movie recording started."); strcpy(curMovieFilename, origname); }
// PlayMovie / MoviePlay function void FCEUI_LoadMovie(char *fname, int _read_only) { char buffer [512]; fname = (char*)convertToFCM(fname,buffer); FILE *fp; char *fn = NULL; FCEUI_StopMovie(); #if 0 if(!fname) fname = fn = FCEU_MakeFName(FCEUMKF_MOVIE,CurrentMovie,0); #endif #if 0 char origname[512]; strcpy(origname,fname); #endif // check movie_readonly movie_readonly = _read_only; if(access(fname, W_OK)) movie_readonly = 2; fp = fopen(fname, (movie_readonly>=2) ? "rb" : "r+b"); if(fn) { free(fn); fname = NULL; } if(!fp) return; // read header { uint32 magic; uint32 version; uint8 flags[4]; read32le(&magic, fp); if(magic != MOVIE_MAGIC) { fclose(fp); return; } //DEBUG_COMPARE_RAM(__LINE__); read32le(&version, fp); if(version == 1) { // attempt to load previous version's format fclose(fp); printf("movie: trying movie v1\n"); FCEUI_LoadMovie_v1(fname, _read_only); return; } else if(version == MOVIE_VERSION) {} else { // unsupported version printf("movie: unsupported version\n"); fclose(fp); return; } fread(flags, 1, 4, fp); read32le(&framecount, fp); read32le(&rerecord_count, fp); read32le(&moviedatasize, fp); read32le(&savestate_offset, fp); read32le(&firstframeoffset, fp); if(fseek(fp, savestate_offset, SEEK_SET)) { fclose(fp); return; } // FCEU_PrintError("flags[0] & MOVIE_FLAG_NOSYNCHACK=%d",flags[0] & MOVIE_FLAG_NOSYNCHACK); if(flags[0] & MOVIE_FLAG_NOSYNCHACK) movieSyncHackOn=0; else movieSyncHackOn=1; } // fully reload the game to reinitialize everything before playing any movie // to try fixing nondeterministic playback of some games #if 0 // do we need this? { extern char lastLoadedGameName [2048]; #if 0 // TODO? extern int disableBatteryLoading, suppressAddPowerCommand; suppressAddPowerCommand=1; suppressMovieStop=1; #endif { FCEUGI * gi = FCEUI_LoadGame(lastLoadedGameName); if(!gi) PowerNES(); } #if 0 // TODO? suppressMovieStop=0; suppressAddPowerCommand=0; #endif } #endif // Loading new savestates doesn't work and even breaks FDS //if(!FCEUSS_LoadFP(fp,1)) return; ResetInputTypes(); fseek(fp, firstframeoffset, SEEK_SET); moviedata = (uint8*)realloc(moviedata, moviedatasize); fread(moviedata, 1, moviedatasize, fp); framecount = 0; // movies start at frame 0! frameptr = 0; current = CurrentMovie; slots[current] = fp; memset(joop,0,sizeof(joop)); current = -1 - current; framets=0; nextts=0; nextd = -1; MovieStatus[CurrentMovie] = 1; #if 0 if(!fname) FCEUI_SelectMovie(CurrentMovie,1); /* Quick hack to display status. */ else #endif FCEU_DispMessage("Movie playback started."); #if 0 strcpy(curMovieFilename, origname); #else strcpy(curMovieFilename, fname); #endif }
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); p->szFilename = ""; if (strlen(taseditorConfig.lastAuthorName)) { // convert UTF8 char* string to Unicode wstring wchar_t savedAuthorName[AUTHOR_NAME_MAX_LEN] = {0}; MultiByteToWideChar(CP_UTF8, 0, taseditorConfig.lastAuthorName, -1, savedAuthorName, AUTHOR_NAME_MAX_LEN); p->authorName = savedAuthorName; } else { p->authorName = L""; } SendMessage(GetDlgItem(hwndDlg, IDC_EDIT_AUTHOR), CCM_SETUNICODEFORMAT, TRUE, 0); SetDlgItemTextW(hwndDlg, IDC_EDIT_AUTHOR, (LPCWSTR)(p->authorName.c_str())); // Populate the "record from..." dialog { char* findGlob=strdup(FCEU_MakeFName(FCEUMKF_STATEGLOB, 0, 0).c_str()); WIN32_FIND_DATA wfd; HANDLE hFind; int i=0; SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_INSERTSTRING, i++, (LPARAM)"Start"); SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, 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), ".fm2")) continue; SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_INSERTSTRING, i++, (LPARAM)wfd.cFileName); } while(FindNextFile(hFind, &wfd)); FindClose(hFind); } free(findGlob); SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_INSERTSTRING, i++, (LPARAM)"Browse..."); SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_SETCURSEL, p->recordFrom, 0); } UpdateRecordDialog(hwndDlg); return TRUE; case WM_COMMAND: if(HIWORD(wParam) == CBN_SELCHANGE) { LONG lIndex = SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_GETCURSEL, 0, 0); if(lIndex == CB_ERR) { // fix listbox selection SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_SETCURSEL, (WPARAM)0, 0); } UpdateRecordDialog(hwndDlg); return TRUE; } else if(HIWORD(wParam) == CBN_CLOSEUP) { LONG lCount = SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_GETCOUNT, 0, 0); LONG lIndex = SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, 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 = "FCEU Save State (*.fc?)\0*.fc?\0\0"; ofn.lpstrFile = szChoice; ofn.lpstrDefExt = "fcs"; ofn.nMaxFile = MAX_PATH; if(GetOpenFileName(&ofn)) { SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_INSERTSTRING, lIndex, (LPARAM)szChoice); SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_SETCURSEL, (WPARAM)lIndex, 0); } else UpdateRecordDialog(hwndDlg); } return TRUE; } else if(HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) == IDC_EDIT_FILENAME) { UpdateRecordDialog(hwndDlg); } else { switch(LOWORD(wParam)) { case IDOK: { LONG lIndex = SendDlgItemMessage(hwndDlg, IDC_COMBO_RECORDFROM, CB_GETCURSEL, 0, 0); p->szFilename = GetRecordPath(hwndDlg); p->recordFrom = (int)lIndex; // save author name in params and in config (converted to multibyte char*) wchar_t authorName[AUTHOR_NAME_MAX_LEN] = {0}; GetDlgItemTextW(hwndDlg, IDC_EDIT_AUTHOR, (LPWSTR)authorName, AUTHOR_NAME_MAX_LEN); p->authorName = authorName; if (p->authorName == L"") taseditorConfig.lastAuthorName[0] = 0; else // convert Unicode wstring to UTF8 char* string WideCharToMultiByte(CP_UTF8, 0, (p->authorName).c_str(), -1, taseditorConfig.lastAuthorName, AUTHOR_NAME_MAX_LEN, 0, 0); if (lIndex >= 2) p->szSavestateFilename = GetSavePath(hwndDlg); EndDialog(hwndDlg, 1); } return TRUE; case IDCANCEL: EndDialog(hwndDlg, 0); return TRUE; case IDC_BUTTON_BROWSEFILE: { OPENFILENAME ofn; char szChoice[MAX_PATH]={0}; // browse button memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwndDlg; ofn.lpstrFilter = "FCEUX Movie File (*.fm2)\0*.fm2\0All Files (*.*)\0*.*\0\0"; ofn.lpstrFile = szChoice; ofn.lpstrDefExt = "fm2"; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT; if(GetSaveFileName(&ofn)) { UpdateRecordDialogPath(hwndDlg,szChoice); } } return TRUE; } } } return FALSE; }
BOOL CALLBACK ReplayDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: { SendDlgItemMessage(hwndDlg, IDC_CHECK_READONLY, BM_SETCHECK, replayReadOnlySetting?BST_CHECKED:BST_UNCHECKED, 0); SendDlgItemMessage(hwndDlg, IDC_CHECK_STOPMOVIE,BM_SETCHECK, BST_UNCHECKED, 0); #define NUM_OF_MOVIEGLOB_PATHS 1 char* findGlob[NUM_OF_MOVIEGLOB_PATHS] = {strdup(FCEU_MakeFName(FCEUMKF_MOVIEGLOB, 0, 0).c_str())}; int items=0; for(int j = 0;j < NUM_OF_MOVIEGLOB_PATHS; j++) { char* temp=0; do { temp=strchr(findGlob[j],'/'); if(temp) *temp = '\\'; } while(temp); // disabled because... apparently something is case sensitive?? // for(i=1;i<strlen(findGlob[j]);i++) // findGlob[j][i] = tolower(findGlob[j][i]); } for(int j = 0;j < NUM_OF_MOVIEGLOB_PATHS; j++) { // if the two directories are the same, only look through one of them to avoid adding everything twice if(j==1 && !strnicmp(findGlob[0],findGlob[1],MAX(strlen(findGlob[0]),strlen(findGlob[1]))-6)) continue; char globBase[512]; strcpy(globBase,findGlob[j]); globBase[strlen(globBase)-5]='\0'; //char szFindPath[512]; //mbg merge 7/17/06 removed WIN32_FIND_DATA wfd; HANDLE hFind; memset(&wfd, 0, sizeof(wfd)); hFind = FindFirstFile(findGlob[j], &wfd); if(hFind != INVALID_HANDLE_VALUE) { do { if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue; //TODO - a big copy/pasted block below. factor out extension extractor or use another one // filter out everything that's not an extension we like (*.fm2 and *.fm3) // (because FindFirstFile is too dumb to do that) { std::string ext = getExtension(wfd.cFileName); if(ext != "fm2") if(ext != "fm3") if(ext != "zip") if(ext != "rar") if(ext != "7z") continue; } char filename [512]; sprintf(filename, "%s%s", globBase, wfd.cFileName); //replay system requires this to stay put. SetCurrentDirectory(BaseDirectory.c_str()); ArchiveScanRecord asr = FCEUD_ScanArchive(filename); if(!asr.isArchive()) { FCEUFILE* fp = FCEU_fopen(filename,0,"rb",0); if(fp) { //fp->stream = fp->stream->memwrap(); - no need to load whole movie to memory! We only need to read movie header! HandleScan(hwndDlg, fp, items); delete fp; } } else { asr.files.FilterByExtension(fm2ext); for(uint32 i=0;i<asr.files.size();i++) { FCEUFILE* fp = FCEU_fopen(filename,0,"rb",0,asr.files[i].index); if(fp) { HandleScan(hwndDlg,fp, items); delete fp; } } } } while(FindNextFile(hFind, &wfd)); FindClose(hFind); } } for(int j = 0; j < NUM_OF_MOVIEGLOB_PATHS; j++) free(findGlob[j]); if(items>0) SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_SETCURSEL, items-1, 0); SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_INSERTSTRING, items++, (LPARAM)"Browse..."); UpdateReplayDialog(hwndDlg); } SetFocus(GetDlgItem(hwndDlg, IDC_COMBO_FILENAME)); return FALSE; case WM_COMMAND: if (HIWORD(wParam) == EN_CHANGE) { if (LOWORD(wParam) == IDC_EDIT_STOPFRAME) // Check if Stop movie at value has changed { if (stopframeWasEditedByUser) { HWND hwnd1 = GetDlgItem(hwndDlg,IDC_CHECK_STOPMOVIE); Button_SetCheck(hwnd1,BST_CHECKED); stopframeWasEditedByUser = true; } else stopframeWasEditedByUser = true; } } if (HIWORD(wParam) == CBN_SELCHANGE) { UpdateReplayDialog(hwndDlg); } else if(HIWORD(wParam) == CBN_CLOSEUP) { LONG lCount = SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_GETCOUNT, 0, 0); LONG lIndex = SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, 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 IDC_BUTTON_METADATA: DialogBoxParam(fceu_hInstance, "IDD_REPLAY_METADATA", hwndDlg, ReplayMetadataDialogProc, (LPARAM)0); break; case IDOK: { LONG lCount = SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_GETCOUNT, 0, 0); LONG lIndex = SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_GETCURSEL, 0, 0); if(lIndex != CB_ERR) { if(lIndex == lCount-1) { // pop open a file browser... char *pn=strdup(FCEU_GetPath(FCEUMKF_MOVIE).c_str()); 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 = "FCEUX Movie Files (*.fm2), TAS Editor Projects (*.fm3)\0*.fm2;*.fm3\0FCEUX Movie Files (*.fm2)\0*.fm2\0Archive Files (*.zip,*.rar,*.7z)\0*.zip;*.rar;*.7z\0All Files (*.*)\0*.*\0\0"; ofn.lpstrFile = szFile; ofn.nMaxFile = sizeof(szFile); ofn.lpstrInitialDir = pn; ofn.Flags = OFN_NOCHANGEDIR | OFN_HIDEREADONLY; ofn.lpstrDefExt = "fm2"; ofn.lpstrTitle = "Play Movie from File"; if(GetOpenFileName(&ofn)) { char relative[MAX_PATH*2]; AbsoluteToRelative(relative, szFile, BaseDirectory.c_str()); //replay system requires this to stay put. SetCurrentDirectory(BaseDirectory.c_str()); ArchiveScanRecord asr = FCEUD_ScanArchive(relative); FCEUFILE* fp = FCEU_fopen(relative,0,"rb",0,-1,fm2ext); if(!fp) goto abort; strcpy(relative,fp->fullFilename.c_str()); delete fp; LONG lOtherIndex = SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_FINDSTRING, (WPARAM)-1, (LPARAM)relative); if(lOtherIndex != CB_ERR) { // select already existing string SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_SETCURSEL, lOtherIndex, 0); UpdateReplayDialog(hwndDlg); } else { SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_INSERTSTRING, lIndex, (LPARAM)relative); SendDlgItemMessage(hwndDlg, IDC_COMBO_FILENAME, CB_SETCURSEL, lIndex, 0); //UpdateReplayDialog(hwndDlg); - this call would be redundant, because the update is always triggered by CBN_SELCHANGE message anyway } // restore focus to the dialog SetFocus(GetDlgItem(hwndDlg, IDC_COMBO_FILENAME)); } abort: 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 replayReadOnlySetting = (SendDlgItemMessage(hwndDlg, IDC_CHECK_READONLY, BM_GETCHECK, 0, 0) == BST_CHECKED); char offset1Str[32]={0}; SendDlgItemMessage(hwndDlg, IDC_EDIT_STOPFRAME, WM_GETTEXT, (WPARAM)32, (LPARAM)offset1Str); replayStopFrameSetting = (SendDlgItemMessage(hwndDlg, IDC_CHECK_STOPMOVIE, BM_GETCHECK,0,0) == BST_CHECKED)? strtol(offset1Str,0,10):0; EndDialog(hwndDlg, (INT_PTR)fn); } } } return TRUE; case IDCANCEL: EndDialog(hwndDlg, 0); return TRUE; } } return FALSE; case WM_CTLCOLORSTATIC: if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_LABEL_CURRCHECKSUM)) { // 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, IDC_LABEL_ROMCHECKSUM, szMd5Text, 35); if (!strlen(szMd5Text) || !strcmp(szMd5Text, "unknown") || !strcmp(szMd5Text, "00000000000000000000000000000000") || !strcmp(szMd5Text, md5_asciistr(GameInfo->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((HDC)wParam,TRANSPARENT); return (BOOL)GetSysColorBrush(COLOR_BTNFACE); } else if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_LABEL_NEWPPUUSED)) { HDC hdcStatic = (HDC)wParam; char szMd5Text[35]; GetDlgItemText(hwndDlg, IDC_LABEL_NEWPPUUSED, szMd5Text, 35); bool want_newppu = (strcmp(szMd5Text, "Off") != 0); extern int newppu; if ((want_newppu && newppu) || (!want_newppu && !newppu)) SetTextColor(hdcStatic, RGB(0,0,0)); // use black color for a match else SetTextColor(hdcStatic, RGB(255,0,0)); // use red for a mismatch SetBkMode((HDC)wParam,TRANSPARENT); return (BOOL)GetSysColorBrush(COLOR_BTNFACE); } else { return FALSE; } } return FALSE; };