Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
|
59e563723d | ||
|
14ad539f9b | ||
|
238b9f0909 |
31 changed files with 655 additions and 256 deletions
|
@ -52,6 +52,8 @@ struct _lsnes_status
|
||||||
bool rtc_valid; //RTC time valid?
|
bool rtc_valid; //RTC time valid?
|
||||||
std::u32string rtc; //RTC time.
|
std::u32string rtc; //RTC time.
|
||||||
std::vector<std::u32string> inputs; //Input display.
|
std::vector<std::u32string> inputs; //Input display.
|
||||||
|
bool vi_valid; //VI count valid?
|
||||||
|
uint64_t vi_counter; //VI counter.
|
||||||
std::map<std::string, std::u32string> mvars; //Memory watches.
|
std::map<std::string, std::u32string> mvars; //Memory watches.
|
||||||
std::map<std::string, std::u32string> lvars; //Lua variables.
|
std::map<std::string, std::u32string> lvars; //Lua variables.
|
||||||
};
|
};
|
||||||
|
|
|
@ -129,6 +129,7 @@ struct emulator_instance
|
||||||
status_updater* supdater;
|
status_updater* supdater;
|
||||||
threads::id emu_thread;
|
threads::id emu_thread;
|
||||||
time_t random_seed_value;
|
time_t random_seed_value;
|
||||||
|
bool vi_prev_frame;
|
||||||
dtor_list D;
|
dtor_list D;
|
||||||
private:
|
private:
|
||||||
emulator_instance(const emulator_instance&);
|
emulator_instance(const emulator_instance&);
|
||||||
|
|
|
@ -45,13 +45,14 @@ std::string translate_name_mprefix(std::string original, int& binary, int save);
|
||||||
extern std::string last_save;
|
extern std::string last_save;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restore the actual core state from quicksave. Only call in rewind callback.
|
* Quicksave state.
|
||||||
*
|
|
||||||
* Parameter state: The state to restore.
|
|
||||||
* Parameter secs: The seconds counter.
|
|
||||||
* Parameter ssecs: The subsecond counter.
|
|
||||||
*/
|
*/
|
||||||
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs);
|
void do_quicksave(moviefile::dynamic_state& dstate, struct movie& mov);
|
||||||
|
/**
|
||||||
|
* Quickload state.
|
||||||
|
*/
|
||||||
|
void do_quickload(moviefile::dynamic_state& dstate, struct movie& mov);
|
||||||
|
|
||||||
|
|
||||||
std::string get_mprefix_for_project();
|
std::string get_mprefix_for_project();
|
||||||
void set_mprefix_for_project(const std::string& pfx);
|
void set_mprefix_for_project(const std::string& pfx);
|
||||||
|
|
|
@ -25,7 +25,8 @@ enum lsnes_movie_tags
|
||||||
TAG_RAMCONTENT = 0xd3ec3770,
|
TAG_RAMCONTENT = 0xd3ec3770,
|
||||||
TAG_ROMHINT = 0x6f715830,
|
TAG_ROMHINT = 0x6f715830,
|
||||||
TAG_BRANCH = 0xf2e60707,
|
TAG_BRANCH = 0xf2e60707,
|
||||||
TAG_BRANCH_NAME = 0x6dcb2155
|
TAG_BRANCH_NAME = 0x6dcb2155,
|
||||||
|
TAG_VICOUNTER = 0x55758e30,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,6 +52,84 @@ struct moviefile
|
||||||
private:
|
private:
|
||||||
branch_extractor* real;
|
branch_extractor* real;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* Dynamic information (savestate).
|
||||||
|
*/
|
||||||
|
struct dynamic_state
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize dynamic state to load defaults.
|
||||||
|
*/
|
||||||
|
dynamic_state();
|
||||||
|
/**
|
||||||
|
* Clear the state.
|
||||||
|
*/
|
||||||
|
void clear_state(int64_t sec, int64_t ssec);
|
||||||
|
/**
|
||||||
|
* Swap state with another.
|
||||||
|
*/
|
||||||
|
void swap_with(dynamic_state& d);
|
||||||
|
/**
|
||||||
|
* Contents of SRAM.
|
||||||
|
*/
|
||||||
|
std::map<std::string, std::vector<char>> sram;
|
||||||
|
/**
|
||||||
|
* Core savestate (if is_savestate is true).
|
||||||
|
*/
|
||||||
|
std::vector<char> savestate; //Savestate to load (if is_savestate is true).
|
||||||
|
/**
|
||||||
|
* Host memory (if is_savestate is true).
|
||||||
|
*/
|
||||||
|
std::vector<char> host_memory;
|
||||||
|
/**
|
||||||
|
* Screenshot (if is_savestate is true).
|
||||||
|
*/
|
||||||
|
std::vector<char> screenshot;
|
||||||
|
/**
|
||||||
|
* Current frame (if is_savestate is true).
|
||||||
|
*/
|
||||||
|
uint64_t save_frame;
|
||||||
|
/**
|
||||||
|
* Number of lagged frames (if is_savestate is true).
|
||||||
|
*/
|
||||||
|
uint64_t lagged_frames;
|
||||||
|
/**
|
||||||
|
* Poll counters (if is_savestate is true).
|
||||||
|
*/
|
||||||
|
std::vector<uint32_t> pollcounters;
|
||||||
|
/**
|
||||||
|
* Poll flag.
|
||||||
|
*/
|
||||||
|
unsigned poll_flag;
|
||||||
|
/**
|
||||||
|
* Current RTC second.
|
||||||
|
*/
|
||||||
|
int64_t rtc_second;
|
||||||
|
/**
|
||||||
|
* Current RTC subsecond.
|
||||||
|
*/
|
||||||
|
int64_t rtc_subsecond;
|
||||||
|
/**
|
||||||
|
* Active macros at savestate.
|
||||||
|
*/
|
||||||
|
std::map<std::string, uint64_t> active_macros;
|
||||||
|
/**
|
||||||
|
* VI counters valid.
|
||||||
|
*/
|
||||||
|
bool vi_valid;
|
||||||
|
/**
|
||||||
|
* VI counter.
|
||||||
|
*/
|
||||||
|
uint64_t vi_counter;
|
||||||
|
/**
|
||||||
|
* VI counter for this frame.
|
||||||
|
*/
|
||||||
|
uint32_t vi_this_frame;
|
||||||
|
/**
|
||||||
|
* Movie pointer. Only used for quicksave/quickload.
|
||||||
|
*/
|
||||||
|
uint64_t movie_ptr;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* This constructor construct movie structure with default settings.
|
* This constructor construct movie structure with default settings.
|
||||||
*
|
*
|
||||||
|
@ -157,41 +235,13 @@ struct moviefile
|
||||||
*/
|
*/
|
||||||
bool is_savestate;
|
bool is_savestate;
|
||||||
/**
|
/**
|
||||||
* Contents of SRAM on time of savestate (if is_savestate is true).
|
* The dynamic state.
|
||||||
*/
|
*/
|
||||||
std::map<std::string, std::vector<char>> sram;
|
dynamic_state dynamic;
|
||||||
/**
|
|
||||||
* Core savestate (if is_savestate is true).
|
|
||||||
*/
|
|
||||||
std::vector<char> savestate; //Savestate to load (if is_savestate is true).
|
|
||||||
/**
|
/**
|
||||||
* Anchoring core savestate (if not empty).
|
* Anchoring core savestate (if not empty).
|
||||||
*/
|
*/
|
||||||
std::vector<char> anchor_savestate;
|
std::vector<char> anchor_savestate;
|
||||||
/**
|
|
||||||
* Host memory (if is_savestate is true).
|
|
||||||
*/
|
|
||||||
std::vector<char> host_memory;
|
|
||||||
/**
|
|
||||||
* Screenshot (if is_savestate is true).
|
|
||||||
*/
|
|
||||||
std::vector<char> screenshot;
|
|
||||||
/**
|
|
||||||
* Current frame (if is_savestate is true).
|
|
||||||
*/
|
|
||||||
uint64_t save_frame;
|
|
||||||
/**
|
|
||||||
* Number of lagged frames (if is_savestate is true).
|
|
||||||
*/
|
|
||||||
uint64_t lagged_frames;
|
|
||||||
/**
|
|
||||||
* Poll counters (if is_savestate is true).
|
|
||||||
*/
|
|
||||||
std::vector<uint32_t> pollcounters;
|
|
||||||
/**
|
|
||||||
* Poll flag.
|
|
||||||
*/
|
|
||||||
unsigned poll_flag;
|
|
||||||
/**
|
/**
|
||||||
* Compressed rrdata.
|
* Compressed rrdata.
|
||||||
*/
|
*/
|
||||||
|
@ -204,14 +254,6 @@ struct moviefile
|
||||||
* Branches.
|
* Branches.
|
||||||
*/
|
*/
|
||||||
std::map<std::string, portctrl::frame_vector> branches;
|
std::map<std::string, portctrl::frame_vector> branches;
|
||||||
/**
|
|
||||||
* Current RTC second.
|
|
||||||
*/
|
|
||||||
int64_t rtc_second;
|
|
||||||
/**
|
|
||||||
* Current RTC subsecond.
|
|
||||||
*/
|
|
||||||
int64_t rtc_subsecond;
|
|
||||||
/**
|
/**
|
||||||
* Movie starting RTC second.
|
* Movie starting RTC second.
|
||||||
*/
|
*/
|
||||||
|
@ -232,10 +274,6 @@ struct moviefile
|
||||||
* Subtitles.
|
* Subtitles.
|
||||||
*/
|
*/
|
||||||
std::map<moviefile_subtiming, std::string> subtitles;
|
std::map<moviefile_subtiming, std::string> subtitles;
|
||||||
/**
|
|
||||||
* Active macros at savestate.
|
|
||||||
*/
|
|
||||||
std::map<std::string, uint64_t> active_macros;
|
|
||||||
/**
|
/**
|
||||||
* Get number of frames in movie.
|
* Get number of frames in movie.
|
||||||
*
|
*
|
||||||
|
|
|
@ -109,8 +109,9 @@ extern "C" {
|
||||||
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
|
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
|
||||||
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
|
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
|
||||||
#define LSNES_CORE_CAP1_LIGHTGUN 0x00020000U
|
#define LSNES_CORE_CAP1_LIGHTGUN 0x00020000U
|
||||||
|
//Core signals type extensions #1 (VFR flag). Only supported if emu_flags1 >= 3
|
||||||
|
#define LSNES_CORE_CAP1_TYPEEXT1 0x00040000U
|
||||||
//Reserved capabilities.
|
//Reserved capabilities.
|
||||||
#define LSNES_CORE_CAP1_RESERVED18 0x00040000U
|
|
||||||
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
|
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
|
||||||
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
|
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
|
||||||
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
|
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
|
||||||
|
@ -379,6 +380,9 @@ struct lsnes_core_get_type_info
|
||||||
struct lsnes_core_get_type_info_romimage* images;
|
struct lsnes_core_get_type_info_romimage* images;
|
||||||
//Output: List of settings. Terminated by setting with NULL iname.
|
//Output: List of settings. Terminated by setting with NULL iname.
|
||||||
struct lsnes_core_get_type_info_param* settings;
|
struct lsnes_core_get_type_info_param* settings;
|
||||||
|
//Output: Nonzero if input and output framerates should be decoupled.
|
||||||
|
//Present only if LSNES_CORE_CAP1_TYPEEXT1 is set.
|
||||||
|
int is_vfr;
|
||||||
};
|
};
|
||||||
|
|
||||||
//Request 3: Request information about region.
|
//Request 3: Request information about region.
|
||||||
|
|
|
@ -619,6 +619,7 @@ public:
|
||||||
void debug_reset() { core->debug_reset(); }
|
void debug_reset() { core->debug_reset(); }
|
||||||
bool isnull() { return core->isnull(); }
|
bool isnull() { return core->isnull(); }
|
||||||
bool safe_to_unload(loadlib::module& mod) { return core->safe_to_unload(mod); }
|
bool safe_to_unload(loadlib::module& mod) { return core->safe_to_unload(mod); }
|
||||||
|
bool is_vfr() { return t_is_vfr(); }
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Load a ROM slot set. Changes the ROM currently loaded for core.
|
* Load a ROM slot set. Changes the ROM currently loaded for core.
|
||||||
|
@ -638,6 +639,10 @@ protected:
|
||||||
* Returns: The controller configuration.
|
* Returns: The controller configuration.
|
||||||
*/
|
*/
|
||||||
virtual controller_set t_controllerconfig(std::map<std::string, std::string>& settings) = 0;
|
virtual controller_set t_controllerconfig(std::map<std::string, std::string>& settings) = 0;
|
||||||
|
/**
|
||||||
|
* Is VFR (defaults to false).
|
||||||
|
*/
|
||||||
|
virtual bool t_is_vfr();
|
||||||
private:
|
private:
|
||||||
core_type(const core_type&);
|
core_type(const core_type&);
|
||||||
core_type& operator=(const core_type&);
|
core_type& operator=(const core_type&);
|
||||||
|
|
|
@ -73,8 +73,7 @@ struct lua_state
|
||||||
void callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw();
|
void callback_snoop_input(uint32_t port, uint32_t controller, uint32_t index, short value) throw();
|
||||||
void callback_quit() throw();
|
void callback_quit() throw();
|
||||||
void callback_keyhook(const std::string& key, keyboard::key& p) throw();
|
void callback_keyhook(const std::string& key, keyboard::key& p) throw();
|
||||||
void callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov,
|
void callback_do_unsafe_rewind(movie& mov, void* u);
|
||||||
void* u);
|
|
||||||
bool callback_do_button(uint32_t port, uint32_t controller, uint32_t index, const char* type);
|
bool callback_do_button(uint32_t port, uint32_t controller, uint32_t index, const char* type);
|
||||||
void callback_movie_lost(const char* what);
|
void callback_movie_lost(const char* what);
|
||||||
void callback_do_latch(std::list<std::string>& args);
|
void callback_do_latch(std::list<std::string>& args);
|
||||||
|
|
|
@ -3,22 +3,16 @@
|
||||||
|
|
||||||
#include "library/lua-base.hpp"
|
#include "library/lua-base.hpp"
|
||||||
#include "library/string.hpp"
|
#include "library/string.hpp"
|
||||||
|
#include "core/moviefile.hpp"
|
||||||
|
|
||||||
struct lua_unsaferewind
|
struct lua_unsaferewind
|
||||||
{
|
{
|
||||||
lua_unsaferewind(lua::state& L);
|
lua_unsaferewind(lua::state& L);
|
||||||
static size_t overcommit() { return 0; }
|
static size_t overcommit() { return 0; }
|
||||||
std::vector<char> state;
|
moviefile::dynamic_state dstate;
|
||||||
uint64_t frame;
|
|
||||||
uint64_t lag;
|
|
||||||
uint64_t ptr;
|
|
||||||
uint64_t secs;
|
|
||||||
uint64_t ssecs;
|
|
||||||
std::vector<uint32_t> pollcounters;
|
|
||||||
std::vector<char> hostmemory;
|
|
||||||
std::string print()
|
std::string print()
|
||||||
{
|
{
|
||||||
return (stringfmt() << "to frame " << frame).str();
|
return (stringfmt() << "to frame " << dstate.save_frame).str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
12
lua.lyx
12
lua.lyx
|
@ -6264,6 +6264,18 @@ Syntax: number movie.currentframe()
|
||||||
Return number of current frame.
|
Return number of current frame.
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Subsection
|
||||||
|
movie.currentvi: Get current VI number
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Itemize
|
||||||
|
Syntax: number movie.currentvi()
|
||||||
|
\end_layout
|
||||||
|
|
||||||
|
\begin_layout Standard
|
||||||
|
Return number of current VI.
|
||||||
|
\end_layout
|
||||||
|
|
||||||
\begin_layout Subsection
|
\begin_layout Subsection
|
||||||
movie.framecount: Get move frame count
|
movie.framecount: Get move frame count
|
||||||
\end_layout
|
\end_layout
|
||||||
|
|
|
@ -147,7 +147,7 @@ void status_updater::update()
|
||||||
_status.speed = (unsigned)(100 * framerate.get_realized_multiplier() + 0.5);
|
_status.speed = (unsigned)(100 * framerate.get_realized_multiplier() + 0.5);
|
||||||
|
|
||||||
if(mlogic && !runmode.is_corrupt()) {
|
if(mlogic && !runmode.is_corrupt()) {
|
||||||
time_t timevalue = static_cast<time_t>(mlogic.get_mfile().rtc_second);
|
time_t timevalue = static_cast<time_t>(mlogic.get_mfile().dynamic.rtc_second);
|
||||||
struct tm* time_decompose = gmtime(&timevalue);
|
struct tm* time_decompose = gmtime(&timevalue);
|
||||||
char datebuffer[512];
|
char datebuffer[512];
|
||||||
strftime(datebuffer, 511, "%Y%m%d(%a)T%H%M%S", time_decompose);
|
strftime(datebuffer, 511, "%Y%m%d(%a)T%H%M%S", time_decompose);
|
||||||
|
@ -195,6 +195,9 @@ void status_updater::update()
|
||||||
}
|
}
|
||||||
_status.inputs.push_back(_buffer);
|
_status.inputs.push_back(_buffer);
|
||||||
}
|
}
|
||||||
|
//VI counts. Only display if type is VFR.
|
||||||
|
_status.vi_valid = mlogic.get_mfile().gametype->get_type().is_vfr();
|
||||||
|
_status.vi_counter = mlogic.get_mfile().dynamic.vi_counter;
|
||||||
//Lua variables.
|
//Lua variables.
|
||||||
_status.lvars = lua2.get_watch_vars();
|
_status.lvars = lua2.get_watch_vars();
|
||||||
//Memory watches.
|
//Memory watches.
|
||||||
|
|
|
@ -122,6 +122,7 @@ emulator_instance::emulator_instance()
|
||||||
settings->add_set(lsnes_setgrp);
|
settings->add_set(lsnes_setgrp);
|
||||||
dispatch->set_error_streams(&messages.getstream());
|
dispatch->set_error_streams(&messages.getstream());
|
||||||
random_seed_value = 0;
|
random_seed_value = 0;
|
||||||
|
vi_prev_frame = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
emulator_instance::~emulator_instance()
|
emulator_instance::~emulator_instance()
|
||||||
|
|
|
@ -97,7 +97,8 @@ portctrl::frame movie_logic::update_controls(bool subframe, bool forced) throw(s
|
||||||
if(core.lua2->requests_subframe_paint)
|
if(core.lua2->requests_subframe_paint)
|
||||||
core.fbuf->redraw_framebuffer();
|
core.fbuf->redraw_framebuffer();
|
||||||
|
|
||||||
if(subframe) {
|
//If VI did not occur last frame, do subframe anyway.
|
||||||
|
if(subframe || !core.vi_prev_frame) {
|
||||||
if(core.runmode->is_advance_subframe()) {
|
if(core.runmode->is_advance_subframe()) {
|
||||||
//Note that platform::wait() may change value of cancel flag.
|
//Note that platform::wait() may change value of cancel flag.
|
||||||
if(!core.runmode->test_cancel()) {
|
if(!core.runmode->test_cancel()) {
|
||||||
|
@ -163,6 +164,8 @@ portctrl::frame movie_logic::update_controls(bool subframe, bool forced) throw(s
|
||||||
}
|
}
|
||||||
core.runmode->set_point(emulator_runmode::P_START);
|
core.runmode->set_point(emulator_runmode::P_START);
|
||||||
core.supdater->update();
|
core.supdater->update();
|
||||||
|
//Clear the previous VI flag, so next poll will be subframe.
|
||||||
|
core.vi_prev_frame = false;
|
||||||
}
|
}
|
||||||
platform::flush_command_queue();
|
platform::flush_command_queue();
|
||||||
portctrl::frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
|
portctrl::frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
|
||||||
|
@ -249,10 +252,10 @@ public:
|
||||||
if(!*core.mlogic)
|
if(!*core.mlogic)
|
||||||
return;
|
return;
|
||||||
auto& m = core.mlogic->get_mfile();
|
auto& m = core.mlogic->get_mfile();
|
||||||
m.rtc_subsecond += increment;
|
m.dynamic.rtc_subsecond += increment;
|
||||||
while(m.rtc_subsecond >= per_second) {
|
while(m.dynamic.rtc_subsecond >= per_second) {
|
||||||
m.rtc_second++;
|
m.dynamic.rtc_second++;
|
||||||
m.rtc_subsecond -= per_second;
|
m.dynamic.rtc_subsecond -= per_second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,7 +272,7 @@ public:
|
||||||
time_t get_time()
|
time_t get_time()
|
||||||
{
|
{
|
||||||
auto& core = CORE();
|
auto& core = CORE();
|
||||||
return *core.mlogic ? core.mlogic->get_mfile().rtc_second : 0;
|
return *core.mlogic ? core.mlogic->get_mfile().dynamic.rtc_second : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t get_randomseed()
|
time_t get_randomseed()
|
||||||
|
@ -280,7 +283,14 @@ public:
|
||||||
void output_frame(framebuffer::raw& screen, uint32_t fps_n, uint32_t fps_d)
|
void output_frame(framebuffer::raw& screen, uint32_t fps_n, uint32_t fps_d)
|
||||||
{
|
{
|
||||||
auto& core = CORE();
|
auto& core = CORE();
|
||||||
core.lua2->callback_do_frame_emulated();
|
//VI occured.
|
||||||
|
auto& mfile = core.mlogic->get_mfile();
|
||||||
|
mfile.dynamic.vi_this_frame++;
|
||||||
|
mfile.dynamic.vi_counter++;
|
||||||
|
|
||||||
|
//This is done elsewhere for VFR.
|
||||||
|
if(!mfile.gametype->get_type().is_vfr())
|
||||||
|
core.lua2->callback_do_frame_emulated();
|
||||||
core.runmode->set_point(emulator_runmode::P_VIDEO);
|
core.runmode->set_point(emulator_runmode::P_VIDEO);
|
||||||
core.fbuf->redraw_framebuffer(screen, false, true);
|
core.fbuf->redraw_framebuffer(screen, false, true);
|
||||||
auto rate = core.rom->get_audio_rate();
|
auto rate = core.rom->get_audio_rate();
|
||||||
|
@ -686,7 +696,7 @@ namespace
|
||||||
|
|
||||||
//If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
|
//If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
|
||||||
//failing.
|
//failing.
|
||||||
int handle_load()
|
int _handle_load()
|
||||||
{
|
{
|
||||||
auto& core = CORE();
|
auto& core = CORE();
|
||||||
std::string old_project = *core.mlogic ? core.mlogic->get_mfile().projectid : "";
|
std::string old_project = *core.mlogic ? core.mlogic->get_mfile().projectid : "";
|
||||||
|
@ -695,8 +705,7 @@ jumpback:
|
||||||
if(!*core.mlogic)
|
if(!*core.mlogic)
|
||||||
return 0;
|
return 0;
|
||||||
uint64_t t = framerate_regulator::get_utime();
|
uint64_t t = framerate_regulator::get_utime();
|
||||||
std::vector<char> s;
|
core.lua2->callback_do_unsafe_rewind(core.mlogic->get_movie(), unsafe_rewind_obj);
|
||||||
core.lua2->callback_do_unsafe_rewind(s, 0, 0, core.mlogic->get_movie(), unsafe_rewind_obj);
|
|
||||||
core.dispatch->mode_change(false);
|
core.dispatch->mode_change(false);
|
||||||
do_unsafe_rewind = false;
|
do_unsafe_rewind = false;
|
||||||
core.mlogic->get_mfile().is_savestate = true;
|
core.mlogic->get_mfile().is_savestate = true;
|
||||||
|
@ -772,6 +781,17 @@ nothing_to_do:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int handle_load()
|
||||||
|
{
|
||||||
|
auto& core = CORE();
|
||||||
|
int r = _handle_load();
|
||||||
|
if(r > 0) {
|
||||||
|
//Set the vi prev frame flag, as not to mess up frame advance at first oppurtunity.
|
||||||
|
core.vi_prev_frame = true;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
//If there are pending saves, perform them.
|
//If there are pending saves, perform them.
|
||||||
void handle_saves()
|
void handle_saves()
|
||||||
{
|
{
|
||||||
|
@ -787,11 +807,7 @@ nothing_to_do:
|
||||||
}
|
}
|
||||||
if(do_unsafe_rewind && !unsafe_rewind_obj) {
|
if(do_unsafe_rewind && !unsafe_rewind_obj) {
|
||||||
uint64_t t = framerate_regulator::get_utime();
|
uint64_t t = framerate_regulator::get_utime();
|
||||||
std::vector<char> s = core.rom->save_core_state(true);
|
core.lua2->callback_do_unsafe_rewind(core.mlogic->get_movie(), NULL);
|
||||||
uint64_t secs = core.mlogic->get_mfile().rtc_second;
|
|
||||||
uint64_t ssecs = core.mlogic->get_mfile().rtc_subsecond;
|
|
||||||
core.lua2->callback_do_unsafe_rewind(s, secs, ssecs, core.mlogic->get_movie(),
|
|
||||||
NULL);
|
|
||||||
do_unsafe_rewind = false;
|
do_unsafe_rewind = false;
|
||||||
messages << "Rewind point set in " << (framerate_regulator::get_utime() - t)
|
messages << "Rewind point set in " << (framerate_regulator::get_utime() - t)
|
||||||
<< " usec." << std::endl;
|
<< " usec." << std::endl;
|
||||||
|
@ -865,6 +881,10 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
||||||
core.runmode->set_pause_cond(initial.start_paused);
|
core.runmode->set_pause_cond(initial.start_paused);
|
||||||
platform::set_paused(core.runmode->is_paused());
|
platform::set_paused(core.runmode->is_paused());
|
||||||
stop_at_frame_active = false;
|
stop_at_frame_active = false;
|
||||||
|
//Always set VI last frame flag when loading any savestate or movie, as not to distrupt frame advance at
|
||||||
|
//first oppurtunity. And since we loadstated above, VI count this frame is set apporiately.
|
||||||
|
core.vi_prev_frame = true;
|
||||||
|
|
||||||
|
|
||||||
core.lua2->run_startup_scripts();
|
core.lua2->run_startup_scripts();
|
||||||
|
|
||||||
|
@ -874,7 +894,9 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
||||||
just_did_loadstate = first_round;
|
just_did_loadstate = first_round;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
core.framerate->ack_frame_tick(framerate_regulator::get_utime());
|
//Only consider frames with VI real frames.
|
||||||
|
if(core.vi_prev_frame)
|
||||||
|
core.framerate->ack_frame_tick(framerate_regulator::get_utime());
|
||||||
core.runmode->decay_skiplag();
|
core.runmode->decay_skiplag();
|
||||||
|
|
||||||
if(!first_round) {
|
if(!first_round) {
|
||||||
|
@ -921,9 +943,20 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
||||||
just_did_loadstate = false;
|
just_did_loadstate = false;
|
||||||
}
|
}
|
||||||
core.dbg->do_callback_frame(core.mlogic->get_movie().get_current_frame(), false);
|
core.dbg->do_callback_frame(core.mlogic->get_movie().get_current_frame(), false);
|
||||||
|
//VI count this frame should be 0 here.
|
||||||
core.rom->emulate();
|
core.rom->emulate();
|
||||||
|
//This is done elsewhere for non-VFR.
|
||||||
|
if(core.mlogic->get_mfile().gametype->get_type().is_vfr())
|
||||||
|
core.lua2->callback_do_frame_emulated();
|
||||||
|
//Reset the vi this frame count to 0, as it is only meaningful inside emulate.
|
||||||
|
//Also, if VIs occured, set flag informing that so frame advance can stop only on output frames.
|
||||||
|
auto& VIs = core.mlogic->get_mfile().dynamic.vi_this_frame;
|
||||||
|
if(VIs > 0)
|
||||||
|
core.vi_prev_frame = true;
|
||||||
|
VIs = 0;
|
||||||
random_mix_timing_entropy();
|
random_mix_timing_entropy();
|
||||||
if(core.runmode->is_freerunning())
|
//Only wait if VI, to get about proper framerate.
|
||||||
|
if(core.runmode->is_freerunning() && core.vi_prev_frame)
|
||||||
platform::wait(core.framerate->to_wait_frame(framerate_regulator::get_utime()));
|
platform::wait(core.framerate->to_wait_frame(framerate_regulator::get_utime()));
|
||||||
first_round = false;
|
first_round = false;
|
||||||
core.lua2->callback_do_frame();
|
core.lua2->callback_do_frame();
|
||||||
|
|
|
@ -230,23 +230,23 @@ void do_save_state(const std::string& filename, int binary) throw(std::bad_alloc
|
||||||
try {
|
try {
|
||||||
uint64_t origtime = framerate_regulator::get_utime();
|
uint64_t origtime = framerate_regulator::get_utime();
|
||||||
target.is_savestate = true;
|
target.is_savestate = true;
|
||||||
target.sram = core.rom->save_sram();
|
target.dynamic.sram = core.rom->save_sram();
|
||||||
for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
|
for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
|
||||||
target.romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
target.romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
||||||
target.romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
target.romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
||||||
target.namehint[i] = core.rom->romimg[i].namehint;
|
target.namehint[i] = core.rom->romimg[i].namehint;
|
||||||
}
|
}
|
||||||
target.savestate = core.rom->save_core_state();
|
target.dynamic.savestate = core.rom->save_core_state();
|
||||||
core.fbuf->get_framebuffer().save(target.screenshot);
|
core.fbuf->get_framebuffer().save(target.dynamic.screenshot);
|
||||||
core.mlogic->get_movie().save_state(target.projectid, target.save_frame,
|
core.mlogic->get_movie().save_state(target.projectid, target.dynamic.save_frame,
|
||||||
target.lagged_frames, target.pollcounters);
|
target.dynamic.lagged_frames, target.dynamic.pollcounters);
|
||||||
target.poll_flag = core.rom->get_pflag();
|
target.dynamic.poll_flag = core.rom->get_pflag();
|
||||||
auto prj = core.project->get();
|
auto prj = core.project->get();
|
||||||
if(prj) {
|
if(prj) {
|
||||||
target.gamename = prj->gamename;
|
target.gamename = prj->gamename;
|
||||||
target.authors = prj->authors;
|
target.authors = prj->authors;
|
||||||
}
|
}
|
||||||
target.active_macros = core.controls->get_macro_frames();
|
target.dynamic.active_macros = core.controls->get_macro_frames();
|
||||||
target.save(filename2, SET_savecompression(*core.settings), binary > 0,
|
target.save(filename2, SET_savecompression(*core.settings), binary > 0,
|
||||||
core.mlogic->get_rrdata());
|
core.mlogic->get_rrdata());
|
||||||
uint64_t took = framerate_regulator::get_utime() - origtime;
|
uint64_t took = framerate_regulator::get_utime() - origtime;
|
||||||
|
@ -289,7 +289,6 @@ void do_save_movie(const std::string& filename, int binary) throw(std::bad_alloc
|
||||||
target.gamename = prj->gamename;
|
target.gamename = prj->gamename;
|
||||||
target.authors = prj->authors;
|
target.authors = prj->authors;
|
||||||
}
|
}
|
||||||
target.active_macros.clear();
|
|
||||||
target.save(filename2, SET_savecompression(*core.settings), binary > 0,
|
target.save(filename2, SET_savecompression(*core.settings), binary > 0,
|
||||||
core.mlogic->get_rrdata());
|
core.mlogic->get_rrdata());
|
||||||
uint64_t took = framerate_regulator::get_utime() - origtime;
|
uint64_t took = framerate_regulator::get_utime() - origtime;
|
||||||
|
@ -422,16 +421,17 @@ namespace
|
||||||
//Load the savestate and movie state.
|
//Load the savestate and movie state.
|
||||||
//Set the core ports in order to avoid port state being reinitialized when loading.
|
//Set the core ports in order to avoid port state being reinitialized when loading.
|
||||||
core.controls->set_ports(portset);
|
core.controls->set_ports(portset);
|
||||||
core.rom->load_core_state(_movie.savestate);
|
core.rom->load_core_state(_movie.dynamic.savestate);
|
||||||
core.rom->set_pflag(_movie.poll_flag);
|
core.rom->set_pflag(_movie.dynamic.poll_flag);
|
||||||
core.controls->set_macro_frames(_movie.active_macros);
|
core.controls->set_macro_frames(_movie.dynamic.active_macros);
|
||||||
} else {
|
} else {
|
||||||
//Reload the ROM in order to rewind to the beginning.
|
//Reload the ROM in order to rewind to the beginning.
|
||||||
core.rom->load(_movie.settings, _movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
core.rom->load(_movie.settings, _movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||||
|
//Reset things to beginning.
|
||||||
|
_movie.is_savestate = false;
|
||||||
|
_movie.dynamic.clear_state(_movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||||
//Load the SRAM and volatile RAM. Or anchor savestate if any.
|
//Load the SRAM and volatile RAM. Or anchor savestate if any.
|
||||||
core.controls->set_ports(portset);
|
core.controls->set_ports(portset);
|
||||||
_movie.rtc_second = _movie.movie_rtc_second;
|
|
||||||
_movie.rtc_subsecond = _movie.movie_rtc_subsecond;
|
|
||||||
if(!_movie.anchor_savestate.empty()) {
|
if(!_movie.anchor_savestate.empty()) {
|
||||||
core.rom->load_core_state(_movie.anchor_savestate);
|
core.rom->load_core_state(_movie.anchor_savestate);
|
||||||
} else {
|
} else {
|
||||||
|
@ -443,6 +443,16 @@ namespace
|
||||||
core.controls->set_macro_frames(std::map<std::string, uint64_t>());
|
core.controls->set_macro_frames(std::map<std::string, uint64_t>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Clear the data that should be cleared when movie is at beginning.
|
||||||
|
void clear_runtime_movie_data(emulator_instance& core)
|
||||||
|
{
|
||||||
|
auto& mf = core.mlogic->get_mfile();
|
||||||
|
mf.is_savestate = false;
|
||||||
|
mf.dynamic.clear_state(mf.movie_rtc_second, mf.movie_rtc_subsecond);
|
||||||
|
core.mlogic->get_movie().reset_state();
|
||||||
|
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
||||||
|
@ -474,10 +484,7 @@ void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
||||||
core.mlogic->get_mfile().romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
core.mlogic->get_mfile().romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
||||||
core.mlogic->get_mfile().romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
core.mlogic->get_mfile().romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
||||||
}
|
}
|
||||||
core.mlogic->get_mfile().is_savestate = false;
|
clear_runtime_movie_data(core);
|
||||||
core.mlogic->get_mfile().host_memory.clear();
|
|
||||||
core.mlogic->get_movie().reset_state();
|
|
||||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
|
||||||
core.lua2->callback_do_rewind();
|
core.lua2->callback_do_rewind();
|
||||||
} catch(std::bad_alloc& e) {
|
} catch(std::bad_alloc& e) {
|
||||||
OOM_panic();
|
OOM_panic();
|
||||||
|
@ -490,23 +497,15 @@ void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
||||||
//The more complicated Read-Write case.
|
//The more complicated Read-Write case.
|
||||||
//We need to create a new movie and movie file.
|
//We need to create a new movie and movie file.
|
||||||
temporary_handle<moviefile> _movie;
|
temporary_handle<moviefile> _movie;
|
||||||
_movie.get()->force_corrupt = false;
|
|
||||||
_movie.get()->gametype = NULL; //Not yet known.
|
|
||||||
_movie.get()->coreversion = core.rom->get_core_identifier();
|
_movie.get()->coreversion = core.rom->get_core_identifier();
|
||||||
_movie.get()->projectid = get_random_hexstring(40);
|
_movie.get()->projectid = get_random_hexstring(40);
|
||||||
_movie.get()->rerecords = "0";
|
|
||||||
_movie.get()->rerecords_mem = 0;
|
|
||||||
for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
|
for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
|
||||||
_movie.get()->namehint[i] = core.rom->romimg[i].namehint;
|
_movie.get()->namehint[i] = core.rom->romimg[i].namehint;
|
||||||
_movie.get()->romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
_movie.get()->romimg_sha256[i] = core.rom->romimg[i].sha_256.read();
|
||||||
_movie.get()->romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
_movie.get()->romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
||||||
}
|
}
|
||||||
_movie.get()->is_savestate = false;
|
_movie.get()->movie_rtc_second = _movie.get()->dynamic.rtc_second;
|
||||||
_movie.get()->save_frame = 0;
|
_movie.get()->movie_rtc_subsecond = _movie.get()->dynamic.rtc_subsecond;
|
||||||
_movie.get()->lagged_frames = 0;
|
|
||||||
_movie.get()->poll_flag = false;
|
|
||||||
_movie.get()->movie_rtc_second = _movie.get()->rtc_second = 1000000000ULL;
|
|
||||||
_movie.get()->movie_rtc_subsecond = _movie.get()->rtc_subsecond = 0;
|
|
||||||
_movie.get()->start_paused = false;
|
_movie.get()->start_paused = false;
|
||||||
_movie.get()->lazy_project_create = true;
|
_movie.get()->lazy_project_create = true;
|
||||||
portctrl::type_set& portset2 = construct_movie_portset(*_movie.get(), *core.rom);
|
portctrl::type_set& portset2 = construct_movie_portset(*_movie.get(), *core.rom);
|
||||||
|
@ -570,10 +569,7 @@ void do_load_rewind() throw(std::bad_alloc, std::runtime_error)
|
||||||
core.dispatch->mode_change(true);
|
core.dispatch->mode_change(true);
|
||||||
try {
|
try {
|
||||||
handle_load_core(core.mlogic->get_mfile(), portset, false);
|
handle_load_core(core.mlogic->get_mfile(), portset, false);
|
||||||
core.mlogic->get_mfile().is_savestate = false;
|
clear_runtime_movie_data(core);
|
||||||
core.mlogic->get_mfile().host_memory.clear();
|
|
||||||
core.mlogic->get_movie().reset_state();
|
|
||||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
|
||||||
core.lua2->callback_do_rewind();
|
core.lua2->callback_do_rewind();
|
||||||
} catch(std::bad_alloc& e) {
|
} catch(std::bad_alloc& e) {
|
||||||
OOM_panic();
|
OOM_panic();
|
||||||
|
@ -605,8 +601,8 @@ void do_load_state_preserve(struct moviefile& _movie)
|
||||||
|
|
||||||
newmovie.get()->load(_movie.rerecords, _movie.projectid, *_movie.input);
|
newmovie.get()->load(_movie.rerecords, _movie.projectid, *_movie.input);
|
||||||
if(will_load_state)
|
if(will_load_state)
|
||||||
newmovie.get()->restore_state(_movie.save_frame, _movie.lagged_frames, _movie.pollcounters, true,
|
newmovie.get()->restore_state(_movie.dynamic.save_frame, _movie.dynamic.lagged_frames,
|
||||||
_movie.input, _movie.projectid);
|
_movie.dynamic.pollcounters, true, _movie.input, _movie.projectid);
|
||||||
|
|
||||||
//Count a rerecord.
|
//Count a rerecord.
|
||||||
if(core.mlogic->get_rrdata().is_lazy() && !_movie.lazy_project_create)
|
if(core.mlogic->get_rrdata().is_lazy() && !_movie.lazy_project_create)
|
||||||
|
@ -627,19 +623,15 @@ void do_load_state_preserve(struct moviefile& _movie)
|
||||||
//Set new movie.
|
//Set new movie.
|
||||||
core.mlogic->set_movie(*(newmovie()), true);
|
core.mlogic->set_movie(*(newmovie()), true);
|
||||||
|
|
||||||
//Some fields MUST be taken from movie or one gets desyncs.
|
//Take dynamic state from new file (to avoid desyncs). If loading movie, it has been cleared.
|
||||||
core.mlogic->get_mfile().is_savestate = _movie.is_savestate;
|
core.mlogic->get_mfile().is_savestate = _movie.is_savestate;
|
||||||
core.mlogic->get_mfile().rtc_second = _movie.rtc_second;
|
core.mlogic->get_mfile().dynamic.swap_with(_movie.dynamic);
|
||||||
core.mlogic->get_mfile().rtc_subsecond = _movie.rtc_subsecond;
|
|
||||||
std::swap(core.mlogic->get_mfile().host_memory, _movie.host_memory);
|
|
||||||
if(!will_load_state)
|
|
||||||
core.mlogic->get_mfile().host_memory.clear();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
//Paint the screen.
|
//Paint the screen.
|
||||||
framebuffer::raw tmp;
|
framebuffer::raw tmp;
|
||||||
if(will_load_state) {
|
if(will_load_state) {
|
||||||
tmp.load(_movie.screenshot);
|
tmp.load(_movie.dynamic.screenshot);
|
||||||
core.fbuf->redraw_framebuffer(tmp);
|
core.fbuf->redraw_framebuffer(tmp);
|
||||||
} else
|
} else
|
||||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||||
|
@ -691,8 +683,8 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
||||||
newmovie.get()->load(_movie.rerecords, _movie.projectid, *_movie.input);
|
newmovie.get()->load(_movie.rerecords, _movie.projectid, *_movie.input);
|
||||||
newmovie.get()->set_pflag_handler(&lsnes_pflag_handler);
|
newmovie.get()->set_pflag_handler(&lsnes_pflag_handler);
|
||||||
if(will_load_state)
|
if(will_load_state)
|
||||||
newmovie.get()->restore_state(_movie.save_frame, _movie.lagged_frames, _movie.pollcounters, true,
|
newmovie.get()->restore_state(_movie.dynamic.save_frame, _movie.dynamic.lagged_frames,
|
||||||
NULL, _movie.projectid);
|
_movie.dynamic.pollcounters, true, NULL, _movie.projectid);
|
||||||
|
|
||||||
//Copy the other branches.
|
//Copy the other branches.
|
||||||
if(lmode != LOAD_STATE_INITIAL && core.mlogic->get_mfile().projectid == _movie.projectid) {
|
if(lmode != LOAD_STATE_INITIAL && core.mlogic->get_mfile().projectid == _movie.projectid) {
|
||||||
|
@ -752,12 +744,6 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
//If loaded a movie, clear the is savestate and rrdata.
|
|
||||||
if(!will_load_state) {
|
|
||||||
_movie.is_savestate = false;
|
|
||||||
_movie.host_memory.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
core.lua2->callback_movie_lost("load");
|
core.lua2->callback_movie_lost("load");
|
||||||
|
|
||||||
//Copy the data.
|
//Copy the data.
|
||||||
|
@ -766,6 +752,15 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
||||||
core.mlogic->set_mfile(_movie, true);
|
core.mlogic->set_mfile(_movie, true);
|
||||||
used = true;
|
used = true;
|
||||||
|
|
||||||
|
//Set up VI counter if none is available.
|
||||||
|
if(!_movie.dynamic.vi_valid) {
|
||||||
|
//If no VI counter available, set it to frame-1 and there have been 0 this frame.
|
||||||
|
uint64_t f = core.mlogic->get_movie().get_current_frame();
|
||||||
|
_movie.dynamic.vi_counter = (f > 0) ? (f - 1) : 0;
|
||||||
|
_movie.dynamic.vi_this_frame = 0;
|
||||||
|
_movie.dynamic.vi_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
set_mprefix(get_mprefix_for_project(core.mlogic->get_mfile().projectid));
|
set_mprefix(get_mprefix_for_project(core.mlogic->get_mfile().projectid));
|
||||||
|
|
||||||
//Activate RW mode if needed.
|
//Activate RW mode if needed.
|
||||||
|
@ -783,7 +778,7 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
||||||
{
|
{
|
||||||
framebuffer::raw tmp;
|
framebuffer::raw tmp;
|
||||||
if(will_load_state) {
|
if(will_load_state) {
|
||||||
tmp.load(_movie.screenshot);
|
tmp.load(_movie.dynamic.screenshot);
|
||||||
core.fbuf->redraw_framebuffer(tmp);
|
core.fbuf->redraw_framebuffer(tmp);
|
||||||
} else
|
} else
|
||||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||||
|
@ -879,18 +874,30 @@ bool do_load_state(const std::string& filename, int lmode)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs)
|
void do_quicksave(moviefile::dynamic_state& dstate, struct movie& mov)
|
||||||
{
|
{
|
||||||
auto& core = CORE();
|
auto& core = CORE();
|
||||||
//Force unlazy rrdata.
|
auto& mf = core.mlogic->get_mfile();
|
||||||
core.mlogic->get_rrdata().read_base(rrdata::filename(core.mlogic->get_mfile().projectid),
|
dstate = mf.dynamic;
|
||||||
false);
|
dstate.savestate = core.rom->save_core_state(true);
|
||||||
core.mlogic->get_rrdata().add((*core.nrrdata)());
|
mov.fast_save(dstate.save_frame, dstate.movie_ptr, dstate.lagged_frames, dstate.pollcounters);
|
||||||
core.mlogic->get_mfile().rtc_second = secs;
|
|
||||||
core.mlogic->get_mfile().rtc_subsecond = ssecs;
|
|
||||||
core.rom->load_core_state(state, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_quickload(moviefile::dynamic_state& dstate, struct movie& mov)
|
||||||
|
{
|
||||||
|
auto& core = CORE();
|
||||||
|
auto& mf = core.mlogic->get_mfile();
|
||||||
|
|
||||||
|
//Force unlazy rrdata.
|
||||||
|
core.mlogic->get_rrdata().read_base(rrdata::filename(core.mlogic->get_mfile().projectid), false);
|
||||||
|
core.mlogic->get_rrdata().add((*core.nrrdata)());
|
||||||
|
|
||||||
|
core.rom->load_core_state(dstate.savestate, true);
|
||||||
|
mov.fast_load(dstate.save_frame, dstate.movie_ptr, dstate.lagged_frames, dstate.pollcounters);
|
||||||
|
mf.dynamic = dstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
rrdata::rrdata()
|
rrdata::rrdata()
|
||||||
: init(false)
|
: init(false)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
void moviefile::brief_info::binary_io(int _stream)
|
void moviefile::brief_info::binary_io(int _stream)
|
||||||
{
|
{
|
||||||
|
bool vi_override = false;
|
||||||
|
|
||||||
binarystream::input in(_stream);
|
binarystream::input in(_stream);
|
||||||
sysregion = in.string();
|
sysregion = in.string();
|
||||||
//Discard the settings.
|
//Discard the settings.
|
||||||
|
@ -32,8 +34,14 @@ void moviefile::brief_info::binary_io(int _stream)
|
||||||
this->corename = s.string_implicit();
|
this->corename = s.string_implicit();
|
||||||
}},{TAG_PROJECT_ID, [this](binarystream::input& s) {
|
}},{TAG_PROJECT_ID, [this](binarystream::input& s) {
|
||||||
this->projectid = s.string_implicit();
|
this->projectid = s.string_implicit();
|
||||||
}},{TAG_SAVESTATE, [this](binarystream::input& s) {
|
}},{TAG_SAVESTATE, [this, &vi_override](binarystream::input& s) {
|
||||||
|
//TAG_VICOUNTER overrides this.
|
||||||
|
if(!vi_override)
|
||||||
|
this->current_frame = s.number();
|
||||||
|
}},{TAG_VICOUNTER, [this, &vi_override](binarystream::input& s) {
|
||||||
|
//TAG_VICOUNTER overrides TAG_SAVESTATE.
|
||||||
this->current_frame = s.number();
|
this->current_frame = s.number();
|
||||||
|
vi_override = true;
|
||||||
}},{TAG_RRDATA, [this](binarystream::input& s) {
|
}},{TAG_RRDATA, [this](binarystream::input& s) {
|
||||||
std::vector<char> c_rrdata;
|
std::vector<char> c_rrdata;
|
||||||
s.blob_implicit(c_rrdata);
|
s.blob_implicit(c_rrdata);
|
||||||
|
@ -118,28 +126,29 @@ void moviefile::binary_io(int _stream, rrdata_set& rrd) throw(std::bad_alloc, st
|
||||||
});
|
});
|
||||||
if(is_savestate) {
|
if(is_savestate) {
|
||||||
out.extension(TAG_SAVESTATE, [this](binarystream::output& s) {
|
out.extension(TAG_SAVESTATE, [this](binarystream::output& s) {
|
||||||
s.number(this->save_frame);
|
s.number(this->dynamic.save_frame);
|
||||||
s.number(this->lagged_frames);
|
s.number(this->dynamic.lagged_frames);
|
||||||
s.number(this->rtc_second);
|
s.number(this->dynamic.rtc_second);
|
||||||
s.number(this->rtc_subsecond);
|
s.number(this->dynamic.rtc_subsecond);
|
||||||
s.number(this->pollcounters.size());
|
s.number(this->dynamic.pollcounters.size());
|
||||||
for(auto i : this->pollcounters)
|
for(auto i : this->dynamic.pollcounters)
|
||||||
s.number32(i);
|
s.number32(i);
|
||||||
s.byte(this->poll_flag ? 0x01 : 0x00);
|
s.byte(this->dynamic.poll_flag ? 0x01 : 0x00);
|
||||||
s.blob_implicit(this->savestate);
|
s.blob_implicit(this->dynamic.savestate);
|
||||||
}, true, out.numberbytes(save_frame) + out.numberbytes(lagged_frames) + out.numberbytes(rtc_second) +
|
}, true, out.numberbytes(dynamic.save_frame) + out.numberbytes(dynamic.lagged_frames) +
|
||||||
out.numberbytes(rtc_subsecond) + out.numberbytes(pollcounters.size()) +
|
out.numberbytes(dynamic.rtc_second) + out.numberbytes(dynamic.rtc_subsecond) +
|
||||||
4 * pollcounters.size() + 1 + savestate.size());
|
out.numberbytes(dynamic.pollcounters.size()) +
|
||||||
|
4 * dynamic.pollcounters.size() + 1 + dynamic.savestate.size());
|
||||||
|
|
||||||
out.extension(TAG_HOSTMEMORY, [this](binarystream::output& s) {
|
out.extension(TAG_HOSTMEMORY, [this](binarystream::output& s) {
|
||||||
s.blob_implicit(this->host_memory);
|
s.blob_implicit(this->dynamic.host_memory);
|
||||||
});
|
});
|
||||||
|
|
||||||
out.extension(TAG_SCREENSHOT, [this](binarystream::output& s) {
|
out.extension(TAG_SCREENSHOT, [this](binarystream::output& s) {
|
||||||
s.blob_implicit(this->screenshot);
|
s.blob_implicit(this->dynamic.screenshot);
|
||||||
}, true, screenshot.size());
|
}, true, dynamic.screenshot.size());
|
||||||
|
|
||||||
for(auto i : sram) {
|
for(auto i : dynamic.sram) {
|
||||||
out.extension(TAG_SAVE_SRAM, [&i](binarystream::output& s) {
|
out.extension(TAG_SAVE_SRAM, [&i](binarystream::output& s) {
|
||||||
s.string(i.first);
|
s.string(i.first);
|
||||||
s.blob_implicit(i.second);
|
s.blob_implicit(i.second);
|
||||||
|
@ -164,7 +173,7 @@ void moviefile::binary_io(int _stream, rrdata_set& rrd) throw(std::bad_alloc, st
|
||||||
s.string_implicit(i.second);
|
s.string_implicit(i.second);
|
||||||
});
|
});
|
||||||
|
|
||||||
for(auto i : active_macros)
|
for(auto i : dynamic.active_macros)
|
||||||
out.extension(TAG_MACRO, [&i](binarystream::output& s) {
|
out.extension(TAG_MACRO, [&i](binarystream::output& s) {
|
||||||
s.number(i.second);
|
s.number(i.second);
|
||||||
s.string_implicit(i.first);
|
s.string_implicit(i.first);
|
||||||
|
@ -177,6 +186,11 @@ void moviefile::binary_io(int _stream, rrdata_set& rrd) throw(std::bad_alloc, st
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.extension(TAG_VICOUNTER, [this](binarystream::output& s) {
|
||||||
|
s.number(dynamic.vi_counter);
|
||||||
|
s.number(dynamic.vi_this_frame);
|
||||||
|
});
|
||||||
|
|
||||||
int64_t next_bnum = 0;
|
int64_t next_bnum = 0;
|
||||||
std::map<std::string, uint64_t> branch_table;
|
std::map<std::string, uint64_t> branch_table;
|
||||||
for(auto& i : branches) {
|
for(auto& i : branches) {
|
||||||
|
@ -212,6 +226,7 @@ void moviefile::binary_io(int _stream, core_type& romtype) throw(std::bad_alloc,
|
||||||
auto ctrldata = gametype->get_type().controllerconfig(settings);
|
auto ctrldata = gametype->get_type().controllerconfig(settings);
|
||||||
portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
|
portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||||
input = NULL;
|
input = NULL;
|
||||||
|
dynamic.vi_valid = false;
|
||||||
|
|
||||||
in.extension({
|
in.extension({
|
||||||
{TAG_ANCHOR_SAVE, [this](binarystream::input& s) {
|
{TAG_ANCHOR_SAVE, [this](binarystream::input& s) {
|
||||||
|
@ -225,10 +240,10 @@ void moviefile::binary_io(int _stream, core_type& romtype) throw(std::bad_alloc,
|
||||||
}},{TAG_GAMENAME, [this](binarystream::input& s) {
|
}},{TAG_GAMENAME, [this](binarystream::input& s) {
|
||||||
this->gamename = s.string_implicit();
|
this->gamename = s.string_implicit();
|
||||||
}},{TAG_HOSTMEMORY, [this](binarystream::input& s) {
|
}},{TAG_HOSTMEMORY, [this](binarystream::input& s) {
|
||||||
s.blob_implicit(this->host_memory);
|
s.blob_implicit(this->dynamic.host_memory);
|
||||||
}},{TAG_MACRO, [this](binarystream::input& s) {
|
}},{TAG_MACRO, [this](binarystream::input& s) {
|
||||||
uint64_t n = s.number();
|
uint64_t n = s.number();
|
||||||
this->active_macros[s.string_implicit()] = n;
|
this->dynamic.active_macros[s.string_implicit()] = n;
|
||||||
}},{TAG_BRANCH_NAME, [this, &branch_table, &next_bnum, &next_branch](binarystream::input& s) {
|
}},{TAG_BRANCH_NAME, [this, &branch_table, &next_bnum, &next_branch](binarystream::input& s) {
|
||||||
branch_table[next_bnum++] = next_branch = s.string_implicit();
|
branch_table[next_bnum++] = next_branch = s.string_implicit();
|
||||||
}},{TAG_MOVIE, [this, &ports, &next_branch](binarystream::input& s) {
|
}},{TAG_MOVIE, [this, &ports, &next_branch](binarystream::input& s) {
|
||||||
|
@ -269,25 +284,29 @@ void moviefile::binary_io(int _stream, core_type& romtype) throw(std::bad_alloc,
|
||||||
this->rerecords = (stringfmt() << rrdata_set::count(c_rrdata)).str();
|
this->rerecords = (stringfmt() << rrdata_set::count(c_rrdata)).str();
|
||||||
}},{TAG_SAVE_SRAM, [this](binarystream::input& s) {
|
}},{TAG_SAVE_SRAM, [this](binarystream::input& s) {
|
||||||
std::string a = s.string();
|
std::string a = s.string();
|
||||||
s.blob_implicit(this->sram[a]);
|
s.blob_implicit(this->dynamic.sram[a]);
|
||||||
}},{TAG_SAVESTATE, [this](binarystream::input& s) {
|
}},{TAG_SAVESTATE, [this](binarystream::input& s) {
|
||||||
this->is_savestate = true;
|
this->is_savestate = true;
|
||||||
this->save_frame = s.number();
|
this->dynamic.save_frame = s.number();
|
||||||
this->lagged_frames = s.number();
|
this->dynamic.lagged_frames = s.number();
|
||||||
this->rtc_second = s.number();
|
this->dynamic.rtc_second = s.number();
|
||||||
this->rtc_subsecond = s.number();
|
this->dynamic.rtc_subsecond = s.number();
|
||||||
this->pollcounters.resize(s.number());
|
this->dynamic.pollcounters.resize(s.number());
|
||||||
for(auto& i : this->pollcounters)
|
for(auto& i : this->dynamic.pollcounters)
|
||||||
i = s.number32();
|
i = s.number32();
|
||||||
this->poll_flag = (s.byte() != 0);
|
this->dynamic.poll_flag = (s.byte() != 0);
|
||||||
s.blob_implicit(this->savestate);
|
s.blob_implicit(this->dynamic.savestate);
|
||||||
}},{TAG_SCREENSHOT, [this](binarystream::input& s) {
|
}},{TAG_SCREENSHOT, [this](binarystream::input& s) {
|
||||||
s.blob_implicit(this->screenshot);
|
s.blob_implicit(this->dynamic.screenshot);
|
||||||
}},{TAG_SUBTITLE, [this](binarystream::input& s) {
|
}},{TAG_SUBTITLE, [this](binarystream::input& s) {
|
||||||
uint64_t f = s.number();
|
uint64_t f = s.number();
|
||||||
uint64_t l = s.number();
|
uint64_t l = s.number();
|
||||||
std::string x = s.string_implicit();
|
std::string x = s.string_implicit();
|
||||||
this->subtitles[moviefile_subtiming(f, l)] = x;
|
this->subtitles[moviefile_subtiming(f, l)] = x;
|
||||||
|
}},{TAG_VICOUNTER, [this](binarystream::input& s) {
|
||||||
|
dynamic.vi_counter = s.number();
|
||||||
|
dynamic.vi_this_frame = s.number();
|
||||||
|
dynamic.vi_valid = true;
|
||||||
}}
|
}}
|
||||||
}, binarystream::null_default);
|
}, binarystream::null_default);
|
||||||
|
|
||||||
|
|
|
@ -200,9 +200,12 @@ void moviefile::brief_info::load(zip::reader& r)
|
||||||
r.read_linefile("gametype", sysregion);
|
r.read_linefile("gametype", sysregion);
|
||||||
r.read_linefile("coreversion", corename);
|
r.read_linefile("coreversion", corename);
|
||||||
r.read_linefile("projectid", projectid);
|
r.read_linefile("projectid", projectid);
|
||||||
if(r.has_member("savestate"))
|
if(r.has_member("savestate")) {
|
||||||
r.read_numeric_file("saveframe", current_frame);
|
if(r.has_member("vicount"))
|
||||||
else
|
r.read_numeric_file("vicount", current_frame);
|
||||||
|
else
|
||||||
|
r.read_numeric_file("saveframe", current_frame);
|
||||||
|
} else
|
||||||
current_frame = 0;
|
current_frame = 0;
|
||||||
r.read_numeric_file("rerecords", rerecords);
|
r.read_numeric_file("rerecords", rerecords);
|
||||||
r.read_linefile("rom.sha256", hash[0], true);
|
r.read_linefile("rom.sha256", hash[0], true);
|
||||||
|
@ -242,6 +245,10 @@ void moviefile::load(zip::reader& r, core_type& romtype) throw(std::bad_alloc, s
|
||||||
auto ctrldata = gametype->get_type().controllerconfig(settings);
|
auto ctrldata = gametype->get_type().controllerconfig(settings);
|
||||||
portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
|
portctrl::type_set& ports = portctrl::type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||||
|
|
||||||
|
dynamic.vi_valid = true;
|
||||||
|
dynamic.vi_counter = 0;
|
||||||
|
dynamic.vi_this_frame = 0;
|
||||||
|
|
||||||
branches.clear();
|
branches.clear();
|
||||||
r.read_linefile("gamename", gamename, true);
|
r.read_linefile("gamename", gamename, true);
|
||||||
r.read_linefile("projectid", projectid);
|
r.read_linefile("projectid", projectid);
|
||||||
|
@ -266,34 +273,42 @@ void moviefile::load(zip::reader& r, core_type& romtype) throw(std::bad_alloc, s
|
||||||
movie_rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
movie_rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||||
r.read_numeric_file("starttime.second", movie_rtc_second, true);
|
r.read_numeric_file("starttime.second", movie_rtc_second, true);
|
||||||
r.read_numeric_file("starttime.subsecond", movie_rtc_subsecond, true);
|
r.read_numeric_file("starttime.subsecond", movie_rtc_subsecond, true);
|
||||||
rtc_second = movie_rtc_second;
|
dynamic.rtc_second = movie_rtc_second;
|
||||||
rtc_subsecond = movie_rtc_subsecond;
|
dynamic.rtc_subsecond = movie_rtc_subsecond;
|
||||||
if(r.has_member("savestate.anchor"))
|
if(r.has_member("savestate.anchor"))
|
||||||
r.read_raw_file("savestate.anchor", anchor_savestate);
|
r.read_raw_file("savestate.anchor", anchor_savestate);
|
||||||
if(r.has_member("savestate")) {
|
if(r.has_member("savestate")) {
|
||||||
|
dynamic.vi_valid = false;
|
||||||
|
if(r.has_member("vicounter")) {
|
||||||
|
r.read_numeric_file("vicounter", dynamic.vi_counter);
|
||||||
|
r.read_numeric_file("vithisframe", dynamic.vi_this_frame);
|
||||||
|
dynamic.vi_valid = true;
|
||||||
|
}
|
||||||
is_savestate = true;
|
is_savestate = true;
|
||||||
r.read_numeric_file("saveframe", save_frame, true);
|
r.read_numeric_file("saveframe", dynamic.save_frame, true);
|
||||||
r.read_numeric_file("lagcounter", lagged_frames, true);
|
r.read_numeric_file("lagcounter", dynamic.lagged_frames, true);
|
||||||
read_pollcounters(r, "pollcounters", pollcounters);
|
read_pollcounters(r, "pollcounters", dynamic.pollcounters);
|
||||||
if(r.has_member("hostmemory"))
|
if(r.has_member("hostmemory"))
|
||||||
r.read_raw_file("hostmemory", host_memory);
|
r.read_raw_file("hostmemory", dynamic.host_memory);
|
||||||
r.read_raw_file("savestate", savestate);
|
else
|
||||||
|
dynamic.host_memory.clear();
|
||||||
|
r.read_raw_file("savestate", dynamic.savestate);
|
||||||
for(auto name : r)
|
for(auto name : r)
|
||||||
if(name.length() >= 5 && name.substr(0, 5) == "sram.")
|
if(name.length() >= 5 && name.substr(0, 5) == "sram.")
|
||||||
r.read_raw_file(name, sram[name.substr(5)]);
|
r.read_raw_file(name, dynamic.sram[name.substr(5)]);
|
||||||
r.read_raw_file("screenshot", screenshot);
|
r.read_raw_file("screenshot", dynamic.screenshot);
|
||||||
//If these can't be read, just use some (wrong) values.
|
//If these can't be read, just use some (wrong) values.
|
||||||
r.read_numeric_file("savetime.second", rtc_second, true);
|
r.read_numeric_file("savetime.second", dynamic.rtc_second, true);
|
||||||
r.read_numeric_file("savetime.subsecond", rtc_subsecond, true);
|
r.read_numeric_file("savetime.subsecond", dynamic.rtc_subsecond, true);
|
||||||
uint64_t _poll_flag = 2; //Legacy behaviour is the default.
|
uint64_t _poll_flag = 2; //Legacy behaviour is the default.
|
||||||
r.read_numeric_file("pollflag", _poll_flag, true);
|
r.read_numeric_file("pollflag", _poll_flag, true);
|
||||||
poll_flag = _poll_flag;
|
dynamic.poll_flag = _poll_flag;
|
||||||
active_macros = read_active_macros(r, "macros");
|
dynamic.active_macros = read_active_macros(r, "macros");
|
||||||
}
|
}
|
||||||
for(auto name : r)
|
for(auto name : r)
|
||||||
if(name.length() >= 8 && name.substr(0, 8) == "initram.")
|
if(name.length() >= 8 && name.substr(0, 8) == "initram.")
|
||||||
r.read_raw_file(name, ramcontent[name.substr(8)]);
|
r.read_raw_file(name, ramcontent[name.substr(8)]);
|
||||||
if(rtc_subsecond < 0 || movie_rtc_subsecond < 0)
|
if(dynamic.rtc_subsecond < 0 || movie_rtc_subsecond < 0)
|
||||||
throw std::runtime_error("Invalid RTC subsecond value");
|
throw std::runtime_error("Invalid RTC subsecond value");
|
||||||
std::string name = r.find_first();
|
std::string name = r.find_first();
|
||||||
for(auto name : r)
|
for(auto name : r)
|
||||||
|
|
|
@ -173,20 +173,22 @@ void moviefile::save(zip::writer& w, rrdata_set& rrd) throw(std::bad_alloc, std:
|
||||||
w.write_numeric_file("starttime.second", movie_rtc_second);
|
w.write_numeric_file("starttime.second", movie_rtc_second);
|
||||||
w.write_numeric_file("starttime.subsecond", movie_rtc_subsecond);
|
w.write_numeric_file("starttime.subsecond", movie_rtc_subsecond);
|
||||||
if(!anchor_savestate.empty())
|
if(!anchor_savestate.empty())
|
||||||
w.write_raw_file("savestate.anchor", anchor_savestate);
|
w.write_raw_file("savestate.anchor", anchor_savestate);
|
||||||
if(is_savestate) {
|
if(is_savestate) {
|
||||||
w.write_numeric_file("saveframe", save_frame);
|
w.write_numeric_file("vicounter", dynamic.vi_counter);
|
||||||
w.write_numeric_file("lagcounter", lagged_frames);
|
w.write_numeric_file("vithisframe", dynamic.vi_this_frame);
|
||||||
write_pollcounters(w, "pollcounters", pollcounters);
|
w.write_numeric_file("saveframe", dynamic.save_frame);
|
||||||
w.write_raw_file("hostmemory", host_memory);
|
w.write_numeric_file("lagcounter", dynamic.lagged_frames);
|
||||||
w.write_raw_file("savestate", savestate);
|
write_pollcounters(w, "pollcounters", dynamic.pollcounters);
|
||||||
w.write_raw_file("screenshot", screenshot);
|
w.write_raw_file("hostmemory", dynamic.host_memory);
|
||||||
for(auto i : sram)
|
w.write_raw_file("savestate", dynamic.savestate);
|
||||||
|
w.write_raw_file("screenshot", dynamic.screenshot);
|
||||||
|
for(auto i : dynamic.sram)
|
||||||
w.write_raw_file("sram." + i.first, i.second);
|
w.write_raw_file("sram." + i.first, i.second);
|
||||||
w.write_numeric_file("savetime.second", rtc_second);
|
w.write_numeric_file("savetime.second", dynamic.rtc_second);
|
||||||
w.write_numeric_file("savetime.subsecond", rtc_subsecond);
|
w.write_numeric_file("savetime.subsecond", dynamic.rtc_subsecond);
|
||||||
w.write_numeric_file("pollflag", poll_flag);
|
w.write_numeric_file("pollflag", dynamic.poll_flag);
|
||||||
write_active_macros(w, "macros", active_macros);
|
write_active_macros(w, "macros", dynamic.active_macros);
|
||||||
}
|
}
|
||||||
for(auto i : ramcontent)
|
for(auto i : ramcontent)
|
||||||
w.write_raw_file("initram." + i.first, i.second);
|
w.write_raw_file("initram." + i.first, i.second);
|
||||||
|
|
|
@ -75,7 +75,7 @@ moviefile::brief_info::brief_info(const std::string& filename)
|
||||||
sysregion = mv.gametype->get_name();
|
sysregion = mv.gametype->get_name();
|
||||||
corename = mv.coreversion;
|
corename = mv.coreversion;
|
||||||
projectid = mv.projectid;
|
projectid = mv.projectid;
|
||||||
current_frame = mv.is_savestate ? mv.save_frame : 0;
|
current_frame = mv.is_savestate ? mv.dynamic.save_frame : 0;
|
||||||
rerecords = mv.rerecords_mem;
|
rerecords = mv.rerecords_mem;
|
||||||
for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
|
for(unsigned i = 0; i < ROM_SLOT_COUNT; i++) {
|
||||||
hash[i] = mv.romimg_sha256[i];
|
hash[i] = mv.romimg_sha256[i];
|
||||||
|
@ -101,6 +101,55 @@ moviefile::brief_info::brief_info(const std::string& filename)
|
||||||
load(r);
|
load(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moviefile::dynamic_state::dynamic_state()
|
||||||
|
{
|
||||||
|
save_frame = 0;
|
||||||
|
lagged_frames = 0;
|
||||||
|
rtc_second = DEFAULT_RTC_SECOND;
|
||||||
|
rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||||
|
poll_flag = 0;
|
||||||
|
vi_valid = true;
|
||||||
|
vi_counter = 0;
|
||||||
|
vi_this_frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moviefile::dynamic_state::clear_state(int64_t sec, int64_t ssec)
|
||||||
|
{
|
||||||
|
sram.clear();
|
||||||
|
savestate.clear();
|
||||||
|
host_memory.clear();
|
||||||
|
screenshot.clear();
|
||||||
|
save_frame = 0;
|
||||||
|
lagged_frames = 0;
|
||||||
|
for(auto& i : pollcounters)
|
||||||
|
i = 0;
|
||||||
|
poll_flag = 0;
|
||||||
|
rtc_second = sec;
|
||||||
|
rtc_subsecond = ssec;
|
||||||
|
active_macros.clear();
|
||||||
|
vi_valid = true;
|
||||||
|
vi_counter = 0;
|
||||||
|
vi_this_frame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void moviefile::dynamic_state::swap_with(dynamic_state& d)
|
||||||
|
{
|
||||||
|
std::swap(sram, d.sram);
|
||||||
|
std::swap(savestate, d.savestate);
|
||||||
|
std::swap(host_memory, d.host_memory);
|
||||||
|
std::swap(screenshot, d.screenshot);
|
||||||
|
std::swap(save_frame, d.save_frame);
|
||||||
|
std::swap(lagged_frames, d.lagged_frames);
|
||||||
|
std::swap(pollcounters, d.pollcounters);
|
||||||
|
std::swap(poll_flag, d.poll_flag);
|
||||||
|
std::swap(rtc_second, d.rtc_second);
|
||||||
|
std::swap(rtc_subsecond, d.rtc_subsecond);
|
||||||
|
std::swap(active_macros, d.active_macros);
|
||||||
|
std::swap(vi_valid, d.vi_valid);
|
||||||
|
std::swap(vi_counter, d.vi_counter);
|
||||||
|
std::swap(vi_this_frame, d.vi_this_frame);
|
||||||
|
}
|
||||||
|
|
||||||
moviefile::moviefile() throw(std::bad_alloc)
|
moviefile::moviefile() throw(std::bad_alloc)
|
||||||
{
|
{
|
||||||
force_corrupt = false;
|
force_corrupt = false;
|
||||||
|
@ -109,12 +158,12 @@ moviefile::moviefile() throw(std::bad_alloc)
|
||||||
coreversion = "";
|
coreversion = "";
|
||||||
projectid = "";
|
projectid = "";
|
||||||
rerecords = "0";
|
rerecords = "0";
|
||||||
|
rerecords_mem = 0;
|
||||||
is_savestate = false;
|
is_savestate = false;
|
||||||
movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND;
|
movie_rtc_second = DEFAULT_RTC_SECOND;
|
||||||
movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
movie_rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||||
start_paused = false;
|
start_paused = false;
|
||||||
lazy_project_create = true;
|
lazy_project_create = true;
|
||||||
poll_flag = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_settings, uint64_t rtc_sec,
|
moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_settings, uint64_t rtc_sec,
|
||||||
|
@ -125,12 +174,12 @@ moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_sett
|
||||||
coreversion = rom.get_core_identifier();
|
coreversion = rom.get_core_identifier();
|
||||||
projectid = get_random_hexstring(40);
|
projectid = get_random_hexstring(40);
|
||||||
rerecords = "0";
|
rerecords = "0";
|
||||||
|
rerecords_mem = 0;
|
||||||
is_savestate = false;
|
is_savestate = false;
|
||||||
movie_rtc_second = rtc_second = rtc_sec;
|
movie_rtc_second = dynamic.rtc_second = rtc_sec;
|
||||||
movie_rtc_subsecond = rtc_subsecond = rtc_subsec;
|
movie_rtc_subsecond = dynamic.rtc_subsecond = rtc_subsec;
|
||||||
start_paused = false;
|
start_paused = false;
|
||||||
lazy_project_create = true;
|
lazy_project_create = true;
|
||||||
poll_flag = 0;
|
|
||||||
settings = c_settings;
|
settings = c_settings;
|
||||||
input = NULL;
|
input = NULL;
|
||||||
auto ctrldata = rom.controllerconfig(settings);
|
auto ctrldata = rom.controllerconfig(settings);
|
||||||
|
@ -158,7 +207,6 @@ moviefile::moviefile(const std::string& movie, core_type& romtype) throw(std::ba
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
input = NULL;
|
input = NULL;
|
||||||
poll_flag = false;
|
|
||||||
start_paused = false;
|
start_paused = false;
|
||||||
force_corrupt = false;
|
force_corrupt = false;
|
||||||
is_savestate = false;
|
is_savestate = false;
|
||||||
|
@ -303,15 +351,8 @@ void moviefile::copy_fields(const moviefile& mv)
|
||||||
movie_sram = mv.movie_sram;
|
movie_sram = mv.movie_sram;
|
||||||
ramcontent = mv.ramcontent;
|
ramcontent = mv.ramcontent;
|
||||||
is_savestate = mv.is_savestate;
|
is_savestate = mv.is_savestate;
|
||||||
sram = mv.sram;
|
dynamic = mv.dynamic;
|
||||||
savestate = mv.savestate;
|
|
||||||
anchor_savestate = mv.anchor_savestate;
|
anchor_savestate = mv.anchor_savestate;
|
||||||
host_memory = mv.host_memory;
|
|
||||||
screenshot = mv.screenshot;
|
|
||||||
save_frame = mv.save_frame;
|
|
||||||
lagged_frames = mv.lagged_frames;
|
|
||||||
pollcounters = mv.pollcounters;
|
|
||||||
poll_flag = mv.poll_flag;
|
|
||||||
c_rrdata = mv.c_rrdata;
|
c_rrdata = mv.c_rrdata;
|
||||||
branches = mv.branches;
|
branches = mv.branches;
|
||||||
|
|
||||||
|
@ -321,14 +362,11 @@ void moviefile::copy_fields(const moviefile& mv)
|
||||||
if(mv.branches.count(i.first) && &mv.branches.find(i.first)->second == mv.input)
|
if(mv.branches.count(i.first) && &mv.branches.find(i.first)->second == mv.input)
|
||||||
input = &i.second;
|
input = &i.second;
|
||||||
|
|
||||||
rtc_second = mv.rtc_second;
|
|
||||||
rtc_subsecond = mv.rtc_subsecond;
|
|
||||||
movie_rtc_second = mv.movie_rtc_second;
|
movie_rtc_second = mv.movie_rtc_second;
|
||||||
movie_rtc_subsecond = mv.movie_rtc_subsecond;
|
movie_rtc_subsecond = mv.movie_rtc_subsecond;
|
||||||
start_paused = mv.start_paused;
|
start_paused = mv.start_paused;
|
||||||
lazy_project_create = mv.lazy_project_create;
|
lazy_project_create = mv.lazy_project_create;
|
||||||
subtitles = mv.subtitles;
|
subtitles = mv.subtitles;
|
||||||
active_macros = mv.active_macros;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void moviefile::fork_branch(const std::string& oldname, const std::string& newname)
|
void moviefile::fork_branch(const std::string& oldname, const std::string& newname)
|
||||||
|
|
|
@ -151,8 +151,7 @@ namespace
|
||||||
m.start_paused = true;
|
m.start_paused = true;
|
||||||
m.movie_rtc_second = p.movie_rtc_second;
|
m.movie_rtc_second = p.movie_rtc_second;
|
||||||
m.movie_rtc_subsecond = p.movie_rtc_subsecond;
|
m.movie_rtc_subsecond = p.movie_rtc_subsecond;
|
||||||
m.save_frame = 0;
|
m.dynamic = moviefile::dynamic_state();
|
||||||
m.lagged_frames = 0;
|
|
||||||
m.anchor_savestate = p.anchor_savestate;
|
m.anchor_savestate = p.anchor_savestate;
|
||||||
m.movie_sram = p.movie_sram;
|
m.movie_sram = p.movie_sram;
|
||||||
m.authors = p.authors;
|
m.authors = p.authors;
|
||||||
|
|
|
@ -234,7 +234,6 @@ void UI_save_movie(emulator_instance& inst, std::ostringstream& stream)
|
||||||
inst.mlogic->get_mfile().gamename = prj->gamename;
|
inst.mlogic->get_mfile().gamename = prj->gamename;
|
||||||
inst.mlogic->get_mfile().authors = prj->authors;
|
inst.mlogic->get_mfile().authors = prj->authors;
|
||||||
}
|
}
|
||||||
inst.mlogic->get_mfile().active_macros.clear();
|
|
||||||
inst.mlogic->get_mfile().save(stream, inst.mlogic->get_rrdata());
|
inst.mlogic->get_mfile().save(stream, inst.mlogic->get_rrdata());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
OBJECTS=test.$(OBJECT_SUFFIX)
|
OBJECTS=test.$(OBJECT_SUFFIX) test2.$(OBJECT_SUFFIX)
|
||||||
|
|
||||||
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
|
.PRECIOUS: %.$(OBJECT_SUFFIX) %.files
|
||||||
|
|
||||||
|
|
212
src/emulation/test/test2.cpp
Normal file
212
src/emulation/test/test2.cpp
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2012-2013 by Ilari Liusvaara *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License version 2 as *
|
||||||
|
* published by the Free Software Foundation. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License version 2 for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* version 2 along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include "lsnes.hpp"
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "core/audioapi.hpp"
|
||||||
|
#include "core/misc.hpp"
|
||||||
|
#include "core/command.hpp"
|
||||||
|
#include "core/controllerframe.hpp"
|
||||||
|
#include "core/dispatch.hpp"
|
||||||
|
#include "core/framebuffer.hpp"
|
||||||
|
#include "core/instance.hpp"
|
||||||
|
#include "core/messages.hpp"
|
||||||
|
#include "interface/callbacks.hpp"
|
||||||
|
#include "interface/cover.hpp"
|
||||||
|
#include "interface/romtype.hpp"
|
||||||
|
#include "library/framebuffer-pixfmt-rgb32.hpp"
|
||||||
|
#include "library/string.hpp"
|
||||||
|
#include "library/portctrl-data.hpp"
|
||||||
|
#include "library/serialization.hpp"
|
||||||
|
#include "library/minmax.hpp"
|
||||||
|
#include "library/framebuffer.hpp"
|
||||||
|
#include "library/hex.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
uint32_t cover_fbmem[480 * 432];
|
||||||
|
bool pflag = false;
|
||||||
|
|
||||||
|
//Framebuffer.
|
||||||
|
struct framebuffer::info cover_fbinfo = {
|
||||||
|
&framebuffer::pixfmt_rgb32, //Format.
|
||||||
|
(char*)cover_fbmem, //Memory.
|
||||||
|
480, 432, 1920, //Physical size.
|
||||||
|
480, 432, 1920, //Logical size.
|
||||||
|
0, 0 //Offset.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct interface_device_reg test_registers[] = {
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "ports.inc"
|
||||||
|
|
||||||
|
controller_set test_controllerconfig(std::map<std::string, std::string>& settings)
|
||||||
|
{
|
||||||
|
std::map<std::string, std::string> _settings = settings;
|
||||||
|
controller_set r;
|
||||||
|
r.ports.push_back(&psystem);
|
||||||
|
r.ports.push_back(&ptype1);
|
||||||
|
r.ports.push_back(&ptype2);
|
||||||
|
r.logical_map.push_back(std::make_pair(1, 0));
|
||||||
|
r.logical_map.push_back(std::make_pair(2, 0));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void redraw_cover_fbinfo()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
|
||||||
|
cover_fbmem[i] = 0x00000000;
|
||||||
|
cover_render_string(cover_fbmem, 0, 0, "TEST MODE", 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void redraw_screen()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < sizeof(cover_fbmem) / sizeof(cover_fbmem[0]); i++)
|
||||||
|
cover_fbmem[i] = 0x00000000;
|
||||||
|
{
|
||||||
|
std::ostringstream str;
|
||||||
|
unsigned k = 0;
|
||||||
|
for(unsigned i = 0; i < 6; i++)
|
||||||
|
str << ecore_callbacks->get_input(1, 0, i) << " ";
|
||||||
|
for(unsigned i = 0; i < 15; i++)
|
||||||
|
if(ecore_callbacks->get_input(1, 0, i + 6)) k |= (1 << i);
|
||||||
|
str << hex::to16(k);
|
||||||
|
cover_render_string(cover_fbmem, 0, 0, str.str(), 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::ostringstream str;
|
||||||
|
unsigned k = 0;
|
||||||
|
for(unsigned i = 0; i < 6; i++)
|
||||||
|
str << ecore_callbacks->get_input(2, 0, i) << " ";
|
||||||
|
for(unsigned i = 0; i < 15; i++)
|
||||||
|
if(ecore_callbacks->get_input(2, 0, i + 6)) k |= (1 << i);
|
||||||
|
str << hex::to16(k);
|
||||||
|
cover_render_string(cover_fbmem, 0, 16, str.str(), 0xFFFFFF, 0x00000, 480, 432, 1920, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _test_core2 : public core_core, public core_type, public core_region, public core_sysregion
|
||||||
|
{
|
||||||
|
_test_core2()
|
||||||
|
: core_core({&psystem, &ptype1, &ptype2}, {
|
||||||
|
{0, "xyzzy", "xyzzy", {
|
||||||
|
{"Magic", "enum:[\"foo\",\"bar\",\"baz\",[\"qux\",\"zot\"]]"}
|
||||||
|
}}
|
||||||
|
}),
|
||||||
|
core_type({{
|
||||||
|
.iname = "test2",
|
||||||
|
.hname = "test2",
|
||||||
|
.id = 0,
|
||||||
|
.sysname = "Test2",
|
||||||
|
.bios = NULL,
|
||||||
|
.regions = {this},
|
||||||
|
.images = {{"rom", "Cartridge ROM", 1, 0, 0, "test2"}},
|
||||||
|
.settings = {},
|
||||||
|
.core = this,
|
||||||
|
}}),
|
||||||
|
core_region({{"world", "World", 0, 0, false, {1, 1000}, {0}}}),
|
||||||
|
core_sysregion("test2", *this, *this) { hide(); }
|
||||||
|
|
||||||
|
std::string c_core_identifier() { return "TEST2"; }
|
||||||
|
bool c_set_region(core_region& region) { return (®ion == this); }
|
||||||
|
std::pair<uint32_t, uint32_t> c_video_rate() { return std::make_pair(60, 1); }
|
||||||
|
double c_get_PAR() { return 1.0; }
|
||||||
|
std::pair<uint32_t, uint32_t> c_audio_rate() { return std::make_pair(48000, 1); }
|
||||||
|
std::map<std::string, std::vector<char>> c_save_sram() throw(std::bad_alloc) {
|
||||||
|
std::map<std::string, std::vector<char>> s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
void c_load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc) {}
|
||||||
|
void c_serialize(std::vector<char>& out) { out.resize(1); out[0] = fmod; }
|
||||||
|
void c_unserialize(const char* in, size_t insize) { fmod = in[0]; }
|
||||||
|
core_region& c_get_region() { return *this; }
|
||||||
|
void c_power() {}
|
||||||
|
void c_unload_cartridge() {}
|
||||||
|
std::pair<uint32_t, uint32_t> c_get_scale_factors(uint32_t width, uint32_t height) {
|
||||||
|
return std::make_pair(max(512 / width, (uint32_t)1), max(448 / height, (uint32_t)1));
|
||||||
|
}
|
||||||
|
void c_install_handler() {}
|
||||||
|
void c_uninstall_handler() {}
|
||||||
|
void c_emulate() {
|
||||||
|
int16_t audio[800] = {0};
|
||||||
|
pflag = false;
|
||||||
|
redraw_screen();
|
||||||
|
framebuffer::info inf;
|
||||||
|
inf.type = &framebuffer::pixfmt_rgb32;
|
||||||
|
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(cover_fbmem));
|
||||||
|
inf.physwidth = 480;
|
||||||
|
inf.physheight = 432;
|
||||||
|
inf.physstride = 1920;
|
||||||
|
inf.width = 480;
|
||||||
|
inf.height = 432;
|
||||||
|
inf.stride = 1920;
|
||||||
|
inf.offset_x = 0;
|
||||||
|
inf.offset_y = 0;
|
||||||
|
framebuffer::raw ls(inf);
|
||||||
|
fmod++;
|
||||||
|
if(fmod == 50) fmod = 0;
|
||||||
|
if(fmod == 0 || fmod == 16 || fmod == 33)
|
||||||
|
ecore_callbacks->output_frame(ls, 60,1);
|
||||||
|
CORE().audio->submit_buffer(audio, 48, false, 48000);
|
||||||
|
}
|
||||||
|
void c_runtosave() {}
|
||||||
|
bool c_get_pflag() { return pflag; }
|
||||||
|
void c_set_pflag(bool _pflag) { pflag = _pflag; }
|
||||||
|
framebuffer::raw& c_draw_cover() {
|
||||||
|
static framebuffer::raw x(cover_fbinfo);
|
||||||
|
redraw_cover_fbinfo();
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
std::string c_get_core_shortname() { return "test"; }
|
||||||
|
void c_pre_emulate_frame(portctrl::frame& cf) {}
|
||||||
|
void c_execute_action(unsigned id, const std::vector<interface_action_paramval>& p)
|
||||||
|
{
|
||||||
|
if(id == 0)
|
||||||
|
messages << "ID #0, choice: " << p[0].i << std::endl;
|
||||||
|
}
|
||||||
|
const interface_device_reg* c_get_registers() { return test_registers; }
|
||||||
|
int t_load_rom(core_romimage* images, std::map<std::string, std::string>& settings,
|
||||||
|
uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
controller_set t_controllerconfig(std::map<std::string, std::string>& settings)
|
||||||
|
{
|
||||||
|
return test_controllerconfig(settings);
|
||||||
|
}
|
||||||
|
bool t_is_vfr() { return true; }
|
||||||
|
std::pair<uint64_t, uint64_t> c_get_bus_map() { return std::make_pair(0, 0); }
|
||||||
|
std::list<core_vma_info> c_vma_list() { return std::list<core_vma_info>(); }
|
||||||
|
std::set<std::string> c_srams() { return std::set<std::string>(); }
|
||||||
|
unsigned c_action_flags(unsigned id) { return 1; }
|
||||||
|
int c_reset_action(bool hard) { return -1; }
|
||||||
|
void c_set_debug_flags(uint64_t addr, unsigned int sflags, unsigned int cflags) {}
|
||||||
|
void c_set_cheat(uint64_t addr, uint64_t value, bool set) {}
|
||||||
|
void c_debug_reset() {}
|
||||||
|
std::vector<std::string> c_get_trace_cpus()
|
||||||
|
{
|
||||||
|
return std::vector<std::string>();
|
||||||
|
}
|
||||||
|
unsigned char fmod;
|
||||||
|
} test2_core;
|
||||||
|
}
|
|
@ -668,6 +668,10 @@ failed:
|
||||||
{
|
{
|
||||||
internal_pflag = true;
|
internal_pflag = true;
|
||||||
}
|
}
|
||||||
|
bool supports_vfr_sel()
|
||||||
|
{
|
||||||
|
return (caps1 & LSNES_CORE_CAP1_TYPEEXT1);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
std::string fullname;
|
std::string fullname;
|
||||||
std::string shortname;
|
std::string shortname;
|
||||||
|
@ -691,8 +695,9 @@ failed:
|
||||||
struct c_core_type : public core_type
|
struct c_core_type : public core_type
|
||||||
{
|
{
|
||||||
c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, portctrl::type*> _ports,
|
c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, portctrl::type*> _ports,
|
||||||
unsigned _rcount, unsigned _id)
|
unsigned _rcount, unsigned _id, bool _vfr)
|
||||||
: core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id)
|
: core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id),
|
||||||
|
vfr(_vfr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
~c_core_type() throw()
|
~c_core_type() throw()
|
||||||
|
@ -749,6 +754,10 @@ failed:
|
||||||
}
|
}
|
||||||
return cset;
|
return cset;
|
||||||
}
|
}
|
||||||
|
bool t_is_vfr()
|
||||||
|
{
|
||||||
|
return vfr;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
|
void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
|
||||||
std::map<std::string, std::string>& settings)
|
std::map<std::string, std::string>& settings)
|
||||||
|
@ -779,6 +788,7 @@ failed:
|
||||||
entrypoint_fn entrypoint;
|
entrypoint_fn entrypoint;
|
||||||
unsigned rcount;
|
unsigned rcount;
|
||||||
unsigned id;
|
unsigned id;
|
||||||
|
bool vfr;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<char> msgbuf;
|
std::vector<char> msgbuf;
|
||||||
|
@ -1141,12 +1151,13 @@ no_parameters:
|
||||||
if(!cores.count(_core))
|
if(!cores.count(_core))
|
||||||
throw std::runtime_error("create_type: Unknown core");
|
throw std::runtime_error("create_type: Unknown core");
|
||||||
p.core = cores[_core];
|
p.core = cores[_core];
|
||||||
|
bool is_vfr = dynamic_cast<c_core_core*>(p.core)->supports_vfr_sel() && r.is_vfr;
|
||||||
for(unsigned* reg = r.regions; *reg != 0xFFFFFFFFU; reg++) {
|
for(unsigned* reg = r.regions; *reg != 0xFFFFFFFFU; reg++) {
|
||||||
if(!regions.count(*reg))
|
if(!regions.count(*reg))
|
||||||
throw std::runtime_error("create_type: Unknown region");
|
throw std::runtime_error("create_type: Unknown region");
|
||||||
p.regions.push_back(regions[*reg]);
|
p.regions.push_back(regions[*reg]);
|
||||||
}
|
}
|
||||||
return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type);
|
return new c_core_type(lib, p, cores[_core]->get_ports(), rcount, type, is_vfr);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<const void*, std::list<core_sysregion*>> bylib_sysregion;
|
std::map<const void*, std::list<core_sysregion*>> bylib_sysregion;
|
||||||
|
@ -1184,7 +1195,7 @@ no_parameters:
|
||||||
//Enumerate what the thing supports.
|
//Enumerate what the thing supports.
|
||||||
entrypoint_fn entrypoint(fn);
|
entrypoint_fn entrypoint(fn);
|
||||||
lsnes_core_enumerate_cores r;
|
lsnes_core_enumerate_cores r;
|
||||||
r.emu_flags1 = 2;
|
r.emu_flags1 = 3;
|
||||||
r.message = callback_message;
|
r.message = callback_message;
|
||||||
r.get_input = callback_get_input;
|
r.get_input = callback_get_input;
|
||||||
r.notify_action_update = callback_notify_action_update;
|
r.notify_action_update = callback_notify_action_update;
|
||||||
|
|
|
@ -582,6 +582,11 @@ std::vector<std::string> core_core::get_trace_cpus()
|
||||||
return c_get_trace_cpus();
|
return c_get_trace_cpus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool core_type::t_is_vfr()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
emucore_callbacks::~emucore_callbacks() throw()
|
emucore_callbacks::~emucore_callbacks() throw()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace
|
||||||
|
|
||||||
P(address);
|
P(address);
|
||||||
|
|
||||||
auto& h = CORE().mlogic->get_mfile().host_memory;
|
auto& h = CORE().mlogic->get_mfile().dynamic.host_memory;
|
||||||
if(address + sizeof(S) > h.size()) {
|
if(address + sizeof(S) > h.size()) {
|
||||||
L.pushboolean(0);
|
L.pushboolean(0);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -30,7 +30,7 @@ namespace
|
||||||
|
|
||||||
P(address, value);
|
P(address, value);
|
||||||
|
|
||||||
auto& h = CORE().mlogic->get_mfile().host_memory;
|
auto& h = CORE().mlogic->get_mfile().dynamic.host_memory;
|
||||||
if(address + sizeof(S) > h.size())
|
if(address + sizeof(S) > h.size())
|
||||||
h.resize(address + sizeof(S));
|
h.resize(address + sizeof(S));
|
||||||
serialization::write_endian<S>(&h[address], value, 1);
|
serialization::write_endian<S>(&h[address], value, 1);
|
||||||
|
|
|
@ -418,8 +418,7 @@ uint64_t lua_state::timed_hook(int timer) throw()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_t secs, uint64_t ssecs, movie& mov,
|
void lua_state::callback_do_unsafe_rewind(movie& mov, void* u)
|
||||||
void* u)
|
|
||||||
{
|
{
|
||||||
auto& core = CORE();
|
auto& core = CORE();
|
||||||
if(u) {
|
if(u) {
|
||||||
|
@ -428,9 +427,7 @@ void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_
|
||||||
try {
|
try {
|
||||||
run_callback(*on_pre_rewind);
|
run_callback(*on_pre_rewind);
|
||||||
run_callback(*on_movie_lost, "unsaferewind");
|
run_callback(*on_movie_lost, "unsaferewind");
|
||||||
mainloop_restore_state(u2->state, u2->secs, u2->ssecs);
|
do_quickload(u2->dstate, mov);
|
||||||
mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
|
||||||
try { core.mlogic->get_mfile().host_memory = u2->hostmemory; } catch(...) {}
|
|
||||||
run_callback(*on_post_rewind);
|
run_callback(*on_post_rewind);
|
||||||
delete reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u);
|
delete reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u);
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
|
@ -438,14 +435,9 @@ void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//Save
|
//Save
|
||||||
run_callback(*on_set_rewind, lua::state::fn_tag([&core, save, secs, ssecs, &mov](lua::state& L) ->
|
run_callback(*on_set_rewind, lua::state::fn_tag([&core, &mov](lua::state& L) -> int {
|
||||||
int {
|
|
||||||
lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(*core.lua);
|
lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(*core.lua);
|
||||||
u2->state = save;
|
do_quicksave(u2->dstate, mov);
|
||||||
u2->secs = secs,
|
|
||||||
u2->ssecs = ssecs;
|
|
||||||
u2->hostmemory = core.mlogic->get_mfile().host_memory;
|
|
||||||
mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
|
||||||
return 1;
|
return 1;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -760,7 +760,7 @@ namespace
|
||||||
if((size_t)(daddr + rows * size) < daddr)
|
if((size_t)(daddr + rows * size) < daddr)
|
||||||
throw std::runtime_error("Size to copy too large");
|
throw std::runtime_error("Size to copy too large");
|
||||||
|
|
||||||
auto& h = core.mlogic->get_mfile().host_memory;
|
auto& h = core.mlogic->get_mfile().dynamic.host_memory;
|
||||||
if(daddr + rows * size > h.size()) {
|
if(daddr + rows * size > h.size()) {
|
||||||
equals = false;
|
equals = false;
|
||||||
h.resize(daddr + rows * size);
|
h.resize(daddr + rows * size);
|
||||||
|
|
|
@ -380,7 +380,7 @@ namespace
|
||||||
throw std::runtime_error("Source out of range");
|
throw std::runtime_error("Source out of range");
|
||||||
|
|
||||||
//Calculate new size of target.
|
//Calculate new size of target.
|
||||||
auto& h = core.mlogic->get_mfile().host_memory;
|
auto& h = core.mlogic->get_mfile().dynamic.host_memory;
|
||||||
size_t rsize = size * rows;
|
size_t rsize = size * rows;
|
||||||
if(size && rsize / size != rows)
|
if(size && rsize / size != rows)
|
||||||
throw std::runtime_error("Copy size out of range");
|
throw std::runtime_error("Copy size out of range");
|
||||||
|
|
|
@ -13,6 +13,13 @@ namespace
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int currentvi(lua::state& L, lua::parameters& P)
|
||||||
|
{
|
||||||
|
auto& m = CORE().mlogic->get_mfile();
|
||||||
|
L.pushnumber(m.dynamic.vi_counter);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int lagcounter(lua::state& L, lua::parameters& P)
|
int lagcounter(lua::state& L, lua::parameters& P)
|
||||||
{
|
{
|
||||||
auto& m = CORE().mlogic->get_movie();
|
auto& m = CORE().mlogic->get_movie();
|
||||||
|
@ -79,8 +86,8 @@ namespace
|
||||||
int read_rtc(lua::state& L, lua::parameters& P)
|
int read_rtc(lua::state& L, lua::parameters& P)
|
||||||
{
|
{
|
||||||
auto& core = CORE();
|
auto& core = CORE();
|
||||||
L.pushnumber(core.mlogic->get_mfile().rtc_second);
|
L.pushnumber(core.mlogic->get_mfile().dynamic.rtc_second);
|
||||||
L.pushnumber(core.mlogic->get_mfile().rtc_subsecond);
|
L.pushnumber(core.mlogic->get_mfile().dynamic.rtc_subsecond);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,30 +119,25 @@ namespace
|
||||||
if(!mfile.is_savestate)
|
if(!mfile.is_savestate)
|
||||||
throw std::runtime_error("movie.to_rewind only allows savestates");
|
throw std::runtime_error("movie.to_rewind only allows savestates");
|
||||||
lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(L);
|
lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(L);
|
||||||
u2->state = mfile.savestate;
|
u2->dstate = mfile.dynamic;
|
||||||
if(u2->state.size() >= 32)
|
if(u2->dstate.savestate.size() >= 32)
|
||||||
u2->state.resize(u2->state.size() - 32);
|
u2->dstate.savestate.resize(u2->dstate.savestate.size() - 32);
|
||||||
u2->secs = mfile.rtc_second;
|
|
||||||
u2->ssecs = mfile.rtc_subsecond;
|
|
||||||
u2->pollcounters = mfile.pollcounters;
|
|
||||||
u2->lag = mfile.lagged_frames;
|
|
||||||
u2->frame = mfile.save_frame;
|
|
||||||
u2->hostmemory = mfile.host_memory;
|
|
||||||
//Now the remaining field ptr is somewhat nastier.
|
//Now the remaining field ptr is somewhat nastier.
|
||||||
uint64_t f = 0;
|
uint64_t f = 0;
|
||||||
uint64_t s = mfile.input->size();
|
uint64_t s = mfile.input->size();
|
||||||
u2->ptr = 0;
|
u2->dstate.movie_ptr = 0;
|
||||||
while(++f < u2->frame) {
|
while(++f < u2->dstate.save_frame) {
|
||||||
if(u2->ptr < s)
|
if(u2->dstate.movie_ptr < s)
|
||||||
u2->ptr++;
|
u2->dstate.movie_ptr++;
|
||||||
while(u2->ptr < s && !(*mfile.input)[u2->ptr].sync())
|
while(u2->dstate.movie_ptr < s && !(*mfile.input)[u2->dstate.movie_ptr].sync())
|
||||||
u2->ptr++;
|
u2->dstate.movie_ptr++;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lua::functions LUA_movie_fns(lua_func_misc, "movie", {
|
lua::functions LUA_movie_fns(lua_func_misc, "movie", {
|
||||||
{"currentframe", currentframe},
|
{"currentframe", currentframe},
|
||||||
|
{"currentvi", currentvi},
|
||||||
{"lagcount", lagcounter},
|
{"lagcount", lagcounter},
|
||||||
{"framecount", framecount},
|
{"framecount", framecount},
|
||||||
{"rerecords", rerecords},
|
{"rerecords", rerecords},
|
||||||
|
|
|
@ -1310,6 +1310,8 @@ void wxwin_mainwindow::update_statusbar()
|
||||||
s << "Frame: " << vars.curframe;
|
s << "Frame: " << vars.curframe;
|
||||||
else
|
else
|
||||||
s << "Frame: " << vars.curframe << "/" << vars.length;
|
s << "Frame: " << vars.curframe << "/" << vars.length;
|
||||||
|
if(vars.vi_valid)
|
||||||
|
s << " VI: " << vars.vi_counter;
|
||||||
s << " Lag: " << vars.lag;
|
s << " Lag: " << vars.lag;
|
||||||
if(vars.subframe == _lsnes_status::subframe_savepoint)
|
if(vars.subframe == _lsnes_status::subframe_savepoint)
|
||||||
s << " Subframe: S";
|
s << " Subframe: S";
|
||||||
|
|
|
@ -698,8 +698,10 @@ struct moviefile& wxwin_project::make_movie()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.is_savestate = false;
|
f.is_savestate = false;
|
||||||
f.movie_rtc_second = f.rtc_second = boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
|
f.movie_rtc_second = boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
|
||||||
f.movie_rtc_subsecond = f.rtc_subsecond = boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
|
f.movie_rtc_subsecond = boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
|
||||||
|
f.dynamic.rtc_second = f.movie_rtc_second;
|
||||||
|
f.dynamic.rtc_subsecond = f.movie_rtc_subsecond;
|
||||||
if(f.movie_rtc_subsecond < 0)
|
if(f.movie_rtc_subsecond < 0)
|
||||||
throw std::runtime_error("RTC subsecond must be positive");
|
throw std::runtime_error("RTC subsecond must be positive");
|
||||||
auto ctrldata = inst.rom->controllerconfig(f.settings);
|
auto ctrldata = inst.rom->controllerconfig(f.settings);
|
||||||
|
|
Loading…
Add table
Reference in a new issue