From a30cf51c7d79b6e784b58ee924b2a779bea0c26b Mon Sep 17 00:00:00 2001 From: zeromus Date: Mon, 4 May 2009 23:36:46 +0000 Subject: [PATCH] import latest from rerecording branch --- desmume/dsm.txt | 63 ++++++++++++++++++++++++++++++ desmume/src/NDSSystem.cpp | 4 +- desmume/src/gfx3d.cpp | 33 +++++++++++----- desmume/src/movie.cpp | 8 +++- desmume/src/rasterize.cpp | 24 +++++++----- desmume/src/rtc.cpp | 37 ++++++++---------- desmume/src/saves.cpp | 5 ++- desmume/src/texcache.cpp | 11 ++++-- desmume/src/texcache.h | 4 +- desmume/src/windows/main.cpp | 2 + desmume/src/windows/ram_search.cpp | 51 ++++++++++++++---------- 11 files changed, 173 insertions(+), 69 deletions(-) create mode 100644 desmume/dsm.txt diff --git a/desmume/dsm.txt b/desmume/dsm.txt new file mode 100644 index 000000000..b7ac03918 --- /dev/null +++ b/desmume/dsm.txt @@ -0,0 +1,63 @@ +DSM is ascii plain text. It is derived from the FCEUX FM2 format. +It consists of several key-value pairs followed by an inputlog section. +The inputlog section can be identified by its starting with a | (pipe). +The inputlog section terminates at eof. +Newlines may be \r\n or \n + +Key-value pairs consist of a key identifier, followed by a space separator, followed by the value text. +Value text is always terminated by a newline, which the value text will not include. +The value text is parsed differently depending on the type of the key. +The key-value pairs may be in any order, except that the first key must be version. + +Integer keys (also used for booleans, with a 1 or 0) will have a value that is a simple integer not to exceed 32bits + - version (required) - the version of the movie file format; for now it is always 3 + - emuVersion (required) - the version of the emulator used to produce the movie + - rerecordCount (optional) - the rerecord count + +String keys have values that consist of the remainder of the key-value pair line. As a consequence, string values cannot contain newlines. + - romFilename (required) - the name of the file used to record the movie + - comment (optional) - simply a memo. + by convention, the first token in the comment value is the subject of the comment. + by convention, subsequent comments with the same subject will have their ordering preserved and may be used to approximate multiline comments. + by convention, the author of the movie should be stored in comment(s) with a subject of: author + +Hex string keys (used for binary blobs) will have a value that is like 0x0123456789ABCDEF... + - romChecksum (required) - this is currently unused. + +GUID keys have a value which is in the standard guid format: 452DE2C3-EF43-2FA9-77AC-0677FC51543B + - guid (required) a unique identifier for a movie, generated when the movie is created, which is used when loading a savestate to make sure it belongs to the current movie. + +The inputlog section consists of lines beginning and ending with a | (pipe). +The fields are as follows, except as noted in note C. +|c|.............XXX YYY Z| + +'R','L','D','U','T','S','B','A','Y','X','W','E','G' + +field c is a variable length decimal integer which is a bitfield corresponding to miscellaneous input states which are valid at the start of the frame. +There are currently no valid values and so this should always be 0. + +the format of the main section is as follows: + + the field begins with 13 characters which constitute a bitfield. + any character other than ' ' or '.' means that the button was pressed. + by convention, the following mnemonics will be used in a column to remind us of which button corresponds to which column: + RLDUTSBAYXWEG (Right,Left,Down,Up,sTart,Select,B,A,Y,X,lshoulder,rshoulder,debuG) + This ordering is based on FCEUX to a certain extent, and arbitrary after that. + W and E were chosen for shoulders to suggest West and East for Left and Right. + While the emulator supports a 'lid' button, and to some extent a 'blow' button, these are not supported in the movies. + + XXX: %03d, the x position of the stylus (0,0 topleft, 255,191 bottomright) + YYY: %03d, the y position of the stylus + Z: %1d, 1 if the stylus is pressed pressed; 0 if not + +Additional fields after this main section may be added later without breaking the file format. + +* Notes * +A. There is no key-value pair that indicates the length of the movie. This must be read by scanning the inputlog and counting the number of lines. + +B. All movies start from power-on. + +C. The emulator uses these framerate constants + arm7_cycles_per_frame = 560190 + frames_per_second = 59.8261 + diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index 179550ecb..564b140e6 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -881,6 +881,7 @@ void NDS_FreeROM(void) MMU.bupmem.fp = NULL; } +bool _HACK_DONT_STOPMOVIE = false; void NDS_Reset(BOOL resetBySavestate) { unsigned int i; @@ -889,7 +890,8 @@ void NDS_Reset(BOOL resetBySavestate) FILE* inf = 0; NDS_header * header = NDS_getROMHeader(); - FCEUI_StopMovie(); + if(!_HACK_DONT_STOPMOVIE) + FCEUI_StopMovie(); if (!header) return ; diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index c0f42dce6..c286909f4 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -207,10 +207,10 @@ static CACHE_ALIGN float cacheHalfVector[4][4]; //-------------poly and vertex lists and such things -POLYLIST polylists[2]; -POLYLIST* polylist = &polylists[0]; -VERTLIST vertlists[2]; -VERTLIST* vertlist = &vertlists[0]; +POLYLIST* polylists = NULL; +POLYLIST* polylist = NULL; +VERTLIST* vertlists = NULL; +VERTLIST* vertlist = NULL; int listTwiddle = 1; int triStripToggle; @@ -278,6 +278,8 @@ static void makeTables() { void gfx3d_init() { + if(polylists == NULL) { polylists = new POLYLIST[2]; polylist = &polylists[0]; } + if(vertlists == NULL) { vertlists = new VERTLIST[2]; vertlist = &vertlists[0]; } makeTables(); gfx3d_reset(); } @@ -2328,6 +2330,9 @@ SFORMAT SF_GFX3D[]={ //-------------savestate void gfx3d_savestate(std::ostream* os) { + //version + write32le(1,os); + //dump the render lists OSWRITE(vertlist->count); for(int i=0;icount;i++) @@ -2339,6 +2344,11 @@ void gfx3d_savestate(std::ostream* os) bool gfx3d_loadstate(std::istream* is, int size) { + int version; + if(read32le(&version,is) != 1) return false; + if(size==8) version = 0; + + gfx3d_glPolygonAttrib_cache(); gfx3d_glTexImage_cache(); gfx3d_Control_cache(); @@ -2352,12 +2362,15 @@ bool gfx3d_loadstate(std::istream* is, int size) polylist = &polylists[listTwiddle]; vertlist = &vertlists[listTwiddle]; - OSREAD(vertlist->count); - for(int i=0;icount;i++) - vertlist->list[i].load(is); - OSREAD(polylist->count); - for(int i=0;icount;i++) - polylist->list[i].load(is); + if(version==1) + { + OSREAD(vertlist->count); + for(int i=0;icount;i++) + vertlist->list[i].load(is); + OSREAD(polylist->count); + for(int i=0;icount;i++) + polylist->list[i].load(is); + } gfx3d.polylist = &polylists[listTwiddle^1]; gfx3d.vertlist = &vertlists[listTwiddle^1]; diff --git a/desmume/src/movie.cpp b/desmume/src/movie.cpp index e4dd0ab88..5e2bd9c80 100644 --- a/desmume/src/movie.cpp +++ b/desmume/src/movie.cpp @@ -477,8 +477,12 @@ static void openRecordingMovie(const char* fname) if(author != L"") currMovieData.comments.push_back(L"author " + author); //currMovieData.romChecksum = GameInfo->MD5; //currMovieData.romFilename = FileBase; - + + extern bool _HACK_DONT_STOPMOVIE; + _HACK_DONT_STOPMOVIE = true; NDS_Reset(); + _HACK_DONT_STOPMOVIE = false; + //todo ? //poweron(true); //else @@ -755,6 +759,7 @@ bool mov_loadstate(std::istream* is, int size) currMovieData.rerecordCount = currRerecordCount; openRecordingMovie(curMovieFilename); + //printf("DUMPING MOVIE: %d FRAMES\n",currMovieData.records.size()); currMovieData.dump(osRecordingMovie, false); movieMode = MOVIEMODE_RECORD; } @@ -844,6 +849,7 @@ void LoadFM2_binarychunk(MovieData& movieData, std::istream* fp, int size) int todo = std::min(size, flen); int numRecords = todo/recordsize; + //printf("LOADED MOVIE: %d records; currFrameCounter: %d\n",numRecords,currFrameCounter); movieData.records.resize(numRecords); for(int i=0;i static T interpolate(const float ratio, const T& x0, const T& x1) { diff --git a/desmume/src/rtc.cpp b/desmume/src/rtc.cpp index ddac69bcb..43c7f977c 100644 --- a/desmume/src/rtc.cpp +++ b/desmume/src/rtc.cpp @@ -79,33 +79,30 @@ struct movietime { struct movietime movie; -int oldframeCounter; -u64 totalcycles=2904024960000ULL;//noon -int totalseconds; bool moviemode=false; - -void InitMovieTime(void) { - - movie.year=9; - movie.month=1; - movie.monthday=1; - movie.weekday=4; - oldframeCounter=0; - -} +void InitMovieTime(void) +{ + movie.year=9; + movie.month=1; + movie.monthday=1; + movie.weekday=4; +} #ifdef WIN32 static void MovieTime(void) { - if(currFrameCounter > oldframeCounter) { - int difference; - difference=currFrameCounter-oldframeCounter; - oldframeCounter=currFrameCounter; - totalcycles+=((560190<<1)*difference); - } + //now, you might think it is silly to go through all these conniptions + //when we could just assume that there are 60fps and base the seconds on frameCounter/60 + //but, we were imagining that one day we might need more precision - totalseconds=totalcycles / 67222800; //one second + const u32 arm9rate_unitsperframe = 560190<<1; + const u32 arm9rate_unitspersecond = (u32)(arm9rate_unitsperframe * 59.8261); + const u64 noon = (u64)arm9rate_unitspersecond * 60 * 60 * 12; + + u64 frameCycles = (u64)arm9rate_unitsperframe * currFrameCounter; + u64 totalcycles = frameCycles + noon; + u32 totalseconds=totalcycles/arm9rate_unitspersecond; movie.sec=totalseconds % 60; movie.minute=totalseconds/60; diff --git a/desmume/src/saves.cpp b/desmume/src/saves.cpp index 9b6f5fff0..32d1a0ab5 100644 --- a/desmume/src/saves.cpp +++ b/desmume/src/saves.cpp @@ -862,7 +862,10 @@ static bool savestate_load(std::istream* is) //while the series of resets below should work, //we are testing the robustness of the savestate system with this full reset. //the full reset wipes more things, so we can make sure that they are being restored correctly - NDS_Reset(TRUE); + extern bool _HACK_DONT_STOPMOVIE; + _HACK_DONT_STOPMOVIE = true; + NDS_Reset(); + _HACK_DONT_STOPMOVIE = false; //reset some options to their old defaults which werent saved nds.debugConsole = FALSE; diff --git a/desmume/src/texcache.cpp b/desmume/src/texcache.cpp index 0adfac384..0accda6a5 100644 --- a/desmume/src/texcache.cpp +++ b/desmume/src/texcache.cpp @@ -132,10 +132,10 @@ static MemSpan MemSpan_TexPalette(u32 ofs, u32 len) return ret; } -TextureCache texcache[MAX_TEXTURE+1]; -u32 texcache_start; -u32 texcache_stop; -u8 TexCache_texMAP[1024*2048*4]; +TextureCache *texcache; +u32 texcache_start; +u32 texcache_stop; +u8 *TexCache_texMAP = NULL; #if defined (DEBUG_DUMP_TEXTURE) && defined (WIN32) @@ -575,6 +575,9 @@ REJECT: void TexCache_Reset() { + if(TexCache_texMAP == NULL) TexCache_texMAP = new u8[1024*2048*4]; + if(texcache == NULL) texcache = new TextureCache[MAX_TEXTURE+1]; + memset(texcache,0,sizeof(texcache)); texcache_start=0; diff --git a/desmume/src/texcache.h b/desmume/src/texcache.h index c350a2fe4..3d6671871 100644 --- a/desmume/src/texcache.h +++ b/desmume/src/texcache.h @@ -36,7 +36,7 @@ struct ALIGN(8) TextureCache }; -extern TextureCache texcache[MAX_TEXTURE+1]; +extern TextureCache *texcache; extern void (*TexCache_BindTexture)(u32 texnum); extern void (*TexCache_BindTextureData)(u32 texnum, u8* data); @@ -48,7 +48,7 @@ void TexCache_SetTexture(u32 format, u32 texpal); void TexCache_Invalidate(); -extern u8 TexCache_texMAP[1024*2048*4]; +extern u8 *TexCache_texMAP; TextureCache* TexCache_Curr(); #endif diff --git a/desmume/src/windows/main.cpp b/desmume/src/windows/main.cpp index 5b6c73cb1..21f7ecb54 100644 --- a/desmume/src/windows/main.cpp +++ b/desmume/src/windows/main.cpp @@ -114,6 +114,7 @@ void DRV_AviVideoUpdate(const u16* buffer); DWORD hKeyInputTimer; extern LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +void InitRamSearch(); CRITICAL_SECTION win_sync; @@ -3139,6 +3140,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM case ID_RAM_SEARCH: if(!RamSearchHWnd) { + InitRamSearch(); RamSearchHWnd = CreateDialog(hAppInst, MAKEINTRESOURCE(IDD_RAMSEARCH), hwnd, (DLGPROC) RamSearchProc); } else diff --git a/desmume/src/windows/ram_search.cpp b/desmume/src/windows/ram_search.cpp index ad40237c6..0ed8f6f2f 100644 --- a/desmume/src/windows/ram_search.cpp +++ b/desmume/src/windows/ram_search.cpp @@ -63,10 +63,12 @@ struct MemoryRegion unsigned int itemIndex; // index into listbox items, valid when s_itemIndicesInvalid is false }; -static unsigned char s_prevValues [MAX_RAM_SIZE+4] = {0}; // values at last search or reset -static unsigned char s_curValues [MAX_RAM_SIZE+4] = {0}; // values at last frame update -static unsigned short s_numChanges [MAX_RAM_SIZE+4] = {0}; // number of changes of the item starting at this virtual index address -static MemoryRegion* s_itemIndexToRegionPointer [MAX_RAM_SIZE+4] = {0}; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false +static struct Buffers { + unsigned char s_prevValues [MAX_RAM_SIZE+4]; // values at last search or reset + unsigned char s_curValues [MAX_RAM_SIZE+4]; // values at last frame update + unsigned short s_numChanges [MAX_RAM_SIZE+4]; // number of changes of the item starting at this virtual index address + MemoryRegion* s_itemIndexToRegionPointer [MAX_RAM_SIZE+4]; // used for random access into the memory list (trading memory size to get speed here, too bad it's so much memory), only valid when s_itemIndicesInvalid is false +} *buffers = NULL; static BOOL s_itemIndicesInvalid = true; // if true, the link from listbox items to memory regions (s_itemIndexToRegionPointer) and the link from memory regions to list box items (MemoryRegion::itemIndex) both need to be recalculated static BOOL s_prevValuesNeedUpdate = true; // if true, the "prev" values should be updated using the "cur" values on the next frame update signaled static unsigned int s_maxItemIndex = 0; // max currently valid item index, the listbox sometimes tries to update things past the end of the list so we need to know this to ignore those attempts @@ -92,6 +94,15 @@ static int s_undoType = 0; // 0 means can't undo, 1 means can undo, 2 means can void RamSearchSaveUndoStateIfNotTooBig(HWND hDlg); static const int tooManyRegionsForUndo = 10000; +void InitRamSearch() +{ + if(buffers == NULL) + { + buffers = new Buffers; + memset(buffers,0,sizeof(Buffers)); + } +} + void ResetMemoryRegions() { // Clear_Sound_Buffer(); @@ -200,7 +211,7 @@ void CalculateItemIndices(int itemSize) unsigned int start = startSkipSize; unsigned int end = region.size; for(unsigned int i = start; i < end; i += itemSize) - s_itemIndexToRegionPointer[itemIndex++] = ®ion; + buffers->s_itemIndexToRegionPointer[itemIndex++] = ®ion; } s_maxItemIndex = itemIndex; s_itemIndicesInvalid = FALSE; @@ -210,7 +221,7 @@ template void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr) { if(s_prevValuesNeedUpdate) - memcpy(s_prevValues + region.virtualIndex, s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); + memcpy(buffers->s_prevValues + region.virtualIndex, buffers->s_curValues + region.virtualIndex, region.size + sizeof(compareType) - sizeof(stepType)); unsigned int startSkipSize = ((unsigned int)(sizeof(stepType) - region.hardwareAddress)) % sizeof(stepType); @@ -222,11 +233,11 @@ void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr { for(unsigned int i = indexStart; i < indexEnd; i++) { - if(s_curValues[i] != sourceAddr[i^swapXOR]) // if value changed + if(buffers->s_curValues[i] != sourceAddr[i^swapXOR]) // if value changed { - s_curValues[i] = sourceAddr[i^swapXOR]; // update value + buffers->s_curValues[i] = sourceAddr[i^swapXOR]; // update value //if(s_numChanges[i] != 0xFFFF) - s_numChanges[i]++; // increase change count + buffers->s_numChanges[i]++; // increase change count } } } @@ -253,10 +264,10 @@ void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr for(unsigned int i = indexStart, j = 0; i < lastIndexToRead; i++, j++) { - if(s_curValues[i] != sourceAddr[i^swapXOR]) // if value of this byte changed + if(buffers->s_curValues[i] != sourceAddr[i^swapXOR]) // if value of this byte changed { if(i < lastIndexToCopy) - s_curValues[i] = sourceAddr[i^swapXOR]; // update value + buffers->s_curValues[i] = sourceAddr[i^swapXOR]; // update value for(int k = 0; k < sizeof(compareType); k++) // loop through the previous entries that contain this byte { if(i >= indexEnd+k) @@ -265,7 +276,7 @@ void UpdateRegionT(const MemoryRegion& region, const MemoryRegion* nextRegionPtr if(nextValidChange[m]+sizeof(compareType) <= i+sizeof(compareType)) // if we didn't already increase the change count for this entry { //if(s_numChanges[i-k] != 0xFFFF) - s_numChanges[i-k]++; // increase the change count for this entry + buffers->s_numChanges[i-k]++; // increase the change count for this entry nextValidChange[m] = i+sizeof(compareType); // and remember not to increase it again } } @@ -333,7 +344,7 @@ void ItemIndexToVirtualRegion(unsigned int itemIndex, MemoryRegion& virtualRegio return; } - const MemoryRegion* regionPtr = s_itemIndexToRegionPointer[itemIndex]; + const MemoryRegion* regionPtr = buffers->s_itemIndexToRegionPointer[itemIndex]; const MemoryRegion& region = *regionPtr; int bytesWithinRegion = (itemIndex - region.itemIndex) * sizeof(stepType); @@ -375,19 +386,19 @@ template<> unsigned char ReadBigEndian(const unsigned char* data) { return *data template compareType GetPrevValueFromVirtualIndex(unsigned int virtualIndex) { - return ReadBigEndian(s_prevValues + virtualIndex); + return ReadBigEndian(buffers->s_prevValues + virtualIndex); //return *(compareType*)(s_prevValues+virtualIndex); } template compareType GetCurValueFromVirtualIndex(unsigned int virtualIndex) { - return ReadBigEndian(s_curValues + virtualIndex); + return ReadBigEndian(buffers->s_curValues + virtualIndex); // return *(compareType*)(s_curValues+virtualIndex); } template unsigned short GetNumChangesFromVirtualIndex(unsigned int virtualIndex) { - unsigned short num = s_numChanges[virtualIndex]; + unsigned short num = buffers->s_numChanges[virtualIndex]; //for(unsigned int i = 1; i < sizeof(stepType); i++) // if(num < s_numChanges[virtualIndex+i]) // num = s_numChanges[virtualIndex+i]; @@ -970,14 +981,14 @@ void CompactAddrs() void soft_reset_address_info () { ResetMemoryRegions(); - memset(s_numChanges, 0, sizeof(s_numChanges)); + memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); CompactAddrs(); } void reset_address_info () { SetRamSearchUndoType(RamSearchHWnd, 0); s_activeMemoryRegionsBackup.clear(); // not necessary, but we'll take the time hit here instead of at the next thing that sets up an undo - memcpy(s_prevValues, s_curValues, sizeof(s_prevValues)); + memcpy(buffers->s_prevValues, buffers->s_curValues, sizeof(buffers->s_prevValues)); s_prevValuesNeedUpdate = false; ResetMemoryRegions(); if(!RamSearchHWnd) @@ -992,7 +1003,7 @@ void reset_address_info () s_prevValuesNeedUpdate = true; signal_new_frame(); } - memset(s_numChanges, 0, sizeof(s_numChanges)); + memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); CompactAddrs(); } @@ -1663,7 +1674,7 @@ LRESULT CALLBACK RamSearchProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lPara {rv = true; break;} } case IDC_C_RESET_CHANGES: - memset(s_numChanges, 0, sizeof(s_numChanges)); + memset(buffers->s_numChanges, 0, sizeof(buffers->s_numChanges)); ListView_Update(GetDlgItem(hDlg,IDC_RAMLIST), -1); //SetRamSearchUndoType(hDlg, 0); {rv = true; break;}