add binary movie mode, which is used when saving movies into savestates

This commit is contained in:
zeromus 2008-06-20 22:15:30 +00:00
parent d159696288
commit 8009546872
8 changed files with 211 additions and 74 deletions

View File

@ -311,7 +311,7 @@ static void Export()
if(GetSaveFileName(&ofn)) if(GetSaveFileName(&ofn))
{ {
fstream* osRecordingMovie = FCEUD_UTF8_fstream(ofn.lpstrFile, "wb"); fstream* osRecordingMovie = FCEUD_UTF8_fstream(ofn.lpstrFile, "wb");
currMovieData.dump(osRecordingMovie); currMovieData.dump(osRecordingMovie,false);
delete osRecordingMovie; delete osRecordingMovie;
osRecordingMovie = 0; osRecordingMovie = 0;
} }

View File

@ -127,18 +127,6 @@ void MovieRecord::parseJoy(std::istream* is, uint8& joystate)
joystate <<= 1; joystate <<= 1;
joystate |= ((buf[i]!=' ')?1:0); joystate |= ((buf[i]!=' ')?1:0);
} }
//older, slower(?) way:
//joystate = 0;
//for(int bit=7;bit>=0;bit--)
//{
// int c = is->get();
// if(c == -1)
// return;
// if(c != ' ')
// joystate |= (1<<bit);
//}
} }
void MovieRecord::parse(MovieData* md, std::istream* is) void MovieRecord::parse(MovieData* md, std::istream* is)
@ -166,9 +154,6 @@ void MovieRecord::parse(MovieData* md, std::istream* is)
parseJoy(is, joysticks[port]); parseJoy(is, joysticks[port]);
else if(md->ports[port] == SI_ZAPPER) else if(md->ports[port] == SI_ZAPPER)
{ {
int x,y,b,bogo;
uint64 zaphit;
//*is >> x >> y >> b >> bogo >> zaphit;
zappers[port].x = uint32DecFromIstream(is); zappers[port].x = uint32DecFromIstream(is);
zappers[port].y = uint32DecFromIstream(is); zappers[port].y = uint32DecFromIstream(is);
zappers[port].b = uint32DecFromIstream(is); zappers[port].b = uint32DecFromIstream(is);
@ -186,6 +171,67 @@ void MovieRecord::parse(MovieData* md, std::istream* is)
//should be left at a newline //should be left at a newline
} }
bool MovieRecord::parseBinary(MovieData* md, std::istream* is)
{
commands = (uint8)is->get();
//check for eof
if(is->gcount() != 1) return false;
if(md->fourscore)
{
is->read((char*)&joysticks,4);
}
else
{
for(int port=0;port<2;port++)
{
if(md->ports[port] == SI_GAMEPAD)
joysticks[port] = (uint8)is->get();
else if(md->ports[port] == SI_ZAPPER)
{
zappers[port].x = (uint8)is->get();
zappers[port].y = (uint8)is->get();
zappers[port].b = (uint8)is->get();
zappers[port].bogo = (uint8)is->get();
zappers[port].zaphit = uint64DecFromIstream(is);
}
}
}
return true;
}
void MovieRecord::dumpBinary(MovieData* md, std::ostream* os, int index)
{
os->put(commands);
if(md->fourscore)
{
os->put(joysticks[0]);
os->put(joysticks[1]);
os->put(joysticks[2]);
os->put(joysticks[3]);
}
else
{
for(int port=0;port<2;port++)
{
if(md->ports[port] == SI_GAMEPAD)
os->put(joysticks[port]);
else if(md->ports[port] == SI_ZAPPER)
{
os->put(zappers[port].x);
os->put(zappers[port].y);
os->put(zappers[port].b);
os->put(zappers[port].bogo);
write64le(zappers[port].zaphit, os);
}
}
}
}
void MovieRecord::dump(MovieData* md, std::ostream* os, int index) void MovieRecord::dump(MovieData* md, std::ostream* os, int index)
{ {
//todo: if we want frame numbers in the output (which we dont since we couldnt cut and paste in movies) //todo: if we want frame numbers in the output (which we dont since we couldnt cut and paste in movies)
@ -239,6 +285,7 @@ MovieData::MovieData()
, palFlag(false) , palFlag(false)
, poweronFlag(false) , poweronFlag(false)
, resetFlag(false) , resetFlag(false)
, binaryFlag(false)
, recordCount(1) , recordCount(1)
, greenZoneCount(0) , greenZoneCount(0)
{ {
@ -279,6 +326,8 @@ void MovieData::installValue(std::string& key, std::string& val)
installInt(val,ports[1]); installInt(val,ports[1]);
else if(key == "port2") else if(key == "port2")
installInt(val,ports[2]); installInt(val,ports[2]);
else if(key == "binary")
installBool(val,binaryFlag);
else if(key == "savestate") else if(key == "savestate")
{ {
int len = HexStringToBytesLength(val); int len = HexStringToBytesLength(val);
@ -290,7 +339,7 @@ void MovieData::installValue(std::string& key, std::string& val)
} }
} }
int MovieData::dump(std::ostream *os) int MovieData::dump(std::ostream *os, bool binary)
{ {
int start = os->tellp(); int start = os->tellp();
*os << "version " << version << endl; *os << "version " << version << endl;
@ -306,11 +355,23 @@ int MovieData::dump(std::ostream *os)
*os << "port0 " << ports[0] << endl; *os << "port0 " << ports[0] << endl;
*os << "port1 " << ports[1] << endl; *os << "port1 " << ports[1] << endl;
*os << "port2 " << ports[2] << endl; *os << "port2 " << ports[2] << endl;
if(binary)
*os << "binary 1" << endl;
if(savestate.size() != 0) if(savestate.size() != 0)
*os << "savestate " << BytesToString(&savestate[0],savestate.size()) << endl; *os << "savestate " << BytesToString(&savestate[0],savestate.size()) << endl;
for(int i=0;i<(int)records.size();i++) if(binary)
records[i].dump(this,os,i); {
//put one | to start the binary dump
os->put('|');
for(int i=0;i<(int)records.size();i++)
records[i].dumpBinary(this,os,i);
}
else
for(int i=0;i<(int)records.size();i++)
records[i].dump(this,os,i);
int end = os->tellp(); int end = os->tellp();
return end-start; return end-start;
} }
@ -348,6 +409,43 @@ bool FCEUMOV_Mode(int modemask)
return FCEUMOV_Mode((EMOVIEMODE)modemask); return FCEUMOV_Mode((EMOVIEMODE)modemask);
} }
static void LoadFM2_binarychunk(MovieData& movieData, std::istream* fp, int size)
{
int recordsize = 1; //1 for the command
if(movieData.fourscore)
recordsize += 4; //4 joysticks
else
{
for(int i=0;i<2;i++)
{
switch(movieData.ports[i])
{
case SI_GAMEPAD: recordsize++; break;
case SI_ZAPPER: recordsize+=10; break;
}
}
}
//find out how much remains in the file
int curr = fp->tellg();
fp->seekg(0,std::ios::end);
int end = fp->tellg();
int flen = end-curr;
fp->seekg(curr,std::ios::beg);
//the amount todo is the min of the limiting size we received and the remaining contents of the file
int todo = std::min(size, flen);
int numRecords = todo/recordsize;
movieData.records.resize(numRecords);
for(int i=0;i<numRecords;i++)
{
movieData.records[i].parseBinary(&movieData,fp);
}
}
//yuck... another custom text parser. //yuck... another custom text parser.
static void LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopAfterHeader) static void LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopAfterHeader)
{ {
@ -367,6 +465,11 @@ static void LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopA
iswhitespace = (c==' '||c=='\t'); iswhitespace = (c==' '||c=='\t');
isrecchar = (c=='|'); isrecchar = (c=='|');
isnewline = (c==10||c==13); isnewline = (c==10||c==13);
if(isrecchar && movieData.binaryFlag && !stopAfterHeader)
{
LoadFM2_binarychunk(movieData, fp, size);
return;
}
switch(state) switch(state)
{ {
case NEWLINE: case NEWLINE:
@ -383,12 +486,12 @@ static void LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopA
{ {
dorecord: dorecord:
if (stopAfterHeader) return; if (stopAfterHeader) return;
MovieRecord record; int currcount = movieData.records.size();
movieData.records.resize(currcount+1);
int preparse = fp->tellg(); int preparse = fp->tellg();
record.parse(&movieData, fp); movieData.records[currcount].parse(&movieData, fp);
int postparse = fp->tellg(); int postparse = fp->tellg();
size -= (postparse-preparse); size -= (postparse-preparse);
movieData.records.push_back(record);
state = NEWLINE; state = NEWLINE;
break; break;
} }
@ -660,7 +763,7 @@ void FCEUI_SaveMovie(char *fname, uint8 flags)
} }
//we are going to go ahead and dump the header. from now on we will only be appending frames //we are going to go ahead and dump the header. from now on we will only be appending frames
currMovieData.dump(osRecordingMovie); currMovieData.dump(osRecordingMovie, false);
//todo - think about this //todo - think about this
//ResetInputTypes(); //ResetInputTypes();
@ -762,7 +865,7 @@ void FCEU_DrawMovies(uint8 *XBuf)
char counterbuf[32] = {0}; char counterbuf[32] = {0};
if(movieMode == MOVIEMODE_PLAY) if(movieMode == MOVIEMODE_PLAY)
sprintf(counterbuf,"%d/%d",currFrameCounter,currMovieData.records.size()); sprintf(counterbuf,"%d/%d",currFrameCounter,currMovieData.records.size());
else if(movieMode == MOVIEMODE_RECORD) else if(movieMode == MOVIEMODE_RECORD)
sprintf(counterbuf,"%d",currMovieData.records.size()); sprintf(counterbuf,"%d",currMovieData.records.size());
if(counterbuf[0]) if(counterbuf[0])
@ -774,7 +877,7 @@ int FCEUMOV_WriteState(std::ostream* os)
{ {
//we are supposed to dump the movie data into the savestate //we are supposed to dump the movie data into the savestate
if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY) if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY)
return currMovieData.dump(os); return currMovieData.dump(os, true);
else return 0; else return 0;
} }
@ -845,7 +948,7 @@ bool FCEUMOV_ReadState(std::istream* is, uint32 size)
currMovieData.recordCount++; currMovieData.recordCount++;
openRecordingMovie(curMovieFilename); openRecordingMovie(curMovieFilename);
currMovieData.dump(osRecordingMovie); currMovieData.dump(osRecordingMovie, false);
movieMode = MOVIEMODE_RECORD; movieMode = MOVIEMODE_RECORD;
} }
} }

View File

@ -93,7 +93,9 @@ public:
std::vector<char> savestate; std::vector<char> savestate;
void parse(MovieData* md, std::istream* is); void parse(MovieData* md, std::istream* is);
bool parseBinary(MovieData* md, std::istream* is);
void dump(MovieData* md, std::ostream* os, int index); void dump(MovieData* md, std::ostream* os, int index);
void dumpBinary(MovieData* md, std::ostream* os, int index);
void parseJoy(std::istream* is, uint8& joystate); void parseJoy(std::istream* is, uint8& joystate);
void dumpJoy(std::ostream* os, uint8 joystate); void dumpJoy(std::ostream* os, uint8 joystate);
@ -123,6 +125,9 @@ public:
int recordCount; int recordCount;
FCEU_Guid guid; FCEU_Guid guid;
//was the frame data stored in binary?
bool binaryFlag;
//which ports are defined for the movie //which ports are defined for the movie
int ports[3]; int ports[3];
//whether fourscore is enabled //whether fourscore is enabled
@ -164,7 +169,7 @@ public:
void truncateAt(int frame); void truncateAt(int frame);
void installValue(std::string& key, std::string& val); void installValue(std::string& key, std::string& val);
int dump(std::ostream* os); int dump(std::ostream* os, bool binary);
void clearRecordRange(int start, int len); void clearRecordRange(int start, int len);
static bool loadSavestateFrom(std::vector<char>* buf); static bool loadSavestateFrom(std::vector<char>* buf);

View File

@ -256,46 +256,49 @@ void NetplayUpdate(uint8 *joyp)
break; break;
case FCEUNPCMD_SAVESTATE: case FCEUNPCMD_SAVESTATE:
{ {
char *fn; //mbg todo netplay
FILE *fp; //char *fn;
//FILE *fp;
/* Send the cheats first, then the save state, since ////Send the cheats first, then the save state, since
there might be a frame or two in between the two sendfile ////there might be a frame or two in between the two sendfile
commands on the server side. ////commands on the server side.
*/
fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());
//if(!
FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn);
// { //fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());
// free(fn);
// return;
// }
free(fn);
if(!FCEUnetplay) return;
fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP,0,0).c_str()); ////why??????
fp = fopen(fn, "wb"); ////if(!
if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION)) // FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn);
{ //// {
fclose(fp); //// free(fn);
if(!FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn)) //// return;
{ //// }
unlink(fn);
free(fn); //free(fn);
return; //if(!FCEUnetplay) return;
}
unlink(fn); //fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP,0,0).c_str());
free(fn); //fp = fopen(fn, "wb");
} //if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION))
else //{
{ // fclose(fp);
fclose(fp); // if(!FCEUNET_SendFile(FCEUNPCMD_LOADSTATE, fn))
FCEUD_PrintError("File error. (K)ill, (M)aim, (D)estroy? Now!"); // {
unlink(fn); // unlink(fn);
free(fn); // free(fn);
return; // 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; break;

View File

@ -314,13 +314,6 @@ static bool ReadStateChunks(std::istream* is, int32 totalsize)
int CurrentState=1; int CurrentState=1;
extern int geniestage; extern int geniestage;
bool FCEUSS_SaveFP(FILE* fp, int compressionLevel)
{
memorystream ms;
bool ret = FCEUSS_SaveMS(&ms,compressionLevel);
fwrite(ms.buf(),1,ms.size(),fp);
return ret;
}
bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel) bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel)
{ {
@ -688,7 +681,8 @@ void FCEUI_LoadState(char *fname)
if(FCEUSS_Load(fname)) if(FCEUSS_Load(fname))
{ {
if(FCEUnetplay) //mbg todo netplay
/*if(FCEUnetplay)
{ {
char *fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0).c_str()); char *fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0).c_str());
FILE *fp; FILE *fp;
@ -709,7 +703,7 @@ void FCEUI_LoadState(char *fname)
} }
free(fn); free(fn);
} }*/
} }
else else
{ {

View File

@ -31,7 +31,6 @@ bool FCEUSS_Load(char *);
//zlib values: 0 (none) through 9 (max) or -1 (default) //zlib values: 0 (none) through 9 (max) or -1 (default)
bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel); bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel);
bool FCEUSS_SaveFP(FILE* fp, int compressionLevel);
bool FCEUSS_LoadFP(std::istream* is, ENUM_SSLOADPARAMS params); bool FCEUSS_LoadFP(std::istream* is, ENUM_SSLOADPARAMS params);

View File

@ -78,6 +78,22 @@ int write32le(uint32 b, std::ostream* os)
return 4; return 4;
} }
int write64le(uint64 b, std::ostream* os)
{
uint8 s[8];
s[0]=b;
s[1]=b>>8;
s[2]=b>>16;
s[3]=b>>24;
s[4]=b>>32;
s[5]=b>>40;
s[6]=b>>48;
s[7]=b>>56;
os->write((char*)&s,8);
return 4;
}
///reads a little endian 32bit value from the specified file ///reads a little endian 32bit value from the specified file
int read32le(uint32 *Bufo, FILE *fp) int read32le(uint32 *Bufo, FILE *fp)
{ {
@ -92,6 +108,21 @@ int read32le(uint32 *Bufo, FILE *fp)
return 1; return 1;
} }
///reads a little endian 64bit value from the specified file
int read64le(uint64 *Bufo, std::istream *is)
{
uint64 buf;
if(is->read((char*)&buf,8).gcount() != 8)
return 0;
#ifdef LSB_FIRST
*Bufo=buf;
#else
*Bufo = FCEU_de64lsb(&buf)
#endif
return 1;
}
int read32le(uint32 *Bufo, std::istream *is) int read32le(uint32 *Bufo, std::istream *is)
{ {
uint32 buf; uint32 buf;

View File

@ -8,6 +8,8 @@
int write16le(uint16 b, FILE *fp); int write16le(uint16 b, FILE *fp);
int write32le(uint32 b, FILE *fp); int write32le(uint32 b, FILE *fp);
int write32le(uint32 b, std::ostream* os); int write32le(uint32 b, std::ostream* os);
int write64le(uint64 b, std::ostream* os);
int read64le(uint64 *Bufo, std::istream *is);
int read32le(uint32 *Bufo, std::istream *is); int read32le(uint32 *Bufo, std::istream *is);
int read32le(uint32 *Bufo, FILE *fp); int read32le(uint32 *Bufo, FILE *fp);
void FlipByteOrder(uint8 *src, uint32 count); void FlipByteOrder(uint8 *src, uint32 count);