add binary movie mode, which is used when saving movies into savestates
This commit is contained in:
parent
d159696288
commit
8009546872
|
@ -311,7 +311,7 @@ static void Export()
|
|||
if(GetSaveFileName(&ofn))
|
||||
{
|
||||
fstream* osRecordingMovie = FCEUD_UTF8_fstream(ofn.lpstrFile, "wb");
|
||||
currMovieData.dump(osRecordingMovie);
|
||||
currMovieData.dump(osRecordingMovie,false);
|
||||
delete osRecordingMovie;
|
||||
osRecordingMovie = 0;
|
||||
}
|
||||
|
|
153
src/movie.cpp
153
src/movie.cpp
|
@ -127,18 +127,6 @@ void MovieRecord::parseJoy(std::istream* is, uint8& joystate)
|
|||
joystate <<= 1;
|
||||
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)
|
||||
|
@ -166,9 +154,6 @@ void MovieRecord::parse(MovieData* md, std::istream* is)
|
|||
parseJoy(is, joysticks[port]);
|
||||
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].y = 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
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
//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)
|
||||
, poweronFlag(false)
|
||||
, resetFlag(false)
|
||||
, binaryFlag(false)
|
||||
, recordCount(1)
|
||||
, greenZoneCount(0)
|
||||
{
|
||||
|
@ -279,6 +326,8 @@ void MovieData::installValue(std::string& key, std::string& val)
|
|||
installInt(val,ports[1]);
|
||||
else if(key == "port2")
|
||||
installInt(val,ports[2]);
|
||||
else if(key == "binary")
|
||||
installBool(val,binaryFlag);
|
||||
else if(key == "savestate")
|
||||
{
|
||||
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();
|
||||
*os << "version " << version << endl;
|
||||
|
@ -306,11 +355,23 @@ int MovieData::dump(std::ostream *os)
|
|||
*os << "port0 " << ports[0] << endl;
|
||||
*os << "port1 " << ports[1] << endl;
|
||||
*os << "port2 " << ports[2] << endl;
|
||||
|
||||
if(binary)
|
||||
*os << "binary 1" << endl;
|
||||
|
||||
if(savestate.size() != 0)
|
||||
*os << "savestate " << BytesToString(&savestate[0],savestate.size()) << endl;
|
||||
for(int i=0;i<(int)records.size();i++)
|
||||
records[i].dump(this,os,i);
|
||||
if(binary)
|
||||
{
|
||||
//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();
|
||||
return end-start;
|
||||
}
|
||||
|
@ -348,6 +409,43 @@ bool FCEUMOV_Mode(int 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.
|
||||
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');
|
||||
isrecchar = (c=='|');
|
||||
isnewline = (c==10||c==13);
|
||||
if(isrecchar && movieData.binaryFlag && !stopAfterHeader)
|
||||
{
|
||||
LoadFM2_binarychunk(movieData, fp, size);
|
||||
return;
|
||||
}
|
||||
switch(state)
|
||||
{
|
||||
case NEWLINE:
|
||||
|
@ -383,12 +486,12 @@ static void LoadFM2(MovieData& movieData, std::istream* fp, int size, bool stopA
|
|||
{
|
||||
dorecord:
|
||||
if (stopAfterHeader) return;
|
||||
MovieRecord record;
|
||||
int currcount = movieData.records.size();
|
||||
movieData.records.resize(currcount+1);
|
||||
int preparse = fp->tellg();
|
||||
record.parse(&movieData, fp);
|
||||
movieData.records[currcount].parse(&movieData, fp);
|
||||
int postparse = fp->tellg();
|
||||
size -= (postparse-preparse);
|
||||
movieData.records.push_back(record);
|
||||
state = NEWLINE;
|
||||
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
|
||||
currMovieData.dump(osRecordingMovie);
|
||||
currMovieData.dump(osRecordingMovie, false);
|
||||
|
||||
//todo - think about this
|
||||
//ResetInputTypes();
|
||||
|
@ -762,7 +865,7 @@ void FCEU_DrawMovies(uint8 *XBuf)
|
|||
char counterbuf[32] = {0};
|
||||
if(movieMode == MOVIEMODE_PLAY)
|
||||
sprintf(counterbuf,"%d/%d",currFrameCounter,currMovieData.records.size());
|
||||
else if(movieMode == MOVIEMODE_RECORD)
|
||||
else if(movieMode == MOVIEMODE_RECORD)
|
||||
sprintf(counterbuf,"%d",currMovieData.records.size());
|
||||
|
||||
if(counterbuf[0])
|
||||
|
@ -774,7 +877,7 @@ int FCEUMOV_WriteState(std::ostream* os)
|
|||
{
|
||||
//we are supposed to dump the movie data into the savestate
|
||||
if(movieMode == MOVIEMODE_RECORD || movieMode == MOVIEMODE_PLAY)
|
||||
return currMovieData.dump(os);
|
||||
return currMovieData.dump(os, true);
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
@ -845,7 +948,7 @@ bool FCEUMOV_ReadState(std::istream* is, uint32 size)
|
|||
currMovieData.recordCount++;
|
||||
|
||||
openRecordingMovie(curMovieFilename);
|
||||
currMovieData.dump(osRecordingMovie);
|
||||
currMovieData.dump(osRecordingMovie, false);
|
||||
movieMode = MOVIEMODE_RECORD;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,9 @@ public:
|
|||
std::vector<char> savestate;
|
||||
|
||||
void parse(MovieData* md, std::istream* is);
|
||||
bool parseBinary(MovieData* md, std::istream* is);
|
||||
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 dumpJoy(std::ostream* os, uint8 joystate);
|
||||
|
||||
|
@ -123,6 +125,9 @@ public:
|
|||
int recordCount;
|
||||
FCEU_Guid guid;
|
||||
|
||||
//was the frame data stored in binary?
|
||||
bool binaryFlag;
|
||||
|
||||
//which ports are defined for the movie
|
||||
int ports[3];
|
||||
//whether fourscore is enabled
|
||||
|
@ -164,7 +169,7 @@ public:
|
|||
|
||||
void truncateAt(int frame);
|
||||
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);
|
||||
|
||||
static bool loadSavestateFrom(std::vector<char>* buf);
|
||||
|
|
|
@ -256,46 +256,49 @@ void NetplayUpdate(uint8 *joyp)
|
|||
break;
|
||||
case FCEUNPCMD_SAVESTATE:
|
||||
{
|
||||
char *fn;
|
||||
FILE *fp;
|
||||
//mbg todo netplay
|
||||
//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 = strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());
|
||||
//if(!
|
||||
FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn);
|
||||
////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.
|
||||
|
||||
// {
|
||||
// free(fn);
|
||||
// return;
|
||||
// }
|
||||
free(fn);
|
||||
if(!FCEUnetplay) return;
|
||||
//fn = strdup(FCEU_MakeFName(FCEUMKF_CHEAT,0,0).c_str());
|
||||
|
||||
fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP,0,0).c_str());
|
||||
fp = fopen(fn, "wb");
|
||||
if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION))
|
||||
{
|
||||
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;
|
||||
}
|
||||
////why??????
|
||||
////if(!
|
||||
// FCEUNET_SendFile(FCEUNPCMD_LOADCHEATS,fn);
|
||||
//// {
|
||||
//// free(fn);
|
||||
//// return;
|
||||
//// }
|
||||
|
||||
//free(fn);
|
||||
//if(!FCEUnetplay) return;
|
||||
|
||||
//fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP,0,0).c_str());
|
||||
//fp = fopen(fn, "wb");
|
||||
//if(FCEUSS_SaveFP(fp,Z_BEST_COMPRESSION))
|
||||
//{
|
||||
// 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;
|
||||
|
|
|
@ -314,13 +314,6 @@ static bool ReadStateChunks(std::istream* is, int32 totalsize)
|
|||
int CurrentState=1;
|
||||
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)
|
||||
{
|
||||
|
@ -688,7 +681,8 @@ void FCEUI_LoadState(char *fname)
|
|||
|
||||
if(FCEUSS_Load(fname))
|
||||
{
|
||||
if(FCEUnetplay)
|
||||
//mbg todo netplay
|
||||
/*if(FCEUnetplay)
|
||||
{
|
||||
char *fn = strdup(FCEU_MakeFName(FCEUMKF_NPTEMP, 0, 0).c_str());
|
||||
FILE *fp;
|
||||
|
@ -709,7 +703,7 @@ void FCEUI_LoadState(char *fname)
|
|||
}
|
||||
|
||||
free(fn);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -31,7 +31,6 @@ bool FCEUSS_Load(char *);
|
|||
|
||||
//zlib values: 0 (none) through 9 (max) or -1 (default)
|
||||
bool FCEUSS_SaveMS(std::ostream* outstream, int compressionLevel);
|
||||
bool FCEUSS_SaveFP(FILE* fp, int compressionLevel);
|
||||
|
||||
bool FCEUSS_LoadFP(std::istream* is, ENUM_SSLOADPARAMS params);
|
||||
|
||||
|
|
|
@ -78,6 +78,22 @@ int write32le(uint32 b, std::ostream* os)
|
|||
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
|
||||
int read32le(uint32 *Bufo, FILE *fp)
|
||||
{
|
||||
|
@ -92,6 +108,21 @@ int read32le(uint32 *Bufo, FILE *fp)
|
|||
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)
|
||||
{
|
||||
uint32 buf;
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
int write16le(uint16 b, FILE *fp);
|
||||
int write32le(uint32 b, FILE *fp);
|
||||
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, FILE *fp);
|
||||
void FlipByteOrder(uint8 *src, uint32 count);
|
||||
|
|
Loading…
Reference in New Issue