Add VBA Movie Version 2

Add new format for recording VBA Movies that records inputs since the
time of the last input instead of the beginning of the movie.

Keep the extension `.vmv` the same, the format is determined from the
header of the file.

Make this the new default format for recording VBA Movies.

Signed-off-by: Rafael Kitover <rkitover@gmail.com>
This commit is contained in:
laqieer 2022-08-07 18:54:49 +00:00 committed by Rafael Kitover
parent 5008ffbacf
commit d2fee771fd
No known key found for this signature in database
GPG Key ID: 08AB596679D86240
5 changed files with 311 additions and 106 deletions

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-07-23 17:25-0700\n" "POT-Creation-Date: 2022-08-06 20:51+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -358,7 +358,7 @@ msgid "Text files (*.txt;*.log)|*.txt;*.log|"
msgstr "" msgstr ""
#: viewers.cpp:562 viewers.cpp:772 gfxviewers.cpp:1600 gfxviewers.cpp:1742 #: viewers.cpp:562 viewers.cpp:772 gfxviewers.cpp:1600 gfxviewers.cpp:1742
#: cmdevents.cpp:1157 cmdevents.cpp:1235 cmdevents.cpp:1305 cmdevents.cpp:1332 #: cmdevents.cpp:1157 cmdevents.cpp:1235 cmdevents.cpp:1305 cmdevents.cpp:1374
#: viewsupt.cpp:1180 #: viewsupt.cpp:1180
msgid "Select output file" msgid "Select output file"
msgstr "" msgstr ""
@ -729,105 +729,101 @@ msgstr ""
msgid "Error saving snapshot file %s" msgid "Error saving snapshot file %s"
msgstr "" msgstr ""
#: cmdevents.cpp:1182 sys.cpp:450 #: cmdevents.cpp:1182 sys.cpp:524
#, c-format #, c-format
msgid "Wrote snapshot %s" msgid "Wrote snapshot %s"
msgstr "" msgstr ""
#: cmdevents.cpp:1203 cmdevents.cpp:1273 #: cmdevents.cpp:1203 cmdevents.cpp:1273 cmdevents.cpp:1344 cmdevents.cpp:1408
msgid " files (" msgid " files ("
msgstr "" msgstr ""
#: cmdevents.cpp:1333 cmdevents.cpp:1354 #: cmdevents.cpp:1439
msgid "VBA Movie files|*.vmv"
msgstr ""
#: cmdevents.cpp:1353
msgid "Select file" msgid "Select file"
msgstr "" msgstr ""
#: cmdevents.cpp:1668 cmdevents.cpp:1761 #: cmdevents.cpp:1756 cmdevents.cpp:1849
msgid "Select state file" msgid "Select state file"
msgstr "" msgstr ""
#: cmdevents.cpp:1669 cmdevents.cpp:1762 #: cmdevents.cpp:1757 cmdevents.cpp:1850
msgid "VisualBoyAdvance saved game files|*.sgm" msgid "VisualBoyAdvance saved game files|*.sgm"
msgstr "" msgstr ""
#: cmdevents.cpp:1792 cmdevents.cpp:1802 cmdevents.cpp:1813 #: cmdevents.cpp:1880 cmdevents.cpp:1890 cmdevents.cpp:1901
#, c-format #, c-format
msgid "Current state slot #%d" msgid "Current state slot #%d"
msgstr "" msgstr ""
#: cmdevents.cpp:1883 #: cmdevents.cpp:1971
msgid "Cannot use Colorizer Hack when GB BIOS File is enabled." msgid "Cannot use Colorizer Hack when GB BIOS File is enabled."
msgstr "" msgstr ""
#: cmdevents.cpp:2098 #: cmdevents.cpp:2186
msgid "Sound enabled" msgid "Sound enabled"
msgstr "" msgstr ""
#: cmdevents.cpp:2098 #: cmdevents.cpp:2186
msgid "Sound disabled" msgid "Sound disabled"
msgstr "" msgstr ""
#: cmdevents.cpp:2111 cmdevents.cpp:2125 #: cmdevents.cpp:2199 cmdevents.cpp:2213
#, c-format #, c-format
msgid "Volume: %d%%" msgid "Volume: %d%%"
msgstr "" msgstr ""
#: cmdevents.cpp:2200 #: cmdevents.cpp:2288
msgid "Set to 0 for pseudo tty" msgid "Set to 0 for pseudo tty"
msgstr "" msgstr ""
#: cmdevents.cpp:2202 #: cmdevents.cpp:2290
msgid "Port to wait for connection:" msgid "Port to wait for connection:"
msgstr "" msgstr ""
#: cmdevents.cpp:2203 #: cmdevents.cpp:2291
msgid "GDB Connection" msgid "GDB Connection"
msgstr "" msgstr ""
#: cmdevents.cpp:2256 #: cmdevents.cpp:2344
#, c-format #, c-format
msgid "Waiting for connection at %s" msgid "Waiting for connection at %s"
msgstr "" msgstr ""
#: cmdevents.cpp:2263 #: cmdevents.cpp:2351
#, c-format #, c-format
msgid "Waiting for connection on port %d" msgid "Waiting for connection on port %d"
msgstr "" msgstr ""
#: cmdevents.cpp:2266 #: cmdevents.cpp:2354
msgid "Waiting for GDB..." msgid "Waiting for GDB..."
msgstr "" msgstr ""
#: cmdevents.cpp:2681 #: cmdevents.cpp:2769
#, c-format #, c-format
msgid "Using pixel filter #%d" msgid "Using pixel filter #%d"
msgstr "" msgstr ""
#: cmdevents.cpp:2696 #: cmdevents.cpp:2784
#, c-format #, c-format
msgid "Using interframe blending #%d" msgid "Using interframe blending #%d"
msgstr "" msgstr ""
#: cmdevents.cpp:2735 panel.cpp:192 panel.cpp:306 #: cmdevents.cpp:2823 panel.cpp:192 panel.cpp:306
msgid "Could not initialize the sound driver!" msgid "Could not initialize the sound driver!"
msgstr "" msgstr ""
#: cmdevents.cpp:2839 #: cmdevents.cpp:2927
msgid "Nintendo GameBoy (+Color+Advance) emulator." msgid "Nintendo GameBoy (+Color+Advance) emulator."
msgstr "" msgstr ""
#: cmdevents.cpp:2840 #: cmdevents.cpp:2928
msgid "" msgid ""
"Copyright (C) 1999-2003 Forgotten\n" "Copyright (C) 1999-2003 Forgotten\n"
"Copyright (C) 2004-2006 VBA development team\n" "Copyright (C) 2004-2006 VBA development team\n"
"Copyright (C) 2007-2020 VBA-M development team" "Copyright (C) 2007-2020 VBA-M development team"
msgstr "" msgstr ""
#: cmdevents.cpp:2841 #: cmdevents.cpp:2929
msgid "" msgid ""
"This program is free software: you can redistribute it and/or modify\n" "This program is free software: you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n" "it under the terms of the GNU General Public License as published by\n"
@ -843,114 +839,114 @@ msgid ""
"along with this program. If not, see http://www.gnu.org/licenses ." "along with this program. If not, see http://www.gnu.org/licenses ."
msgstr "" msgstr ""
#: cmdevents.cpp:3101 #: cmdevents.cpp:3189
msgid "Cannot use GB BIOS when Colorizer Hack is enabled." msgid "Cannot use GB BIOS when Colorizer Hack is enabled."
msgstr "" msgstr ""
#: cmdevents.cpp:3161 #: cmdevents.cpp:3249
msgid "LAN link is already active. Disable link mode to disconnect." msgid "LAN link is already active. Disable link mode to disconnect."
msgstr "" msgstr ""
#: cmdevents.cpp:3167 #: cmdevents.cpp:3255
msgid "Network is not supported in local mode." msgid "Network is not supported in local mode."
msgstr "" msgstr ""
#: opts.cpp:648 opts.cpp:950 #: opts.cpp:649 opts.cpp:951
#, c-format #, c-format
msgid "Invalid value %s for option %s; valid values are %s%s%s" msgid "Invalid value %s for option %s; valid values are %s%s%s"
msgstr "" msgstr ""
#: opts.cpp:665 opts.cpp:962 #: opts.cpp:666 opts.cpp:963
#, c-format #, c-format
msgid "Invalid value %d for option %s; valid values are %d - %d" msgid "Invalid value %d for option %s; valid values are %d - %d"
msgstr "" msgstr ""
#: opts.cpp:672 opts.cpp:681 opts.cpp:970 opts.cpp:978 #: opts.cpp:673 opts.cpp:682 opts.cpp:971 opts.cpp:979
#, c-format #, c-format
msgid "Invalid value %f for option %s; valid values are %f - %f" msgid "Invalid value %f for option %s; valid values are %f - %f"
msgstr "" msgstr ""
#: opts.cpp:738 opts.cpp:759 opts.cpp:1046 #: opts.cpp:739 opts.cpp:760 opts.cpp:1047
#, c-format #, c-format
msgid "Invalid key binding %s for %s" msgid "Invalid key binding %s for %s"
msgstr "" msgstr ""
#: opts.cpp:933 #: opts.cpp:934
#, c-format #, c-format
msgid "Invalid flag option %s - %s ignored" msgid "Invalid flag option %s - %s ignored"
msgstr "" msgstr ""
#: sys.cpp:125 sys.cpp:181 #: sys.cpp:161 sys.cpp:221
msgid "No game in progress to record" msgid "No game in progress to record"
msgstr "" msgstr ""
#: sys.cpp:138 #: sys.cpp:178
#, c-format #, c-format
msgid "Cannot open output file %s" msgid "Cannot open output file %s"
msgstr "" msgstr ""
#: sys.cpp:145 sys.cpp:165 sys.cpp:311 #: sys.cpp:185 sys.cpp:205 sys.cpp:355
msgid "Error writing game recording" msgid "Error writing game recording"
msgstr "" msgstr ""
#: sys.cpp:186 #: sys.cpp:226
msgid "Cannot play game recording while recording" msgid "Cannot play game recording while recording"
msgstr "" msgstr ""
#: sys.cpp:199 #: sys.cpp:243
#, c-format #, c-format
msgid "Cannot open recording file %s" msgid "Cannot open recording file %s"
msgstr "" msgstr ""
#: sys.cpp:206 sys.cpp:216 #: sys.cpp:250 sys.cpp:260
msgid "Error reading game recording" msgid "Error reading game recording"
msgstr "" msgstr ""
#: sys.cpp:322 #: sys.cpp:371 sys.cpp:391
msgid "Playback ended" msgid "Playback ended"
msgstr "" msgstr ""
#: sys.cpp:341 #: sys.cpp:415
#, c-format #, c-format
msgid "%d%%(%d, %d fps)" msgid "%d%%(%d, %d fps)"
msgstr "" msgstr ""
#: sys.cpp:349 #: sys.cpp:423
#, c-format #, c-format
msgid "%d%%" msgid "%d%%"
msgstr "" msgstr ""
#: sys.cpp:769 xrc/GBPrinter.xrc:65 #: sys.cpp:843 xrc/GBPrinter.xrc:65
msgid "&Discard" msgid "&Discard"
msgstr "" msgstr ""
#: sys.cpp:803 #: sys.cpp:877
msgid "Image files (*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png|" msgid "Image files (*.bmp;*.jpg;*.png)|*.bmp;*.jpg;*.png|"
msgstr "" msgstr ""
#: sys.cpp:812 #: sys.cpp:886
msgid "Save printer image to" msgid "Save printer image to"
msgstr "" msgstr ""
#: sys.cpp:826 sys.cpp:1009 #: sys.cpp:900 sys.cpp:1083
#, c-format #, c-format
msgid "Wrote printer output to %s" msgid "Wrote printer output to %s"
msgstr "" msgstr ""
#: sys.cpp:831 sys.cpp:902 #: sys.cpp:905 sys.cpp:976
msgid "&Close" msgid "&Close"
msgstr "" msgstr ""
#: sys.cpp:897 #: sys.cpp:971
msgid "Printed" msgid "Printed"
msgstr "" msgstr ""
#: sys.cpp:1199 #: sys.cpp:1273
#, c-format #, c-format
msgid "Error opening pseudo tty: %s" msgid "Error opening pseudo tty: %s"
msgstr "" msgstr ""
#: sys.cpp:1298 #: sys.cpp:1372
#, c-format #, c-format
msgid "Error setting up server socket (%d)" msgid "Error setting up server socket (%d)"
msgstr "" msgstr ""
@ -1046,70 +1042,70 @@ msgstr ""
msgid "Error writing rewind state" msgid "Error writing rewind state"
msgstr "" msgstr ""
#: panel.cpp:2198 #: panel.cpp:2201
msgid "Failed to set glXSwapIntervalEXT" msgid "Failed to set glXSwapIntervalEXT"
msgstr "" msgstr ""
#: panel.cpp:2207 #: panel.cpp:2210
msgid "Failed to set glXSwapIntervalSGI" msgid "Failed to set glXSwapIntervalSGI"
msgstr "" msgstr ""
#: panel.cpp:2216 #: panel.cpp:2219
msgid "Failed to set glXSwapIntervalMESA" msgid "Failed to set glXSwapIntervalMESA"
msgstr "" msgstr ""
#: panel.cpp:2222 #: panel.cpp:2225
msgid "No support for wglGetExtensionsStringEXT" msgid "No support for wglGetExtensionsStringEXT"
msgstr "" msgstr ""
#: panel.cpp:2225 #: panel.cpp:2228
msgid "No support for WGL_EXT_swap_control" msgid "No support for WGL_EXT_swap_control"
msgstr "" msgstr ""
#: panel.cpp:2234 #: panel.cpp:2237
msgid "Failed to set wglSwapIntervalEXT" msgid "Failed to set wglSwapIntervalEXT"
msgstr "" msgstr ""
#: panel.cpp:2240 #: panel.cpp:2243
msgid "No VSYNC available on this platform" msgid "No VSYNC available on this platform"
msgstr "" msgstr ""
#: panel.cpp:2336 #: panel.cpp:2339
msgid "memory allocation error" msgid "memory allocation error"
msgstr "" msgstr ""
#: panel.cpp:2339 #: panel.cpp:2342
msgid "error initializing codec" msgid "error initializing codec"
msgstr "" msgstr ""
#: panel.cpp:2342 #: panel.cpp:2345
msgid "error writing to output file" msgid "error writing to output file"
msgstr "" msgstr ""
#: panel.cpp:2345 #: panel.cpp:2348
msgid "can't guess output format from file name" msgid "can't guess output format from file name"
msgstr "" msgstr ""
#: panel.cpp:2350 #: panel.cpp:2353
msgid "programming error; aborting!" msgid "programming error; aborting!"
msgstr "" msgstr ""
#: panel.cpp:2362 panel.cpp:2391 #: panel.cpp:2365 panel.cpp:2394
#, c-format #, c-format
msgid "Unable to begin recording to %s (%s)" msgid "Unable to begin recording to %s (%s)"
msgstr "" msgstr ""
#: panel.cpp:2419 #: panel.cpp:2422
#, c-format #, c-format
msgid "Error in audio/video recording (%s); aborting" msgid "Error in audio/video recording (%s); aborting"
msgstr "" msgstr ""
#: panel.cpp:2425 #: panel.cpp:2428
#, c-format #, c-format
msgid "Error in audio recording (%s); aborting" msgid "Error in audio recording (%s); aborting"
msgstr "" msgstr ""
#: panel.cpp:2435 #: panel.cpp:2438
#, c-format #, c-format
msgid "Error in video recording (%s); aborting" msgid "Error in video recording (%s); aborting"
msgstr "" msgstr ""
@ -1170,12 +1166,12 @@ msgstr ""
msgid "CONTROL" msgid "CONTROL"
msgstr "" msgstr ""
#: widgets/sdljoy.cpp:177 #: widgets/sdljoy.cpp:170
#, c-format #, c-format
msgid "Connected %s: %s" msgid "Connected %s: %s"
msgstr "" msgstr ""
#: widgets/sdljoy.cpp:192 #: widgets/sdljoy.cpp:185
#, c-format #, c-format
msgid "Disconnected %s" msgid "Disconnected %s"
msgstr "" msgstr ""

View File

@ -25,36 +25,32 @@ const supportedCodecs videoSupported[] = {
std::vector<char *> recording::getSupVidNames() std::vector<char *> recording::getSupVidNames()
{ {
std::vector<char *> result; std::vector<char *> result;
size_t size = sizeof(videoSupported) / sizeof(videoSupported[0]); for (auto&& codec : videoSupported)
for (size_t i = 0; i < size; ++i) result.push_back((char *)codec.longName);
result.push_back((char *)videoSupported[i].longName);
return result; return result;
} }
std::vector<char *> recording::getSupVidExts() std::vector<char *> recording::getSupVidExts()
{ {
std::vector<char *> result; std::vector<char *> result;
size_t size = sizeof(videoSupported) / sizeof(videoSupported[0]); for (auto&& codec : videoSupported)
for (size_t i = 0; i < size; ++i) result.push_back((char *)codec.exts);
result.push_back((char *)videoSupported[i].exts);
return result; return result;
} }
std::vector<char *> recording::getSupAudNames() std::vector<char *> recording::getSupAudNames()
{ {
std::vector<char *> result; std::vector<char *> result;
size_t size = sizeof(audioSupported) / sizeof(audioSupported[0]); for (auto&& codec : audioSupported)
for (size_t i = 0; i < size; ++i) result.push_back((char *)codec.longName);
result.push_back((char *)audioSupported[i].longName);
return result; return result;
} }
std::vector<char *> recording::getSupAudExts() std::vector<char *> recording::getSupAudExts()
{ {
std::vector<char *> result; std::vector<char *> result;
size_t size = sizeof(audioSupported) / sizeof(audioSupported[0]); for (auto&& codec : audioSupported)
for (size_t i = 0; i < size; ++i) result.push_back((char *)codec.exts);
result.push_back((char *)audioSupported[i].exts);
return result; return result;
} }

View File

@ -1327,17 +1327,61 @@ static wxString mov_path;
EVT_HANDLER_MASK(RecordMovieStartRecording, "Start game recording...", CMDEN_NGREC) EVT_HANDLER_MASK(RecordMovieStartRecording, "Start game recording...", CMDEN_NGREC)
{ {
static wxString mov_exts;
static int mov_extno;
static wxString mov_path;
if (!mov_exts.size()) {
mov_extno = -1;
int extno = 0;
std::vector<char*> fmts = getSupMovNamesToRecord();
std::vector<char*> exts = getSupMovExtsToRecord();
for (auto&& fmt : fmts)
{
mov_exts.append(wxString(fmt, wxConvLibc));
mov_exts.append(_(" files ("));
wxString ext(exts[extno], wxConvLibc);
ext.Replace(wxT(","), wxT(";*."));
ext.insert(0, wxT("*."));
if (mov_extno < 0 && ext.find(wxT("*.vmv")) != wxString::npos)
mov_extno = extno;
mov_exts.append(ext);
mov_exts.append(wxT(")|"));
mov_exts.append(ext);
mov_exts.append(wxT('|'));
extno++;
}
if (mov_extno < 0)
mov_extno = extno;
}
mov_path = GetGamePath(gopts.recording_dir); mov_path = GetGamePath(gopts.recording_dir);
wxString def_name = panel->game_name() + wxT(".vmv"); wxString def_name = panel->game_name();
wxString extoff = mov_exts;
for (int i = 0; i < mov_extno; i++) {
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
}
extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip *
def_name += extoff.Left(wxStrcspn(extoff, wxT(";|")));
wxFileDialog dlg(this, _("Select output file"), mov_path, def_name, wxFileDialog dlg(this, _("Select output file"), mov_path, def_name,
_("VBA Movie files|*.vmv"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); mov_exts, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
dlg.SetFilterIndex(mov_extno);
int ret = ShowModal(&dlg); int ret = ShowModal(&dlg);
mov_extno = dlg.GetFilterIndex();
mov_path = dlg.GetDirectory(); mov_path = dlg.GetDirectory();
if (ret != wxID_OK) if (ret != wxID_OK)
return; return;
systemStartGameRecording(dlg.GetPath()); systemStartGameRecording(dlg.GetPath(), getSupMovFormatsToRecord()[mov_extno]);
} }
EVT_HANDLER_MASK(RecordMovieStopRecording, "Stop game recording", CMDEN_GREC) EVT_HANDLER_MASK(RecordMovieStopRecording, "Stop game recording", CMDEN_GREC)
@ -1347,18 +1391,62 @@ EVT_HANDLER_MASK(RecordMovieStopRecording, "Stop game recording", CMDEN_GREC)
EVT_HANDLER_MASK(PlayMovieStartPlaying, "Start playing movie...", CMDEN_NGREC | CMDEN_NGPLAY) EVT_HANDLER_MASK(PlayMovieStartPlaying, "Start playing movie...", CMDEN_NGREC | CMDEN_NGPLAY)
{ {
static wxString mov_exts;
static int mov_extno;
static wxString mov_path;
if (!mov_exts.size()) {
mov_extno = -1;
int extno = 0;
std::vector<char*> fmts = getSupMovNamesToPlayback();
std::vector<char*> exts = getSupMovExtsToPlayback();
for (size_t i = 0; i < fmts.size(); ++i)
{
mov_exts.append(wxString(fmts[i], wxConvLibc));
mov_exts.append(_(" files ("));
wxString ext(exts[i], wxConvLibc);
ext.Replace(wxT(","), wxT(";*."));
ext.insert(0, wxT("*."));
if (mov_extno < 0 && ext.find(wxT("*.vmv")) != wxString::npos)
mov_extno = extno;
mov_exts.append(ext);
mov_exts.append(wxT(")|"));
mov_exts.append(ext);
mov_exts.append(wxT('|'));
extno++;
}
if (mov_extno < 0)
mov_extno = extno;
}
mov_path = GetGamePath(gopts.recording_dir); mov_path = GetGamePath(gopts.recording_dir);
systemStopGamePlayback(); systemStopGamePlayback();
wxString def_name = panel->game_name() + wxT(".vmv"); wxString def_name = panel->game_name();
wxString extoff = mov_exts;
for (int i = 0; i < mov_extno; i++) {
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
extoff = extoff.Mid(extoff.Find(wxT('|')) + 1);
}
extoff = extoff.Mid(extoff.Find(wxT('|')) + 2); // skip *
def_name += extoff.Left(wxStrcspn(extoff, wxT(";|")));
wxFileDialog dlg(this, _("Select file"), mov_path, def_name, wxFileDialog dlg(this, _("Select file"), mov_path, def_name,
_("VBA Movie files|*.vmv"), wxFD_OPEN | wxFD_FILE_MUST_EXIST); mov_exts, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
dlg.SetFilterIndex(mov_extno);
int ret = ShowModal(&dlg); int ret = ShowModal(&dlg);
mov_extno = dlg.GetFilterIndex();
mov_path = dlg.GetDirectory(); mov_path = dlg.GetDirectory();
if (ret != wxID_OK) if (ret != wxID_OK)
return; return;
systemStartGamePlayback(dlg.GetPath()); systemStartGamePlayback(dlg.GetPath(), getSupMovFormatsToPlayback()[mov_extno]);
} }
EVT_HANDLER_MASK(PlayMovieStopPlaying, "Stop playing movie", CMDEN_GPLAY) EVT_HANDLER_MASK(PlayMovieStopPlaying, "Stop playing movie", CMDEN_GPLAY)

View File

@ -107,17 +107,87 @@ void systemDrawScreen()
// <name>.vmv = keystroke log; all values little-endian ints: // <name>.vmv = keystroke log; all values little-endian ints:
// <version>.32 = 1 // <version>.32 = 1
// for every joypad change (init to 0) and once at end of movie { // for every joypad change (init to 0) and once at end of movie {
// <timestamp>.32 = frames since start of movie // <timestamp>.32 = frames since start of movie in version 1 and frames since the previous change in version 2
// <joypad>.32 = default joypad reading at that time // <joypad>.32 = default joypad reading at that time
// } // }
// <name>.vm0 = saved state // <name>.vm0 = saved state
struct supportedMovie {
MVFormatID formatId;
char const* longName;
char const* exts;
};
const supportedMovie movieSupportedToRecord[] = {
{ MV_FORMAT_ID_VMV2, "VBA Movie v2, Time Diff Format", "vmv" },
{ MV_FORMAT_ID_VMV1, "VBA Movie v1, Old Version for Compatibility", "vmv" },
};
std::vector<MVFormatID> getSupMovFormatsToRecord()
{
std::vector<MVFormatID> result;
for (auto&& fmt: movieSupportedToRecord)
result.push_back(fmt.formatId);
return result;
}
std::vector<char*> getSupMovNamesToRecord()
{
std::vector<char*> result;
for (auto&& fmt: movieSupportedToRecord)
result.push_back((char*)fmt.longName);
return result;
}
std::vector<char*> getSupMovExtsToRecord()
{
std::vector<char*> result;
for (auto&& fmt: movieSupportedToRecord)
result.push_back((char*)fmt.exts);
return result;
}
const supportedMovie movieSupportedToPlayback[] = {
{ MV_FORMAT_ID_VMV, "VBA Movie", "vmv" },
};
std::vector<MVFormatID> getSupMovFormatsToPlayback()
{
std::vector<MVFormatID> result;
for (auto&& fmt: movieSupportedToPlayback)
result.push_back(fmt.formatId);
return result;
}
std::vector<char*> getSupMovNamesToPlayback()
{
std::vector<char*> result;
for (auto&& fmt: movieSupportedToPlayback)
result.push_back((char*)fmt.longName);
return result;
}
std::vector<char*> getSupMovExtsToPlayback()
{
std::vector<char*> result;
for (auto&& fmt: movieSupportedToPlayback)
result.push_back((char*)fmt.exts);
return result;
}
const MVFormatID VMVFormatVersions[] = {
MV_FORMAT_ID_VMV,
MV_FORMAT_ID_VMV1,
MV_FORMAT_ID_VMV2,
};
enum MVFormatID recording_format;
wxFFile game_file; wxFFile game_file;
bool game_recording, game_playback; bool game_recording, game_playback;
uint32_t game_frame; uint32_t game_frame;
uint32_t game_joypad; uint32_t game_joypad;
void systemStartGameRecording(const wxString& fname) void systemStartGameRecording(const wxString& fname, MVFormatID format)
{ {
GameArea* panel = wxGetApp().frame->GetPanel(); GameArea* panel = wxGetApp().frame->GetPanel();
@ -129,11 +199,16 @@ void systemStartGameRecording(const wxString& fname)
systemStopGamePlayback(); systemStopGamePlayback();
wxString fn = fname; wxString fn = fname;
recording_format = format;
if (fn.size() < 4 || !wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".vmv"), false)) if (fn.size() < 4 || !wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".vmv"), false))
fn.append(wxT(".vmv")); fn.append(wxT(".vmv"));
uint32_t version = 1; uint32_t version = 1;
if (recording_format == MV_FORMAT_ID_VMV2)
version = 2;
if (!game_file.Open(fn, wxT("wb")) || game_file.Write(&version, sizeof(version)) != sizeof(version)) { if (!game_file.Open(fn, wxT("wb")) || game_file.Write(&version, sizeof(version)) != sizeof(version)) {
wxLogError(_("Cannot open output file %s"), fname.c_str()); wxLogError(_("Cannot open output file %s"), fname.c_str());
return; return;
@ -173,7 +248,7 @@ void systemStopGameRecording()
uint32_t game_next_frame, game_next_joypad; uint32_t game_next_frame, game_next_joypad;
void systemStartGamePlayback(const wxString& fname) void systemStartGamePlayback(const wxString& fname, MVFormatID format)
{ {
GameArea* panel = wxGetApp().frame->GetPanel(); GameArea* panel = wxGetApp().frame->GetPanel();
@ -190,16 +265,20 @@ void systemStartGamePlayback(const wxString& fname)
systemStopGamePlayback(); systemStopGamePlayback();
wxString fn = fname; wxString fn = fname;
recording_format = format;
if (fn.size() < 4 || !wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".vmv"), false)) if (fn.size() < 4 || !wxString(fn.substr(fn.size() - 4)).IsSameAs(wxT(".vmv"), false))
fn.append(wxT(".vmv")); fn.append(wxT(".vmv"));
uint32_t version; uint32_t version;
if (!game_file.Open(fn, wxT("rb")) || game_file.Read(&version, sizeof(version)) != sizeof(version) || wxUINT32_SWAP_ON_BE(version) != 1) { if (!game_file.Open(fn, wxT("rb")) || game_file.Read(&version, sizeof(version)) != sizeof(version) || wxUINT32_SWAP_ON_BE(version) < 1 || wxUINT32_SWAP_ON_BE(version) > 2) {
wxLogError(_("Cannot open recording file %s"), fname.c_str()); wxLogError(_("Cannot open recording file %s"), fname.c_str());
return; return;
} }
recording_format = VMVFormatVersions[version];
uint32_t gf, jp; uint32_t gf, jp;
if (game_file.Read(&gf, sizeof(gf)) != sizeof(gf) || game_file.Read(&jp, sizeof(jp)) != sizeof(jp)) { if (game_file.Read(&gf, sizeof(gf)) != sizeof(gf) || game_file.Read(&jp, sizeof(jp)) != sizeof(jp)) {
@ -310,22 +389,52 @@ uint32_t systemReadJoypad(int joy)
game_recording = false; game_recording = false;
wxLogError(_("Error writing game recording")); wxLogError(_("Error writing game recording"));
} }
if (recording_format == MV_FORMAT_ID_VMV2)
game_frame = 0;
} }
} else if (game_playback) { } else if (game_playback) {
while (game_frame >= game_next_frame) { switch (recording_format) {
game_joypad = game_next_joypad; case MV_FORMAT_ID_VMV2:
uint32_t gf, jp; if (game_frame >= game_next_frame) {
game_joypad = game_next_joypad;
uint32_t gf, jp;
if (game_file.Read(&gf, sizeof(gf)) != sizeof(gf) || game_file.Read(&jp, sizeof(jp)) != sizeof(jp)) { if (game_file.Read(&gf, sizeof(gf)) != sizeof(gf) || game_file.Read(&jp, sizeof(jp)) != sizeof(jp)) {
game_file.Close(); game_file.Close();
game_playback = false; game_playback = false;
wxString msg(_("Playback ended")); wxString msg(_("Playback ended"));
systemScreenMessage(msg); systemScreenMessage(msg);
break; break;
}
game_next_frame = wxUINT32_SWAP_ON_BE(gf);
game_next_joypad = wxUINT32_SWAP_ON_BE(jp);
game_frame = 0;
} }
break;
game_next_frame = wxUINT32_SWAP_ON_BE(gf); case MV_FORMAT_ID_VMV1:
game_next_joypad = wxUINT32_SWAP_ON_BE(jp); while (game_frame >= game_next_frame) {
game_joypad = game_next_joypad;
uint32_t gf, jp;
if (game_file.Read(&gf, sizeof(gf)) != sizeof(gf) || game_file.Read(&jp, sizeof(jp)) != sizeof(jp)) {
game_file.Close();
game_playback = false;
wxString msg(_("Playback ended"));
systemScreenMessage(msg);
break;
}
game_next_frame = wxUINT32_SWAP_ON_BE(gf);
game_next_joypad = wxUINT32_SWAP_ON_BE(jp);
}
break;
default:
break;
} }
ret = game_joypad; ret = game_joypad;

View File

@ -794,12 +794,28 @@ extern bool debugStartListen(int port);
extern bool debugWaitSocket(); extern bool debugWaitSocket();
#endif #endif
// supported movie format for game recording
enum MVFormatID {
MV_FORMAT_ID_NONE,
/* movie formats */
MV_FORMAT_ID_VMV,
MV_FORMAT_ID_VMV1,
MV_FORMAT_ID_VMV2,
};
std::vector<MVFormatID> getSupMovFormatsToRecord();
std::vector<char*> getSupMovNamesToRecord();
std::vector<char*> getSupMovExtsToRecord();
std::vector<MVFormatID> getSupMovFormatsToPlayback();
std::vector<char*> getSupMovNamesToPlayback();
std::vector<char*> getSupMovExtsToPlayback();
// perhaps these functions should not be called systemXXX // perhaps these functions should not be called systemXXX
// perhaps they should move to panel.cpp/GameArea // perhaps they should move to panel.cpp/GameArea
// but they must integrate with systemReadJoypad // but they must integrate with systemReadJoypad
void systemStartGameRecording(const wxString& fname); void systemStartGameRecording(const wxString& fname, MVFormatID format);
void systemStopGameRecording(); void systemStopGameRecording();
void systemStartGamePlayback(const wxString& fname); void systemStartGamePlayback(const wxString& fname, MVFormatID format);
void systemStopGamePlayback(); void systemStopGamePlayback();
// true if turbo mode (like pressing turbo button constantly) // true if turbo mode (like pressing turbo button constantly)