Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
|
6736ecc285 | ||
|
425e1fc097 |
30 changed files with 679 additions and 76 deletions
|
@ -51,6 +51,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&);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -236,6 +236,18 @@ struct moviefile
|
||||||
* Active macros at savestate.
|
* Active macros at savestate.
|
||||||
*/
|
*/
|
||||||
std::map<std::string, uint64_t> active_macros;
|
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;
|
||||||
/**
|
/**
|
||||||
* 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 >= 2
|
||||||
|
#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
|
||||||
|
@ -349,6 +350,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.
|
||||||
|
|
|
@ -611,6 +611,7 @@ public:
|
||||||
std::vector<std::string> get_trace_cpus() { return core->get_trace_cpus(); }
|
std::vector<std::string> get_trace_cpus() { return core->get_trace_cpus(); }
|
||||||
void debug_reset() { core->debug_reset(); }
|
void debug_reset() { core->debug_reset(); }
|
||||||
bool isnull() { return core->isnull(); }
|
bool isnull() { return core->isnull(); }
|
||||||
|
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.
|
||||||
|
@ -630,6 +631,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&);
|
||||||
|
|
|
@ -191,6 +191,7 @@ struct port_controller_button
|
||||||
TYPE_RAXIS, //Relative Axis (mouse).
|
TYPE_RAXIS, //Relative Axis (mouse).
|
||||||
TYPE_TAXIS, //Throttle Axis (does not pair).
|
TYPE_TAXIS, //Throttle Axis (does not pair).
|
||||||
TYPE_LIGHTGUN, //Lightgun axis.
|
TYPE_LIGHTGUN, //Lightgun axis.
|
||||||
|
TYPE_KEYBOARD, //Keyboard. The names are translated via namemap.
|
||||||
};
|
};
|
||||||
enum _type type;
|
enum _type type;
|
||||||
char32_t symbol;
|
char32_t symbol;
|
||||||
|
@ -216,6 +217,8 @@ struct port_controller
|
||||||
std::string cclass; //Controller class.
|
std::string cclass; //Controller class.
|
||||||
std::string type; //Controller type.
|
std::string type; //Controller type.
|
||||||
std::vector<port_controller_button> buttons; //Buttons.
|
std::vector<port_controller_button> buttons; //Buttons.
|
||||||
|
std::map<signed, std::u32string> namemap; //Button translation map.
|
||||||
|
unsigned reserved_idx; //Number of extra reserved indices.
|
||||||
/**
|
/**
|
||||||
* Count number of analog actions on this controller.
|
* Count number of analog actions on this controller.
|
||||||
*/
|
*/
|
||||||
|
@ -233,6 +236,15 @@ struct port_controller
|
||||||
return NULL;
|
return NULL;
|
||||||
return &buttons[i];
|
return &buttons[i];
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Access specified entry in namemap. Returns '???' if unknown.
|
||||||
|
*/
|
||||||
|
std::u32string get_namemap_entry(short entry) const
|
||||||
|
{
|
||||||
|
if(!namemap.count(entry))
|
||||||
|
return U"???";
|
||||||
|
return namemap.find(entry)->second;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -336,12 +348,12 @@ public:
|
||||||
* Get number of used control indices on controller.
|
* Get number of used control indices on controller.
|
||||||
*
|
*
|
||||||
* Parameter controller: Number of controller.
|
* Parameter controller: Number of controller.
|
||||||
* Returns: Number of used control indices.
|
* Returns: Number of used control indices. First is number of actual indices, second is number of reserved ones.
|
||||||
*/
|
*/
|
||||||
unsigned used_indices(unsigned controller)
|
std::pair<unsigned, unsigned> used_indices(unsigned controller) const
|
||||||
{
|
{
|
||||||
auto c = controller_info->get(controller);
|
auto c = controller_info->get(controller);
|
||||||
return c ? c->buttons.size() : 0;
|
return c ? std::make_pair((unsigned)c->buttons.size(), c->reserved_idx) : std::make_pair(0U, 0U);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Human-readable name.
|
* Human-readable name.
|
||||||
|
@ -519,6 +531,12 @@ public:
|
||||||
throw std::runtime_error("Bad legacy PCID");
|
throw std::runtime_error("Bad legacy PCID");
|
||||||
return legacy_pcids[pcid];
|
return legacy_pcids[pcid];
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Set pollcounters mask.
|
||||||
|
*
|
||||||
|
* Parameter mask: The mask to write.
|
||||||
|
*/
|
||||||
|
void set_pollcounter_mask(uint32_t* mask) const;
|
||||||
private:
|
private:
|
||||||
port_type_set(std::vector<class port_type*> types, struct port_index_map control_map);
|
port_type_set(std::vector<class port_type*> types, struct port_index_map control_map);
|
||||||
size_t* port_offsets;
|
size_t* port_offsets;
|
||||||
|
@ -566,10 +584,14 @@ public:
|
||||||
* Assign the pollcounter_vector.
|
* Assign the pollcounter_vector.
|
||||||
*/
|
*/
|
||||||
pollcounter_vector& operator=(const pollcounter_vector& v) throw(std::bad_alloc);
|
pollcounter_vector& operator=(const pollcounter_vector& v) throw(std::bad_alloc);
|
||||||
|
/**
|
||||||
|
* Zero all unmasked poll counters and clear all DRDY bits. System flag is cleared.
|
||||||
|
*/
|
||||||
|
void clear_unmasked() throw();
|
||||||
/**
|
/**
|
||||||
* Zero all poll counters and clear all DRDY bits. System flag is cleared.
|
* Zero all poll counters and clear all DRDY bits. System flag is cleared.
|
||||||
*/
|
*/
|
||||||
void clear() throw();
|
void clear_all() throw();
|
||||||
/**
|
/**
|
||||||
* Set all DRDY bits.
|
* Set all DRDY bits.
|
||||||
*/
|
*/
|
||||||
|
@ -707,8 +729,47 @@ public:
|
||||||
* Get raw pollcounter data.
|
* Get raw pollcounter data.
|
||||||
*/
|
*/
|
||||||
const uint32_t* rawdata() const throw() { return ctrs; }
|
const uint32_t* rawdata() const throw() { return ctrs; }
|
||||||
|
/**
|
||||||
|
* Write reserved index for controller.
|
||||||
|
*
|
||||||
|
* Parameter port: The port.
|
||||||
|
* Parameter controller: The controller.
|
||||||
|
* Parameter _index: The reserved index (0-based).
|
||||||
|
* Parameter val: The value to write.
|
||||||
|
* Throws std::runtime_error: Specified reserved slot is not valid.
|
||||||
|
*/
|
||||||
|
void reserved(unsigned port, unsigned controller, unsigned _index, uint32_t val)
|
||||||
|
throw(std::runtime_error)
|
||||||
|
{
|
||||||
|
auto counts = (port < types->ports()) ? types->port_type(port).used_indices(controller) :
|
||||||
|
std::make_pair(0U, 0U);
|
||||||
|
unsigned pindex = types->triple_to_index(port, controller, _index + counts.first);
|
||||||
|
if(pindex == 0xFFFFFFFFU)
|
||||||
|
throw std::runtime_error("write_reserved: Invalid reserved index");
|
||||||
|
ctrs[pindex] = val;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Read reserved index for controller.
|
||||||
|
*
|
||||||
|
* Parameter port: The port.
|
||||||
|
* Parameter controller: The controller.
|
||||||
|
* Parameter _index: The reserved index (0-based).
|
||||||
|
* Returns: The value read.
|
||||||
|
* Throws std::runtime_error: Specified reserved slot is not valid.
|
||||||
|
*/
|
||||||
|
uint32_t reserved(unsigned port, unsigned controller, unsigned _index)
|
||||||
|
throw(std::runtime_error)
|
||||||
|
{
|
||||||
|
auto counts = (port < types->ports()) ? types->port_type(port).used_indices(controller) :
|
||||||
|
std::make_pair(0U, 0U);
|
||||||
|
unsigned pindex = types->triple_to_index(port, controller, _index + counts.first);
|
||||||
|
if(pindex == 0xFFFFFFFFU)
|
||||||
|
throw std::runtime_error("write_reserved: Invalid reserved index");
|
||||||
|
return ctrs[pindex];
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
uint32_t* ctrs;
|
uint32_t* ctrs;
|
||||||
|
uint32_t* ctrs_valid_mask;
|
||||||
const port_type_set* types;
|
const port_type_set* types;
|
||||||
bool framepflag;
|
bool framepflag;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,8 @@ struct lua_unsaferewind
|
||||||
uint64_t ptr;
|
uint64_t ptr;
|
||||||
uint64_t secs;
|
uint64_t secs;
|
||||||
uint64_t ssecs;
|
uint64_t ssecs;
|
||||||
|
uint64_t vi_counter;
|
||||||
|
uint32_t vi_this_frame;
|
||||||
std::vector<uint32_t> pollcounters;
|
std::vector<uint32_t> pollcounters;
|
||||||
std::vector<char> hostmemory;
|
std::vector<char> hostmemory;
|
||||||
std::string print()
|
std::string print()
|
||||||
|
|
12
lua.lyx
12
lua.lyx
|
@ -6255,6 +6255,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
|
||||||
|
|
|
@ -193,6 +193,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().vi_counter;
|
||||||
//Lua variables.
|
//Lua variables.
|
||||||
_status.lvars = lua2.get_watch_vars();
|
_status.lvars = lua2.get_watch_vars();
|
||||||
//Memory watches.
|
//Memory watches.
|
||||||
|
|
|
@ -121,6 +121,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()
|
||||||
|
|
|
@ -90,7 +90,8 @@ controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_allo
|
||||||
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()) {
|
||||||
|
@ -156,8 +157,11 @@ controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_allo
|
||||||
}
|
}
|
||||||
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();
|
||||||
|
//TODO: Collapse keyboard symbols.
|
||||||
controller_frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
|
controller_frame tmp = core.controls->get(core.mlogic->get_movie().get_current_frame());
|
||||||
core.rom->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
|
core.rom->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
|
||||||
core.lua2->callback_do_input(tmp, subframe);
|
core.lua2->callback_do_input(tmp, subframe);
|
||||||
|
@ -273,7 +277,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.vi_this_frame++;
|
||||||
|
mfile.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();
|
||||||
|
@ -847,7 +858,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 : "";
|
||||||
|
@ -930,6 +941,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()
|
||||||
{
|
{
|
||||||
|
@ -1023,6 +1045,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();
|
||||||
|
|
||||||
|
@ -1032,7 +1058,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) {
|
||||||
|
@ -1079,9 +1107,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().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();
|
||||||
|
|
|
@ -437,6 +437,19 @@ 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.host_memory.clear();
|
||||||
|
core.mlogic->get_movie().reset_state();
|
||||||
|
mf.vi_valid = true;
|
||||||
|
mf.vi_counter = 0;
|
||||||
|
mf.vi_this_frame = 0;
|
||||||
|
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)
|
||||||
|
@ -468,10 +481,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();
|
||||||
|
@ -484,25 +494,16 @@ 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()->save_frame = 0;
|
|
||||||
_movie.get()->lagged_frames = 0;
|
|
||||||
_movie.get()->poll_flag = false;
|
|
||||||
_movie.get()->movie_rtc_second = _movie.get()->rtc_second = 1000000000ULL;
|
_movie.get()->movie_rtc_second = _movie.get()->rtc_second = 1000000000ULL;
|
||||||
_movie.get()->movie_rtc_subsecond = _movie.get()->rtc_subsecond = 0;
|
_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;
|
|
||||||
port_type_set& portset2 = construct_movie_portset(*_movie.get(), *core.rom);
|
port_type_set& portset2 = construct_movie_portset(*_movie.get(), *core.rom);
|
||||||
_movie.get()->input = NULL;
|
_movie.get()->input = NULL;
|
||||||
_movie.get()->create_default_branch(portset2);
|
_movie.get()->create_default_branch(portset2);
|
||||||
|
@ -564,10 +565,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();
|
||||||
|
@ -760,6 +758,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.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.vi_counter = (f > 0) ? (f - 1) : 0;
|
||||||
|
_movie.vi_this_frame = 0;
|
||||||
|
_movie.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.
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -177,6 +185,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(vi_counter);
|
||||||
|
s.number(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 +225,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);
|
||||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||||
input = NULL;
|
input = NULL;
|
||||||
|
vi_valid = false;
|
||||||
|
|
||||||
in.extension({
|
in.extension({
|
||||||
{TAG_ANCHOR_SAVE, [this](binarystream::input& s) {
|
{TAG_ANCHOR_SAVE, [this](binarystream::input& s) {
|
||||||
|
@ -288,6 +302,10 @@ void moviefile::binary_io(int _stream, core_type& romtype) throw(std::bad_alloc,
|
||||||
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) {
|
||||||
|
vi_counter = s.number();
|
||||||
|
vi_this_frame = s.number();
|
||||||
|
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);
|
||||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||||
|
|
||||||
|
vi_valid = true;
|
||||||
|
vi_counter = 0;
|
||||||
|
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);
|
||||||
|
@ -271,6 +278,12 @@ void moviefile::load(zip::reader& r, core_type& romtype) throw(std::bad_alloc, s
|
||||||
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")) {
|
||||||
|
vi_valid = false;
|
||||||
|
if(r.has_member("vicounter")) {
|
||||||
|
r.read_numeric_file("vicounter", vi_counter);
|
||||||
|
r.read_numeric_file("vithisframe", vi_this_frame);
|
||||||
|
vi_valid = true;
|
||||||
|
}
|
||||||
is_savestate = true;
|
is_savestate = true;
|
||||||
r.read_numeric_file("saveframe", save_frame, true);
|
r.read_numeric_file("saveframe", save_frame, true);
|
||||||
r.read_numeric_file("lagcounter", lagged_frames, true);
|
r.read_numeric_file("lagcounter", lagged_frames, true);
|
||||||
|
|
|
@ -173,8 +173,10 @@ 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("vicounter", vi_counter);
|
||||||
|
w.write_numeric_file("vithisframe", vi_this_frame);
|
||||||
w.write_numeric_file("saveframe", save_frame);
|
w.write_numeric_file("saveframe", save_frame);
|
||||||
w.write_numeric_file("lagcounter", lagged_frames);
|
w.write_numeric_file("lagcounter", lagged_frames);
|
||||||
write_pollcounters(w, "pollcounters", pollcounters);
|
write_pollcounters(w, "pollcounters", pollcounters);
|
||||||
|
|
|
@ -109,12 +109,18 @@ moviefile::moviefile() throw(std::bad_alloc)
|
||||||
coreversion = "";
|
coreversion = "";
|
||||||
projectid = "";
|
projectid = "";
|
||||||
rerecords = "0";
|
rerecords = "0";
|
||||||
|
rerecords_mem = 0;
|
||||||
is_savestate = false;
|
is_savestate = false;
|
||||||
|
save_frame = 0;
|
||||||
|
lagged_frames = 0;
|
||||||
movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND;
|
movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND;
|
||||||
movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||||
start_paused = false;
|
start_paused = false;
|
||||||
lazy_project_create = true;
|
lazy_project_create = true;
|
||||||
poll_flag = 0;
|
poll_flag = 0;
|
||||||
|
vi_valid = true;
|
||||||
|
vi_counter = 0;
|
||||||
|
vi_this_frame = 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,7 +131,10 @@ 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;
|
||||||
|
save_frame = 0;
|
||||||
|
lagged_frames = 0;
|
||||||
movie_rtc_second = rtc_second = rtc_sec;
|
movie_rtc_second = rtc_second = rtc_sec;
|
||||||
movie_rtc_subsecond = rtc_subsecond = rtc_subsec;
|
movie_rtc_subsecond = rtc_subsecond = rtc_subsec;
|
||||||
start_paused = false;
|
start_paused = false;
|
||||||
|
@ -133,6 +142,9 @@ moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_sett
|
||||||
poll_flag = 0;
|
poll_flag = 0;
|
||||||
settings = c_settings;
|
settings = c_settings;
|
||||||
input = NULL;
|
input = NULL;
|
||||||
|
vi_valid = true;
|
||||||
|
vi_counter = 0;
|
||||||
|
vi_this_frame = 0;
|
||||||
auto ctrldata = rom.controllerconfig(settings);
|
auto ctrldata = rom.controllerconfig(settings);
|
||||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||||
create_default_branch(ports);
|
create_default_branch(ports);
|
||||||
|
@ -329,6 +341,9 @@ void moviefile::copy_fields(const moviefile& mv)
|
||||||
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;
|
active_macros = mv.active_macros;
|
||||||
|
vi_valid = mv.vi_valid;
|
||||||
|
vi_counter = mv.vi_counter;
|
||||||
|
vi_this_frame = mv.vi_this_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
void moviefile::fork_branch(const std::string& oldname, const std::string& newname)
|
void moviefile::fork_branch(const std::string& oldname, const std::string& newname)
|
||||||
|
|
|
@ -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/controller-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(controller_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;
|
||||||
|
}
|
|
@ -667,6 +667,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;
|
||||||
|
@ -690,8 +694,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, port_type*> _ports,
|
c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, port_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()
|
||||||
|
@ -748,6 +753,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)
|
||||||
|
@ -778,6 +787,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;
|
||||||
|
@ -1056,12 +1066,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize_core2(entrypoint_fn fn, std::map<unsigned, core_sysregion*>& sysregs,
|
void initialize_core2(entrypoint_fn fn, std::map<unsigned, core_sysregion*>& sysregs,
|
||||||
|
@ -1085,7 +1096,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 = 1;
|
r.emu_flags1 = 2;
|
||||||
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;
|
||||||
|
|
|
@ -569,6 +569,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()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,8 +159,10 @@ port_type_set::port_type_set(std::vector<class port_type*> types, struct port_in
|
||||||
//Count maximum number of controller indices to determine the controller multiplier.
|
//Count maximum number of controller indices to determine the controller multiplier.
|
||||||
controller_multiplier = 1;
|
controller_multiplier = 1;
|
||||||
for(size_t i = 0; i < port_count; i++)
|
for(size_t i = 0; i < port_count; i++)
|
||||||
for(unsigned j = 0; j < types[i]->controller_info->controllers.size(); j++)
|
for(unsigned j = 0; j < types[i]->controller_info->controllers.size(); j++) {
|
||||||
controller_multiplier = max(controller_multiplier, (size_t)types[i]->used_indices(j));
|
auto idxcnt = types[i]->used_indices(j);
|
||||||
|
controller_multiplier = max(controller_multiplier, (size_t)(idxcnt.first + idxcnt.second));
|
||||||
|
}
|
||||||
//Count maximum number of controllers to determine the port multiplier.
|
//Count maximum number of controllers to determine the port multiplier.
|
||||||
port_multiplier = 1;
|
port_multiplier = 1;
|
||||||
for(size_t i = 0; i < port_count; i++)
|
for(size_t i = 0; i < port_count; i++)
|
||||||
|
@ -193,6 +195,28 @@ port_type_set::port_type_set(std::vector<class port_type*> types, struct port_in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void port_type_set::set_pollcounter_mask(uint32_t* mask) const
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < indices_size; i++) {
|
||||||
|
unsigned v = indices_tab[i];
|
||||||
|
//i is the index into map (which decomposes into triple). v is the index in array (which may be
|
||||||
|
//invalid).
|
||||||
|
if(v == 0xFFFFFFFFUL)
|
||||||
|
continue;
|
||||||
|
unsigned _port = i / port_multiplier;
|
||||||
|
unsigned _controller = (i % port_multiplier) / controller_multiplier;
|
||||||
|
unsigned _button = i % controller_multiplier;
|
||||||
|
if(_port >= port_count)
|
||||||
|
continue;
|
||||||
|
//Determine if this is reserved or not (it is reserved if index is beyond limit) and set bit.
|
||||||
|
auto idxcnt = port_types[_port]->used_indices(_controller);
|
||||||
|
if(_button >= idxcnt.first)
|
||||||
|
mask[v >> 5] &= ~(1U << (v & 31));
|
||||||
|
else
|
||||||
|
mask[v >> 5] |= (1U << (v & 31));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
short read_axis_value(const char* buf, size_t& idx) throw()
|
short read_axis_value(const char* buf, size_t& idx) throw()
|
||||||
{
|
{
|
||||||
char ch;
|
char ch;
|
||||||
|
@ -272,7 +296,6 @@ void controller_frame::display(unsigned port, unsigned controller, char32_t* buf
|
||||||
}
|
}
|
||||||
const port_controller& pc = ptype.controller_info->controllers[controller];
|
const port_controller& pc = ptype.controller_info->controllers[controller];
|
||||||
bool need_space = false;
|
bool need_space = false;
|
||||||
short val;
|
|
||||||
for(unsigned i = 0; i < pc.buttons.size(); i++) {
|
for(unsigned i = 0; i < pc.buttons.size(); i++) {
|
||||||
const port_controller_button& pcb = pc.buttons[i];
|
const port_controller_button& pcb = pc.buttons[i];
|
||||||
if(need_space && pcb.type != port_controller_button::TYPE_NULL) {
|
if(need_space && pcb.type != port_controller_button::TYPE_NULL) {
|
||||||
|
@ -289,8 +312,14 @@ void controller_frame::display(unsigned port, unsigned controller, char32_t* buf
|
||||||
case port_controller_button::TYPE_RAXIS:
|
case port_controller_button::TYPE_RAXIS:
|
||||||
case port_controller_button::TYPE_TAXIS:
|
case port_controller_button::TYPE_TAXIS:
|
||||||
case port_controller_button::TYPE_LIGHTGUN:
|
case port_controller_button::TYPE_LIGHTGUN:
|
||||||
val = ptype.read(&ptype, backingmem, controller, i);
|
buf += writeu32val(buf, ptype.read(&ptype, backingmem, controller, i));
|
||||||
buf += writeu32val(buf, val);
|
need_space = true;
|
||||||
|
break;
|
||||||
|
case port_controller_button::TYPE_KEYBOARD:
|
||||||
|
//Write name.
|
||||||
|
auto str = pc.get_namemap_entry(ptype.read(&ptype, backingmem, controller, i));
|
||||||
|
for(auto x : str)
|
||||||
|
*(buf++) = x;
|
||||||
need_space = true;
|
need_space = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -301,22 +330,34 @@ void controller_frame::display(unsigned port, unsigned controller, char32_t* buf
|
||||||
pollcounter_vector::pollcounter_vector() throw(std::bad_alloc)
|
pollcounter_vector::pollcounter_vector() throw(std::bad_alloc)
|
||||||
{
|
{
|
||||||
types = &dummytypes();
|
types = &dummytypes();
|
||||||
ctrs = new uint32_t[types->indices()];
|
size_t elts_base = types->indices();
|
||||||
clear();
|
size_t elts_mask = (elts_base + 31) / 32;
|
||||||
|
size_t elts_all = elts_base + elts_mask;
|
||||||
|
ctrs = new uint32_t[elts_all];
|
||||||
|
memset(ctrs_valid_mask = ctrs + elts_base, 0xFF, sizeof(uint32_t) * elts_mask);
|
||||||
|
clear_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
pollcounter_vector::pollcounter_vector(const port_type_set& p) throw(std::bad_alloc)
|
pollcounter_vector::pollcounter_vector(const port_type_set& p) throw(std::bad_alloc)
|
||||||
{
|
{
|
||||||
types = &p;
|
types = &p;
|
||||||
ctrs = new uint32_t[types->indices()];
|
size_t elts_base = types->indices();
|
||||||
clear();
|
size_t elts_mask = (elts_base + 31) / 32;
|
||||||
|
size_t elts_all = elts_base + elts_mask;
|
||||||
|
ctrs = new uint32_t[elts_all];
|
||||||
|
types->set_pollcounter_mask(ctrs_valid_mask = ctrs + elts_base);
|
||||||
|
clear_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
pollcounter_vector::pollcounter_vector(const pollcounter_vector& p) throw(std::bad_alloc)
|
pollcounter_vector::pollcounter_vector(const pollcounter_vector& p) throw(std::bad_alloc)
|
||||||
{
|
{
|
||||||
ctrs = new uint32_t[p.types->indices()];
|
size_t elts_base = p.types->indices();
|
||||||
|
size_t elts_mask = (elts_base + 31) / 32;
|
||||||
|
size_t elts_all = elts_base + elts_mask;
|
||||||
|
ctrs = new uint32_t[elts_all];
|
||||||
|
ctrs_valid_mask = ctrs + elts_base;
|
||||||
types = p.types;
|
types = p.types;
|
||||||
memcpy(ctrs, p.ctrs, sizeof(uint32_t) * p.types->indices());
|
memcpy(ctrs, p.ctrs, sizeof(uint32_t) * elts_all);
|
||||||
framepflag = p.framepflag;
|
framepflag = p.framepflag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,21 +365,34 @@ pollcounter_vector& pollcounter_vector::operator=(const pollcounter_vector& p) t
|
||||||
{
|
{
|
||||||
if(this == &p)
|
if(this == &p)
|
||||||
return *this;
|
return *this;
|
||||||
uint32_t* n = new uint32_t[p.types->indices()];
|
size_t elts_base = p.types->indices();
|
||||||
|
size_t elts_mask = (elts_base + 31) / 32;
|
||||||
|
size_t elts_all = elts_base + elts_mask;
|
||||||
|
uint32_t* n = new uint32_t[elts_all];
|
||||||
types = p.types;
|
types = p.types;
|
||||||
memcpy(n, p.ctrs, sizeof(uint32_t) * p.types->indices());
|
memcpy(n, p.ctrs, sizeof(uint32_t) * elts_all);
|
||||||
delete[] ctrs;
|
delete[] ctrs;
|
||||||
ctrs = n;
|
ctrs = n;
|
||||||
|
ctrs_valid_mask = ctrs + elts_base;
|
||||||
framepflag = p.framepflag;
|
framepflag = p.framepflag;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
pollcounter_vector::~pollcounter_vector() throw()
|
pollcounter_vector::~pollcounter_vector() throw()
|
||||||
{
|
{
|
||||||
|
//ctrs_valid_mask is part of this.
|
||||||
delete[] ctrs;
|
delete[] ctrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pollcounter_vector::clear() throw()
|
void pollcounter_vector::clear_unmasked() throw()
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < types->indices(); i++)
|
||||||
|
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1)
|
||||||
|
ctrs[i] = 0;
|
||||||
|
framepflag = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pollcounter_vector::clear_all() throw()
|
||||||
{
|
{
|
||||||
memset(ctrs, 0, sizeof(uint32_t) * types->indices());
|
memset(ctrs, 0, sizeof(uint32_t) * types->indices());
|
||||||
framepflag = false;
|
framepflag = false;
|
||||||
|
@ -346,46 +400,65 @@ void pollcounter_vector::clear() throw()
|
||||||
|
|
||||||
void pollcounter_vector::set_all_DRDY() throw()
|
void pollcounter_vector::set_all_DRDY() throw()
|
||||||
{
|
{
|
||||||
|
//Only manipulate valid pcounters.
|
||||||
for(size_t i = 0; i < types->indices(); i++)
|
for(size_t i = 0; i < types->indices(); i++)
|
||||||
ctrs[i] |= 0x80000000UL;
|
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1)
|
||||||
|
ctrs[i] |= 0x80000000UL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pollcounter_vector::clear_DRDY(unsigned idx) throw()
|
void pollcounter_vector::clear_DRDY(unsigned idx) throw()
|
||||||
{
|
{
|
||||||
ctrs[idx] &= 0x7FFFFFFFUL;
|
//Only manipulate valid pcounters.
|
||||||
|
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1)
|
||||||
|
ctrs[idx] &= 0x7FFFFFFFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pollcounter_vector::get_DRDY(unsigned idx) throw()
|
bool pollcounter_vector::get_DRDY(unsigned idx) throw()
|
||||||
{
|
{
|
||||||
return ((ctrs[idx] & 0x80000000UL) != 0);
|
//For not valid pcounters, DRDY is permanently 1.
|
||||||
|
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1)
|
||||||
|
return ((ctrs[idx] & 0x80000000UL) != 0);
|
||||||
|
else
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pollcounter_vector::has_polled() throw()
|
bool pollcounter_vector::has_polled() throw()
|
||||||
{
|
{
|
||||||
uint32_t res = 0;
|
uint32_t res = 0;
|
||||||
for(size_t i = 0; i < types->indices() ; i++)
|
for(size_t i = 0; i < types->indices(); i++)
|
||||||
res |= ctrs[i];
|
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1)
|
||||||
|
res |= ctrs[i];
|
||||||
return ((res & 0x7FFFFFFFUL) != 0);
|
return ((res & 0x7FFFFFFFUL) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pollcounter_vector::get_polls(unsigned idx) throw()
|
uint32_t pollcounter_vector::get_polls(unsigned idx) throw()
|
||||||
{
|
{
|
||||||
return ctrs[idx] & 0x7FFFFFFFUL;
|
//For not valid pcounters, polls is permanently 0.
|
||||||
|
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1)
|
||||||
|
return ctrs[idx] & 0x7FFFFFFFUL;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pollcounter_vector::increment_polls(unsigned idx) throw()
|
uint32_t pollcounter_vector::increment_polls(unsigned idx) throw()
|
||||||
{
|
{
|
||||||
uint32_t x = ctrs[idx] & 0x7FFFFFFFUL;
|
//Only manipulate valid pcounters, for others, permanently 0.
|
||||||
++ctrs[idx];
|
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1) {
|
||||||
return x;
|
uint32_t x = ctrs[idx] & 0x7FFFFFFFUL;
|
||||||
|
++ctrs[idx];
|
||||||
|
return x;
|
||||||
|
} else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pollcounter_vector::max_polls() throw()
|
uint32_t pollcounter_vector::max_polls() throw()
|
||||||
{
|
{
|
||||||
uint32_t max = 0;
|
uint32_t max = 0;
|
||||||
for(unsigned i = 0; i < types->indices(); i++) {
|
for(unsigned i = 0; i < types->indices(); i++) {
|
||||||
uint32_t tmp = ctrs[i] & 0x7FFFFFFFUL;
|
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1) {
|
||||||
max = (max < tmp) ? tmp : max;
|
uint32_t tmp = ctrs[i] & 0x7FFFFFFFUL;
|
||||||
|
max = (max < tmp) ? tmp : max;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
@ -393,7 +466,6 @@ uint32_t pollcounter_vector::max_polls() throw()
|
||||||
void pollcounter_vector::save_state(std::vector<uint32_t>& mem) throw(std::bad_alloc)
|
void pollcounter_vector::save_state(std::vector<uint32_t>& mem) throw(std::bad_alloc)
|
||||||
{
|
{
|
||||||
mem.resize(types->indices());
|
mem.resize(types->indices());
|
||||||
//Compatiblity fun.
|
|
||||||
for(size_t i = 0; i < types->indices(); i++)
|
for(size_t i = 0; i < types->indices(); i++)
|
||||||
mem[i] = ctrs[i];
|
mem[i] = ctrs[i];
|
||||||
}
|
}
|
||||||
|
@ -824,6 +896,7 @@ unsigned port_controller::analog_actions() const
|
||||||
break;
|
break;
|
||||||
case port_controller_button::TYPE_NULL:
|
case port_controller_button::TYPE_NULL:
|
||||||
case port_controller_button::TYPE_BUTTON:
|
case port_controller_button::TYPE_BUTTON:
|
||||||
|
case port_controller_button::TYPE_KEYBOARD:
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -868,6 +941,7 @@ std::pair<unsigned, unsigned> port_controller::analog_action(unsigned k) const
|
||||||
break;
|
break;
|
||||||
case port_controller_button::TYPE_NULL:
|
case port_controller_button::TYPE_NULL:
|
||||||
case port_controller_button::TYPE_BUTTON:
|
case port_controller_button::TYPE_BUTTON:
|
||||||
|
case port_controller_button::TYPE_KEYBOARD:
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,22 @@ namespace
|
||||||
return y.str();
|
return y.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string quote(const std::u32string& _s)
|
||||||
|
{
|
||||||
|
auto s = utf8::to8(_s);
|
||||||
|
std::ostringstream y;
|
||||||
|
y << "U\"";
|
||||||
|
for(auto i : s)
|
||||||
|
if(i == '\"')
|
||||||
|
y << "\"";
|
||||||
|
else if(i == '\\')
|
||||||
|
y << "\\\\";
|
||||||
|
else
|
||||||
|
y << i;
|
||||||
|
y << "\"";
|
||||||
|
return y.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string read_str(const JSON::node& root, const JSON::pointer& ptr)
|
std::string read_str(const JSON::node& root, const JSON::pointer& ptr)
|
||||||
{
|
{
|
||||||
if(root.type_of(ptr) != JSON::string)
|
if(root.type_of(ptr) != JSON::string)
|
||||||
|
@ -117,6 +133,22 @@ namespace
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
port_controller_button pcb_key(const JSON::node& root, const JSON::pointer& ptr)
|
||||||
|
{
|
||||||
|
auto pshadow = ptr.field("shadow");
|
||||||
|
auto pname = ptr.field("name");
|
||||||
|
struct port_controller_button ret;
|
||||||
|
ret.type = port_controller_button::TYPE_KEYBOARD;
|
||||||
|
ret.symbol = U'\0';
|
||||||
|
ret.shadow = (root.type_of(pshadow) != JSON::none) ? read_bool(root, pshadow) : false;
|
||||||
|
ret.rmin = 0;
|
||||||
|
ret.rmax = 0;
|
||||||
|
ret.centers = false;
|
||||||
|
ret.macro = "";
|
||||||
|
ret.msymbol = '\0';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
struct port_controller_button pcs_parse_button(const JSON::node& root, JSON::pointer ptr)
|
struct port_controller_button pcs_parse_button(const JSON::node& root, JSON::pointer ptr)
|
||||||
{
|
{
|
||||||
if(root.type_of_indirect(ptr) != JSON::object)
|
if(root.type_of_indirect(ptr) != JSON::object)
|
||||||
|
@ -129,6 +161,8 @@ namespace
|
||||||
return pcb_button(root, ptr);
|
return pcb_button(root, ptr);
|
||||||
else if(type == "axis" || type == "raxis" || type == "taxis" || type == "lightgun")
|
else if(type == "axis" || type == "raxis" || type == "taxis" || type == "lightgun")
|
||||||
return pcb_axis(root, ptr, type);
|
return pcb_axis(root, ptr, type);
|
||||||
|
else if(type == "key")
|
||||||
|
return pcb_key(root, ptr);
|
||||||
else
|
else
|
||||||
(stringfmt() << "Unknown type '" << type << "' for '" << ptr << "'").throwex();
|
(stringfmt() << "Unknown type '" << type << "' for '" << ptr << "'").throwex();
|
||||||
return pcb_null(root, ptr); //NOTREACHED.
|
return pcb_null(root, ptr); //NOTREACHED.
|
||||||
|
@ -153,6 +187,22 @@ namespace
|
||||||
ret.cclass = cclass;
|
ret.cclass = cclass;
|
||||||
ret.type = type;
|
ret.type = type;
|
||||||
ret.buttons = buttons;
|
ret.buttons = buttons;
|
||||||
|
JSON::pointer _buttonmap = ptr.field("buttonmap");
|
||||||
|
//Namemap is OPTIONAL. If present, it must be an array, giving the entries as strings (or nil)
|
||||||
|
//for not present.
|
||||||
|
if(root.type_of_indirect(_buttonmap) != JSON::none) {
|
||||||
|
if(root.type_of_indirect(_buttonmap) != JSON::array)
|
||||||
|
(stringfmt() << "Expected array or not present for '" << _buttonmap << "'").throwex();
|
||||||
|
for(auto i = root[_buttonmap].begin(); i != root[_buttonmap].end(); ++i) {
|
||||||
|
if(i->type() == JSON::string) {
|
||||||
|
ret.namemap[i.index()] = i->as_string();
|
||||||
|
} else if(i->type() != JSON::none) {
|
||||||
|
(stringfmt() << "Expected string or not present for '"
|
||||||
|
<< _buttonmap.index(i.index()) << "'").throwex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret.reserved_idx = (ret.namemap.size() + 31) / 32; //One bit per namemap entry.
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +252,7 @@ namespace
|
||||||
case port_controller_button::TYPE_RAXIS: s << "RAXIS"; break;
|
case port_controller_button::TYPE_RAXIS: s << "RAXIS"; break;
|
||||||
case port_controller_button::TYPE_TAXIS: s << "TAXIS"; break;
|
case port_controller_button::TYPE_TAXIS: s << "TAXIS"; break;
|
||||||
case port_controller_button::TYPE_LIGHTGUN: s << "LIGHTGUN"; break;
|
case port_controller_button::TYPE_LIGHTGUN: s << "LIGHTGUN"; break;
|
||||||
|
case port_controller_button::TYPE_KEYBOARD: s << "KEYBOARD"; break;
|
||||||
}
|
}
|
||||||
s << "," << (int)b.symbol << ", " << quote(b.name) << ", " << b.shadow << ", " << b.rmin << ", "
|
s << "," << (int)b.symbol << ", " << quote(b.name) << ", " << b.shadow << ", " << b.rmin << ", "
|
||||||
<< b.rmax << ", " << b.centers << ", " << quote(b.macro) << ", " << (int)b.msymbol << "}";
|
<< b.rmax << ", " << b.centers << ", " << quote(b.macro) << ", " << (int)b.msymbol << "}";
|
||||||
|
@ -216,7 +267,10 @@ namespace
|
||||||
write_button(s, i);
|
write_button(s, i);
|
||||||
s << ",\n";
|
s << ",\n";
|
||||||
}
|
}
|
||||||
s << "}};\n";
|
s << "},{";
|
||||||
|
for(auto i : c.namemap)
|
||||||
|
s << "\t{" << i.first << ", " << quote(i.second) << "},\n";
|
||||||
|
s << "}," << c.reserved_idx << "};\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_portdata(std::ostream& s, const port_controller_set& cs, unsigned& idx)
|
void write_portdata(std::ostream& s, const port_controller_set& cs, unsigned& idx)
|
||||||
|
@ -249,6 +303,7 @@ namespace
|
||||||
case port_controller_button::TYPE_NULL: break;
|
case port_controller_button::TYPE_NULL: break;
|
||||||
case port_controller_button::TYPE_RAXIS: x+=16; break;
|
case port_controller_button::TYPE_RAXIS: x+=16; break;
|
||||||
case port_controller_button::TYPE_TAXIS: x+=16; break;
|
case port_controller_button::TYPE_TAXIS: x+=16; break;
|
||||||
|
case port_controller_button::TYPE_KEYBOARD: x+=16; break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return (x + 7) / 8;
|
return (x + 7) / 8;
|
||||||
|
@ -266,6 +321,7 @@ namespace
|
||||||
case port_controller_button::TYPE_NULL: break;
|
case port_controller_button::TYPE_NULL: break;
|
||||||
case port_controller_button::TYPE_RAXIS: break;
|
case port_controller_button::TYPE_RAXIS: break;
|
||||||
case port_controller_button::TYPE_TAXIS: break;
|
case port_controller_button::TYPE_TAXIS: break;
|
||||||
|
case port_controller_button::TYPE_KEYBOARD: break;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return (x + 7) / 8;
|
return (x + 7) / 8;
|
||||||
|
@ -297,6 +353,7 @@ namespace
|
||||||
case port_controller_button::TYPE_RAXIS:
|
case port_controller_button::TYPE_RAXIS:
|
||||||
case port_controller_button::TYPE_TAXIS:
|
case port_controller_button::TYPE_TAXIS:
|
||||||
case port_controller_button::TYPE_LIGHTGUN:
|
case port_controller_button::TYPE_LIGHTGUN:
|
||||||
|
case port_controller_button::TYPE_KEYBOARD:
|
||||||
ii.type = 2;
|
ii.type = 2;
|
||||||
ii.offset = aoffset + 2 * axisidx2;
|
ii.offset = aoffset + 2 * axisidx2;
|
||||||
axisidx2++;
|
axisidx2++;
|
||||||
|
@ -343,6 +400,7 @@ namespace
|
||||||
case port_controller_button::TYPE_RAXIS:
|
case port_controller_button::TYPE_RAXIS:
|
||||||
case port_controller_button::TYPE_TAXIS:
|
case port_controller_button::TYPE_TAXIS:
|
||||||
case port_controller_button::TYPE_LIGHTGUN:
|
case port_controller_button::TYPE_LIGHTGUN:
|
||||||
|
case port_controller_button::TYPE_KEYBOARD:
|
||||||
ins.type = 1;
|
ins.type = 1;
|
||||||
ins.offset = aoffset + 2 * axisidx;
|
ins.offset = aoffset + 2 * axisidx;
|
||||||
ret.push_back(ins);
|
ret.push_back(ins);
|
||||||
|
|
|
@ -120,7 +120,7 @@ void movie::next_frame() throw(std::bad_alloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Reset the poll counters and DRDY flags.
|
//Reset the poll counters and DRDY flags.
|
||||||
pollcounters.clear();
|
pollcounters.clear_unmasked();
|
||||||
|
|
||||||
//Increment the current frame counter and subframe counter. Note that first subframe is undefined for
|
//Increment the current frame counter and subframe counter. Note that first subframe is undefined for
|
||||||
//frame 0 and 0 for frame 1.
|
//frame 0 and 0 for frame 1.
|
||||||
|
@ -346,7 +346,7 @@ void movie::reset_state() throw()
|
||||||
readonly = true;
|
readonly = true;
|
||||||
current_frame = 0;
|
current_frame = 0;
|
||||||
current_frame_first_subframe = 0;
|
current_frame_first_subframe = 0;
|
||||||
pollcounters.clear();
|
pollcounters.clear_all();
|
||||||
lag_frames = 0;
|
lag_frames = 0;
|
||||||
clear_caches();
|
clear_caches();
|
||||||
}
|
}
|
||||||
|
|
|
@ -465,6 +465,7 @@ namespace
|
||||||
case port_controller_button::TYPE_RAXIS: L.pushstring("raxis"); break;
|
case port_controller_button::TYPE_RAXIS: L.pushstring("raxis"); break;
|
||||||
case port_controller_button::TYPE_TAXIS: L.pushstring("axis"); break;
|
case port_controller_button::TYPE_TAXIS: L.pushstring("axis"); break;
|
||||||
case port_controller_button::TYPE_LIGHTGUN: L.pushstring("lightgun"); break;
|
case port_controller_button::TYPE_LIGHTGUN: L.pushstring("lightgun"); break;
|
||||||
|
case port_controller_button::TYPE_KEYBOARD: L.pushstring("keyboard"); break;
|
||||||
};
|
};
|
||||||
L.rawset(-3);
|
L.rawset(-3);
|
||||||
if(cs.buttons[i].symbol) {
|
if(cs.buttons[i].symbol) {
|
||||||
|
|
|
@ -452,7 +452,11 @@ void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_
|
||||||
run_callback(*on_movie_lost, "unsaferewind");
|
run_callback(*on_movie_lost, "unsaferewind");
|
||||||
mainloop_restore_state(u2->state, u2->secs, u2->ssecs);
|
mainloop_restore_state(u2->state, u2->secs, u2->ssecs);
|
||||||
mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
mov.fast_load(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
||||||
try { core.mlogic->get_mfile().host_memory = u2->hostmemory; } catch(...) {}
|
auto& mf = core.mlogic->get_mfile();
|
||||||
|
mf.vi_counter = u2->vi_counter;
|
||||||
|
mf.vi_this_frame = u2->vi_this_frame;
|
||||||
|
mf.vi_valid = true;
|
||||||
|
try { mf.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(...) {
|
||||||
|
@ -460,13 +464,16 @@ 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, save, secs, ssecs, &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;
|
u2->state = save;
|
||||||
u2->secs = secs,
|
u2->secs = secs,
|
||||||
u2->ssecs = ssecs;
|
u2->ssecs = ssecs;
|
||||||
u2->hostmemory = core.mlogic->get_mfile().host_memory;
|
auto& mf = core.mlogic->get_mfile();
|
||||||
|
u2->vi_this_frame = mf.vi_this_frame;
|
||||||
|
u2->vi_counter = mf.vi_counter;
|
||||||
|
u2->hostmemory = mf.host_memory;
|
||||||
mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
mov.fast_save(u2->frame, u2->ptr, u2->lag, u2->pollcounters);
|
||||||
return 1;
|
return 1;
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -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.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();
|
||||||
|
@ -136,6 +143,7 @@ namespace
|
||||||
|
|
||||||
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},
|
||||||
|
|
|
@ -74,6 +74,16 @@ namespace
|
||||||
uint64_t divsl[] = {1000000, 100000, 10000, 1000, 100, 10, 0};
|
uint64_t divsl[] = {1000000, 100000, 10000, 1000, 100, 10, 0};
|
||||||
const unsigned divcnt = sizeof(divs)/sizeof(divs[0]);
|
const unsigned divcnt = sizeof(divs)/sizeof(divs[0]);
|
||||||
|
|
||||||
|
bool is_ctype(int type)
|
||||||
|
{
|
||||||
|
return (type == 0 || type == 1 || type == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_wtype(int type)
|
||||||
|
{
|
||||||
|
return (type == -1 || type == 1 || type == 2);
|
||||||
|
}
|
||||||
|
|
||||||
class exp_imp_type
|
class exp_imp_type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -110,7 +120,7 @@ struct control_info
|
||||||
unsigned position_left;
|
unsigned position_left;
|
||||||
unsigned reserved; //Must be at least 6 for axes.
|
unsigned reserved; //Must be at least 6 for axes.
|
||||||
unsigned index; //Index in poll vector.
|
unsigned index; //Index in poll vector.
|
||||||
int type; //-2 => Port, -1 => Fixed, 0 => Button, 1 => axis.
|
int type; //-2 => Port, -1 => Fixed, 0 => Button, 1 => axis, 2 => Key
|
||||||
char32_t ch;
|
char32_t ch;
|
||||||
std::u32string title;
|
std::u32string title;
|
||||||
unsigned port;
|
unsigned port;
|
||||||
|
@ -124,6 +134,7 @@ struct control_info
|
||||||
unsigned port, unsigned controller);
|
unsigned port, unsigned controller);
|
||||||
static control_info axisinfo(unsigned& p, const std::u32string& title, unsigned idx,
|
static control_info axisinfo(unsigned& p, const std::u32string& title, unsigned idx,
|
||||||
unsigned port, unsigned controller, port_controller_button::_type _axistype, int _rmin, int _rmax);
|
unsigned port, unsigned controller, port_controller_button::_type _axistype, int _rmin, int _rmax);
|
||||||
|
//TODO: keyinfo().
|
||||||
};
|
};
|
||||||
|
|
||||||
control_info control_info::portinfo(unsigned& p, unsigned port, unsigned controller)
|
control_info control_info::portinfo(unsigned& p, unsigned port, unsigned controller)
|
||||||
|
@ -261,6 +272,8 @@ void frame_controls::add_port(unsigned& c, unsigned pid, const port_type& p, con
|
||||||
controlinfo.push_back(control_info::axisinfo(c, utf8::to32(pcb.name), idx, pid, i,
|
controlinfo.push_back(control_info::axisinfo(c, utf8::to32(pcb.name), idx, pid, i,
|
||||||
pcb.type, pcb.rmin, pcb.rmax));
|
pcb.type, pcb.rmin, pcb.rmax));
|
||||||
last_multibyte = true;
|
last_multibyte = true;
|
||||||
|
} else if(pcb.type == port_controller_button::TYPE_KEYBOARD) {
|
||||||
|
//TODO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(nextp > c)
|
if(nextp > c)
|
||||||
|
@ -322,7 +335,7 @@ void frame_controls::format_lines()
|
||||||
//Line2
|
//Line2
|
||||||
for(auto i : controlinfo) {
|
for(auto i : controlinfo) {
|
||||||
auto _title = i.title;
|
auto _title = i.title;
|
||||||
if(i.type == -1 || i.type == 1)
|
if(is_wtype(i.type))
|
||||||
std::copy(_title.begin(), _title.end(), &cp2[i.position_left + off]);
|
std::copy(_title.begin(), _title.end(), &cp2[i.position_left + off]);
|
||||||
if(i.type == 0)
|
if(i.type == 0)
|
||||||
cp2[i.position_left + off] = i.ch;
|
cp2[i.position_left + off] = i.ch;
|
||||||
|
@ -389,6 +402,9 @@ namespace
|
||||||
first = false;
|
first = false;
|
||||||
last_axis = true;
|
last_axis = true;
|
||||||
break;
|
break;
|
||||||
|
case 2: //key
|
||||||
|
//TODO.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return x.str();
|
return x.str();
|
||||||
|
@ -450,6 +466,9 @@ namespace
|
||||||
first = false;
|
first = false;
|
||||||
last_axis = true;
|
last_axis = true;
|
||||||
break;
|
break;
|
||||||
|
case 2: //Key.
|
||||||
|
//TODO.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -496,7 +515,7 @@ namespace
|
||||||
{
|
{
|
||||||
std::set<unsigned> r;
|
std::set<unsigned> r;
|
||||||
for(auto i : info.get_controlinfo()) {
|
for(auto i : info.get_controlinfo()) {
|
||||||
if(i.port == port && i.controller == controller && (i.type == 0 || i.type == 1))
|
if(i.port == port && i.controller == controller && is_ctype(i.type))
|
||||||
r.insert(i.index);
|
r.insert(i.index);
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
|
@ -1016,6 +1035,9 @@ void wxeditor_movie::_moviepanel::render_linen(text_framebuffer& fb, controller_
|
||||||
char c[7];
|
char c[7];
|
||||||
sprintf(c, "%6d", fcontrols.read_index(f, i.index));
|
sprintf(c, "%6d", fcontrols.read_index(f, i.index));
|
||||||
fb.write(c, 0, divcnt + 1 + i.position_left, y, 0x000000, bgc);
|
fb.write(c, 0, divcnt + 1 + i.position_left, y, 0x000000, bgc);
|
||||||
|
} else if(i.type == 2) {
|
||||||
|
//Key.
|
||||||
|
//TODO.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1416,6 +1438,8 @@ void wxeditor_movie::_moviepanel::on_mouse0(unsigned x, unsigned y, bool polarit
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
do_alter_axis(idx, press_line, line);
|
do_alter_axis(idx, press_line, line);
|
||||||
|
} else if(i.type == 2) {
|
||||||
|
//TODO.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1831,7 +1855,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit
|
||||||
} else {
|
} else {
|
||||||
for(auto i : fcontrols.get_controlinfo())
|
for(auto i : fcontrols.get_controlinfo())
|
||||||
if(press_x >= i.position_left + off && press_x < i.position_left + i.reserved + off) {
|
if(press_x >= i.position_left + off && press_x < i.position_left + i.reserved + off) {
|
||||||
if(i.type == 0 || i.type == 1) {
|
if(is_ctype(i.type)) {
|
||||||
clicked_button = true;
|
clicked_button = true;
|
||||||
clicked = i;
|
clicked = i;
|
||||||
controller_name = (stringfmt() << "controller " << i.port << "-"
|
controller_name = (stringfmt() << "controller " << i.port << "-"
|
||||||
|
@ -1847,7 +1871,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit
|
||||||
uint64_t ebutton_low = clicked_button ? first_editable(clicked.index) : std::numeric_limits<uint64_t>::max();
|
uint64_t ebutton_low = clicked_button ? first_editable(clicked.index) : std::numeric_limits<uint64_t>::max();
|
||||||
uint64_t econtroller_low = ebutton_low;
|
uint64_t econtroller_low = ebutton_low;
|
||||||
for(auto i : fcontrols.get_controlinfo())
|
for(auto i : fcontrols.get_controlinfo())
|
||||||
if(i.port == clicked.port && i.controller == clicked.controller && (i.type == 0 || i.type == 1))
|
if(i.port == clicked.port && i.controller == clicked.controller && is_ctype(i.type))
|
||||||
econtroller_low = max(econtroller_low, first_editable(i.index));
|
econtroller_low = max(econtroller_low, first_editable(i.index));
|
||||||
|
|
||||||
bool click_zero = (clicked_button && !clicked.port && !clicked.controller);
|
bool click_zero = (clicked_button && !clicked.port && !clicked.controller);
|
||||||
|
@ -1876,6 +1900,7 @@ void wxeditor_movie::_moviepanel::on_mouse2(unsigned x, unsigned y, bool polarit
|
||||||
press_line < linecount) || (rpress_line >= ebutton_low && rpress_line < linecount)));
|
press_line < linecount) || (rpress_line >= ebutton_low && rpress_line < linecount)));
|
||||||
//Sweep axis is enabled if change axis is enabled and lines don't match.
|
//Sweep axis is enabled if change axis is enabled and lines don't match.
|
||||||
enable_sweep_axis = (enable_change_axis && press_line != rpress_line);
|
enable_sweep_axis = (enable_change_axis && press_line != rpress_line);
|
||||||
|
//TODO: Handle clicked.type == 2.
|
||||||
//Insert frame is enabled if this frame is completely editable and press and release lines match.
|
//Insert frame is enabled if this frame is completely editable and press and release lines match.
|
||||||
enable_insert_frame = (!not_editable && press_line + 1 >= eframe_low && press_line < linecount &&
|
enable_insert_frame = (!not_editable && press_line + 1 >= eframe_low && press_line < linecount &&
|
||||||
press_line == rpress_line);
|
press_line == rpress_line);
|
||||||
|
|
|
@ -522,6 +522,8 @@ void wxeditor_tasinput::update_controls()
|
||||||
current->Add(t.check);
|
current->Add(t.check);
|
||||||
t.check->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
|
t.check->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
|
||||||
wxCommandEventHandler(wxeditor_tasinput::on_control), NULL, this);
|
wxCommandEventHandler(wxeditor_tasinput::on_control), NULL, this);
|
||||||
|
} else if(i.type == port_controller_button::TYPE_KEYBOARD) {
|
||||||
|
//TODO.
|
||||||
} else {
|
} else {
|
||||||
t.panel = new xypanel(current_p, inst, current, i, this,
|
t.panel = new xypanel(current_p, inst, current, i, this,
|
||||||
wxCommandEventHandler(wxeditor_tasinput::on_control), next_id);
|
wxCommandEventHandler(wxeditor_tasinput::on_control), next_id);
|
||||||
|
|
|
@ -1253,6 +1253,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";
|
||||||
|
|
Loading…
Add table
Reference in a new issue