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?
|
||||
std::u32string rtc; //RTC time.
|
||||
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> lvars; //Lua variables.
|
||||
};
|
||||
|
|
|
@ -129,6 +129,7 @@ struct emulator_instance
|
|||
status_updater* supdater;
|
||||
threads::id emu_thread;
|
||||
time_t random_seed_value;
|
||||
bool vi_prev_frame;
|
||||
dtor_list D;
|
||||
private:
|
||||
emulator_instance(const emulator_instance&);
|
||||
|
|
|
@ -25,7 +25,8 @@ enum lsnes_movie_tags
|
|||
TAG_RAMCONTENT = 0xd3ec3770,
|
||||
TAG_ROMHINT = 0x6f715830,
|
||||
TAG_BRANCH = 0xf2e60707,
|
||||
TAG_BRANCH_NAME = 0x6dcb2155
|
||||
TAG_BRANCH_NAME = 0x6dcb2155,
|
||||
TAG_VICOUNTER = 0x55758e30,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -236,6 +236,18 @@ struct moviefile
|
|||
* 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;
|
||||
/**
|
||||
* Get number of frames in movie.
|
||||
*
|
||||
|
|
|
@ -109,8 +109,9 @@ extern "C" {
|
|||
#define LSNES_CORE_CAP1_MEMWATCH 0x00010000U
|
||||
//Core supports lightguns (By setting lightgun_height/lightgun_width in LSNES_CORE_GET_AV_STATE).
|
||||
#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.
|
||||
#define LSNES_CORE_CAP1_RESERVED18 0x00040000U
|
||||
#define LSNES_CORE_CAP1_RESERVED19 0x00080000U
|
||||
#define LSNES_CORE_CAP1_RESERVED20 0x00100000U
|
||||
#define LSNES_CORE_CAP1_RESERVED21 0x00200000U
|
||||
|
@ -349,6 +350,9 @@ struct lsnes_core_get_type_info
|
|||
struct lsnes_core_get_type_info_romimage* images;
|
||||
//Output: List of settings. Terminated by setting with NULL iname.
|
||||
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.
|
||||
|
|
|
@ -611,6 +611,7 @@ public:
|
|||
std::vector<std::string> get_trace_cpus() { return core->get_trace_cpus(); }
|
||||
void debug_reset() { core->debug_reset(); }
|
||||
bool isnull() { return core->isnull(); }
|
||||
bool is_vfr() { return t_is_vfr(); }
|
||||
protected:
|
||||
/**
|
||||
* Load a ROM slot set. Changes the ROM currently loaded for core.
|
||||
|
@ -630,6 +631,10 @@ protected:
|
|||
* Returns: The controller configuration.
|
||||
*/
|
||||
virtual controller_set t_controllerconfig(std::map<std::string, std::string>& settings) = 0;
|
||||
/**
|
||||
* Is VFR (defaults to false).
|
||||
*/
|
||||
virtual bool t_is_vfr();
|
||||
private:
|
||||
core_type(const core_type&);
|
||||
core_type& operator=(const core_type&);
|
||||
|
|
|
@ -191,6 +191,7 @@ struct port_controller_button
|
|||
TYPE_RAXIS, //Relative Axis (mouse).
|
||||
TYPE_TAXIS, //Throttle Axis (does not pair).
|
||||
TYPE_LIGHTGUN, //Lightgun axis.
|
||||
TYPE_KEYBOARD, //Keyboard. The names are translated via namemap.
|
||||
};
|
||||
enum _type type;
|
||||
char32_t symbol;
|
||||
|
@ -216,6 +217,8 @@ struct port_controller
|
|||
std::string cclass; //Controller class.
|
||||
std::string type; //Controller type.
|
||||
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.
|
||||
*/
|
||||
|
@ -233,6 +236,15 @@ struct port_controller
|
|||
return NULL;
|
||||
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.
|
||||
*
|
||||
* 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);
|
||||
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.
|
||||
|
@ -519,6 +531,12 @@ public:
|
|||
throw std::runtime_error("Bad legacy PCID");
|
||||
return legacy_pcids[pcid];
|
||||
}
|
||||
/**
|
||||
* Set pollcounters mask.
|
||||
*
|
||||
* Parameter mask: The mask to write.
|
||||
*/
|
||||
void set_pollcounter_mask(uint32_t* mask) const;
|
||||
private:
|
||||
port_type_set(std::vector<class port_type*> types, struct port_index_map control_map);
|
||||
size_t* port_offsets;
|
||||
|
@ -566,10 +584,14 @@ public:
|
|||
* Assign the pollcounter_vector.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
void clear() throw();
|
||||
void clear_all() throw();
|
||||
/**
|
||||
* Set all DRDY bits.
|
||||
*/
|
||||
|
@ -707,8 +729,47 @@ public:
|
|||
* Get raw pollcounter data.
|
||||
*/
|
||||
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:
|
||||
uint32_t* ctrs;
|
||||
uint32_t* ctrs_valid_mask;
|
||||
const port_type_set* types;
|
||||
bool framepflag;
|
||||
};
|
||||
|
|
|
@ -14,6 +14,8 @@ struct lua_unsaferewind
|
|||
uint64_t ptr;
|
||||
uint64_t secs;
|
||||
uint64_t ssecs;
|
||||
uint64_t vi_counter;
|
||||
uint32_t vi_this_frame;
|
||||
std::vector<uint32_t> pollcounters;
|
||||
std::vector<char> hostmemory;
|
||||
std::string print()
|
||||
|
|
12
lua.lyx
12
lua.lyx
|
@ -6255,6 +6255,18 @@ Syntax: number movie.currentframe()
|
|||
Return number of current frame.
|
||||
\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
|
||||
movie.framecount: Get move frame count
|
||||
\end_layout
|
||||
|
|
|
@ -193,6 +193,9 @@ void status_updater::update()
|
|||
}
|
||||
_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.
|
||||
_status.lvars = lua2.get_watch_vars();
|
||||
//Memory watches.
|
||||
|
|
|
@ -121,6 +121,7 @@ emulator_instance::emulator_instance()
|
|||
settings->add_set(lsnes_setgrp);
|
||||
dispatch->set_error_streams(&messages.getstream());
|
||||
random_seed_value = 0;
|
||||
vi_prev_frame = false;
|
||||
}
|
||||
|
||||
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)
|
||||
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()) {
|
||||
//Note that platform::wait() may change value of cancel flag.
|
||||
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.supdater->update();
|
||||
//Clear the previous VI flag, so next poll will be subframe.
|
||||
core.vi_prev_frame = false;
|
||||
}
|
||||
platform::flush_command_queue();
|
||||
//TODO: Collapse keyboard symbols.
|
||||
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.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)
|
||||
{
|
||||
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.fbuf->redraw_framebuffer(screen, false, true);
|
||||
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
|
||||
//failing.
|
||||
int handle_load()
|
||||
int _handle_load()
|
||||
{
|
||||
auto& core = CORE();
|
||||
std::string old_project = *core.mlogic ? core.mlogic->get_mfile().projectid : "";
|
||||
|
@ -930,6 +941,17 @@ nothing_to_do:
|
|||
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.
|
||||
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);
|
||||
platform::set_paused(core.runmode->is_paused());
|
||||
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();
|
||||
|
||||
|
@ -1032,7 +1058,9 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
|||
just_did_loadstate = first_round;
|
||||
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();
|
||||
|
||||
if(!first_round) {
|
||||
|
@ -1079,9 +1107,20 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
|
|||
just_did_loadstate = 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();
|
||||
//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();
|
||||
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()));
|
||||
first_round = false;
|
||||
core.lua2->callback_do_frame();
|
||||
|
|
|
@ -437,6 +437,19 @@ namespace
|
|||
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)
|
||||
|
@ -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().romxml_sha256[i] = core.rom->romxml[i].sha_256.read();
|
||||
}
|
||||
core.mlogic->get_mfile().is_savestate = false;
|
||||
core.mlogic->get_mfile().host_memory.clear();
|
||||
core.mlogic->get_movie().reset_state();
|
||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||
clear_runtime_movie_data(core);
|
||||
core.lua2->callback_do_rewind();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
|
@ -484,25 +494,16 @@ void do_load_rom() throw(std::bad_alloc, std::runtime_error)
|
|||
//The more complicated Read-Write case.
|
||||
//We need to create a new movie and movie file.
|
||||
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()->projectid = get_random_hexstring(40);
|
||||
_movie.get()->rerecords = "0";
|
||||
_movie.get()->rerecords_mem = 0;
|
||||
for(size_t i = 0; i < ROM_SLOT_COUNT; i++) {
|
||||
_movie.get()->namehint[i] = core.rom->romimg[i].namehint;
|
||||
_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()->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_subsecond = _movie.get()->rtc_subsecond = 0;
|
||||
_movie.get()->start_paused = false;
|
||||
_movie.get()->lazy_project_create = true;
|
||||
port_type_set& portset2 = construct_movie_portset(*_movie.get(), *core.rom);
|
||||
_movie.get()->input = NULL;
|
||||
_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);
|
||||
try {
|
||||
handle_load_core(core.mlogic->get_mfile(), portset, false);
|
||||
core.mlogic->get_mfile().is_savestate = false;
|
||||
core.mlogic->get_mfile().host_memory.clear();
|
||||
core.mlogic->get_movie().reset_state();
|
||||
core.fbuf->redraw_framebuffer(core.rom->draw_cover());
|
||||
clear_runtime_movie_data(core);
|
||||
core.lua2->callback_do_rewind();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
|
@ -760,6 +758,15 @@ void do_load_state(struct moviefile& _movie, int lmode, bool& used)
|
|||
core.mlogic->set_mfile(_movie, 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));
|
||||
|
||||
//Activate RW mode if needed.
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
void moviefile::brief_info::binary_io(int _stream)
|
||||
{
|
||||
bool vi_override = false;
|
||||
|
||||
binarystream::input in(_stream);
|
||||
sysregion = in.string();
|
||||
//Discard the settings.
|
||||
|
@ -32,8 +34,14 @@ void moviefile::brief_info::binary_io(int _stream)
|
|||
this->corename = s.string_implicit();
|
||||
}},{TAG_PROJECT_ID, [this](binarystream::input& s) {
|
||||
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();
|
||||
vi_override = true;
|
||||
}},{TAG_RRDATA, [this](binarystream::input& s) {
|
||||
std::vector<char> 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;
|
||||
std::map<std::string, uint64_t> branch_table;
|
||||
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);
|
||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||
input = NULL;
|
||||
vi_valid = false;
|
||||
|
||||
in.extension({
|
||||
{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();
|
||||
std::string x = s.string_implicit();
|
||||
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);
|
||||
|
||||
|
|
|
@ -200,9 +200,12 @@ void moviefile::brief_info::load(zip::reader& r)
|
|||
r.read_linefile("gametype", sysregion);
|
||||
r.read_linefile("coreversion", corename);
|
||||
r.read_linefile("projectid", projectid);
|
||||
if(r.has_member("savestate"))
|
||||
r.read_numeric_file("saveframe", current_frame);
|
||||
else
|
||||
if(r.has_member("savestate")) {
|
||||
if(r.has_member("vicount"))
|
||||
r.read_numeric_file("vicount", current_frame);
|
||||
else
|
||||
r.read_numeric_file("saveframe", current_frame);
|
||||
} else
|
||||
current_frame = 0;
|
||||
r.read_numeric_file("rerecords", rerecords);
|
||||
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);
|
||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||
|
||||
vi_valid = true;
|
||||
vi_counter = 0;
|
||||
vi_this_frame = 0;
|
||||
|
||||
branches.clear();
|
||||
r.read_linefile("gamename", gamename, true);
|
||||
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"))
|
||||
r.read_raw_file("savestate.anchor", anchor_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;
|
||||
r.read_numeric_file("saveframe", save_frame, 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.subsecond", movie_rtc_subsecond);
|
||||
if(!anchor_savestate.empty())
|
||||
w.write_raw_file("savestate.anchor", anchor_savestate);
|
||||
w.write_raw_file("savestate.anchor", anchor_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("lagcounter", lagged_frames);
|
||||
write_pollcounters(w, "pollcounters", pollcounters);
|
||||
|
|
|
@ -109,12 +109,18 @@ moviefile::moviefile() throw(std::bad_alloc)
|
|||
coreversion = "";
|
||||
projectid = "";
|
||||
rerecords = "0";
|
||||
rerecords_mem = 0;
|
||||
is_savestate = false;
|
||||
save_frame = 0;
|
||||
lagged_frames = 0;
|
||||
movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND;
|
||||
movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||
start_paused = false;
|
||||
lazy_project_create = true;
|
||||
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,
|
||||
|
@ -125,7 +131,10 @@ moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_sett
|
|||
coreversion = rom.get_core_identifier();
|
||||
projectid = get_random_hexstring(40);
|
||||
rerecords = "0";
|
||||
rerecords_mem = 0;
|
||||
is_savestate = false;
|
||||
save_frame = 0;
|
||||
lagged_frames = 0;
|
||||
movie_rtc_second = rtc_second = rtc_sec;
|
||||
movie_rtc_subsecond = rtc_subsecond = rtc_subsec;
|
||||
start_paused = false;
|
||||
|
@ -133,6 +142,9 @@ moviefile::moviefile(loaded_rom& rom, std::map<std::string, std::string>& c_sett
|
|||
poll_flag = 0;
|
||||
settings = c_settings;
|
||||
input = NULL;
|
||||
vi_valid = true;
|
||||
vi_counter = 0;
|
||||
vi_this_frame = 0;
|
||||
auto ctrldata = rom.controllerconfig(settings);
|
||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
|
||||
create_default_branch(ports);
|
||||
|
@ -329,6 +341,9 @@ void moviefile::copy_fields(const moviefile& mv)
|
|||
lazy_project_create = mv.lazy_project_create;
|
||||
subtitles = mv.subtitles;
|
||||
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)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
OBJECTS=test.$(OBJECT_SUFFIX)
|
||||
OBJECTS=test.$(OBJECT_SUFFIX) test2.$(OBJECT_SUFFIX)
|
||||
|
||||
.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;
|
||||
}
|
||||
bool supports_vfr_sel()
|
||||
{
|
||||
return (caps1 & LSNES_CORE_CAP1_TYPEEXT1);
|
||||
}
|
||||
private:
|
||||
std::string fullname;
|
||||
std::string shortname;
|
||||
|
@ -690,8 +694,9 @@ failed:
|
|||
struct c_core_type : public core_type
|
||||
{
|
||||
c_core_type(c_lib_init& lib, core_type_params& p, std::map<unsigned, port_type*> _ports,
|
||||
unsigned _rcount, unsigned _id)
|
||||
: core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id)
|
||||
unsigned _rcount, unsigned _id, bool _vfr)
|
||||
: core_type(p), ports(_ports), entrypoint(lib.get_entrypoint()), rcount(_rcount), id(_id),
|
||||
vfr(_vfr)
|
||||
{
|
||||
}
|
||||
~c_core_type() throw()
|
||||
|
@ -748,6 +753,10 @@ failed:
|
|||
}
|
||||
return cset;
|
||||
}
|
||||
bool t_is_vfr()
|
||||
{
|
||||
return vfr;
|
||||
}
|
||||
private:
|
||||
void copy_settings(std::vector<char>& tmpmem, std::vector<lsnes_core_system_setting>& tmpmem2,
|
||||
std::map<std::string, std::string>& settings)
|
||||
|
@ -778,6 +787,7 @@ failed:
|
|||
entrypoint_fn entrypoint;
|
||||
unsigned rcount;
|
||||
unsigned id;
|
||||
bool vfr;
|
||||
};
|
||||
|
||||
std::vector<char> msgbuf;
|
||||
|
@ -1056,12 +1066,13 @@ no_parameters:
|
|||
if(!cores.count(_core))
|
||||
throw std::runtime_error("create_type: Unknown 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++) {
|
||||
if(!regions.count(*reg))
|
||||
throw std::runtime_error("create_type: Unknown region");
|
||||
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,
|
||||
|
@ -1085,7 +1096,7 @@ no_parameters:
|
|||
//Enumerate what the thing supports.
|
||||
entrypoint_fn entrypoint(fn);
|
||||
lsnes_core_enumerate_cores r;
|
||||
r.emu_flags1 = 1;
|
||||
r.emu_flags1 = 2;
|
||||
r.message = callback_message;
|
||||
r.get_input = callback_get_input;
|
||||
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();
|
||||
}
|
||||
|
||||
bool core_type::t_is_vfr()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
controller_multiplier = 1;
|
||||
for(size_t i = 0; i < port_count; i++)
|
||||
for(unsigned j = 0; j < types[i]->controller_info->controllers.size(); j++)
|
||||
controller_multiplier = max(controller_multiplier, (size_t)types[i]->used_indices(j));
|
||||
for(unsigned j = 0; j < types[i]->controller_info->controllers.size(); 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.
|
||||
port_multiplier = 1;
|
||||
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()
|
||||
{
|
||||
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];
|
||||
bool need_space = false;
|
||||
short val;
|
||||
for(unsigned i = 0; i < pc.buttons.size(); i++) {
|
||||
const port_controller_button& pcb = pc.buttons[i];
|
||||
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_TAXIS:
|
||||
case port_controller_button::TYPE_LIGHTGUN:
|
||||
val = ptype.read(&ptype, backingmem, controller, i);
|
||||
buf += writeu32val(buf, val);
|
||||
buf += writeu32val(buf, ptype.read(&ptype, backingmem, controller, i));
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
@ -301,22 +330,34 @@ void controller_frame::display(unsigned port, unsigned controller, char32_t* buf
|
|||
pollcounter_vector::pollcounter_vector() throw(std::bad_alloc)
|
||||
{
|
||||
types = &dummytypes();
|
||||
ctrs = new uint32_t[types->indices()];
|
||||
clear();
|
||||
size_t elts_base = types->indices();
|
||||
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)
|
||||
{
|
||||
types = &p;
|
||||
ctrs = new uint32_t[types->indices()];
|
||||
clear();
|
||||
size_t elts_base = types->indices();
|
||||
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)
|
||||
{
|
||||
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;
|
||||
memcpy(ctrs, p.ctrs, sizeof(uint32_t) * p.types->indices());
|
||||
memcpy(ctrs, p.ctrs, sizeof(uint32_t) * elts_all);
|
||||
framepflag = p.framepflag;
|
||||
}
|
||||
|
||||
|
@ -324,21 +365,34 @@ pollcounter_vector& pollcounter_vector::operator=(const pollcounter_vector& p) t
|
|||
{
|
||||
if(this == &p)
|
||||
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;
|
||||
memcpy(n, p.ctrs, sizeof(uint32_t) * p.types->indices());
|
||||
memcpy(n, p.ctrs, sizeof(uint32_t) * elts_all);
|
||||
delete[] ctrs;
|
||||
ctrs = n;
|
||||
ctrs_valid_mask = ctrs + elts_base;
|
||||
framepflag = p.framepflag;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pollcounter_vector::~pollcounter_vector() throw()
|
||||
{
|
||||
//ctrs_valid_mask is part of this.
|
||||
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());
|
||||
framepflag = false;
|
||||
|
@ -346,46 +400,65 @@ void pollcounter_vector::clear() throw()
|
|||
|
||||
void pollcounter_vector::set_all_DRDY() throw()
|
||||
{
|
||||
//Only manipulate valid pcounters.
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
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()
|
||||
{
|
||||
uint32_t res = 0;
|
||||
for(size_t i = 0; i < types->indices() ; i++)
|
||||
res |= ctrs[i];
|
||||
for(size_t i = 0; i < types->indices(); i++)
|
||||
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1)
|
||||
res |= ctrs[i];
|
||||
return ((res & 0x7FFFFFFFUL) != 0);
|
||||
}
|
||||
|
||||
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 x = ctrs[idx] & 0x7FFFFFFFUL;
|
||||
++ctrs[idx];
|
||||
return x;
|
||||
//Only manipulate valid pcounters, for others, permanently 0.
|
||||
if((ctrs_valid_mask[idx >> 5] >> (idx & 31)) & 1) {
|
||||
uint32_t x = ctrs[idx] & 0x7FFFFFFFUL;
|
||||
++ctrs[idx];
|
||||
return x;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t pollcounter_vector::max_polls() throw()
|
||||
{
|
||||
uint32_t max = 0;
|
||||
for(unsigned i = 0; i < types->indices(); i++) {
|
||||
uint32_t tmp = ctrs[i] & 0x7FFFFFFFUL;
|
||||
max = (max < tmp) ? tmp : max;
|
||||
if((ctrs_valid_mask[i >> 5] >> (i & 31)) & 1) {
|
||||
uint32_t tmp = ctrs[i] & 0x7FFFFFFFUL;
|
||||
max = (max < tmp) ? tmp : 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)
|
||||
{
|
||||
mem.resize(types->indices());
|
||||
//Compatiblity fun.
|
||||
for(size_t i = 0; i < types->indices(); i++)
|
||||
mem[i] = ctrs[i];
|
||||
}
|
||||
|
@ -824,6 +896,7 @@ unsigned port_controller::analog_actions() const
|
|||
break;
|
||||
case port_controller_button::TYPE_NULL:
|
||||
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;
|
||||
case port_controller_button::TYPE_NULL:
|
||||
case port_controller_button::TYPE_BUTTON:
|
||||
case port_controller_button::TYPE_KEYBOARD:
|
||||
;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,6 +23,22 @@ namespace
|
|||
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)
|
||||
{
|
||||
if(root.type_of(ptr) != JSON::string)
|
||||
|
@ -117,6 +133,22 @@ namespace
|
|||
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)
|
||||
{
|
||||
if(root.type_of_indirect(ptr) != JSON::object)
|
||||
|
@ -129,6 +161,8 @@ namespace
|
|||
return pcb_button(root, ptr);
|
||||
else if(type == "axis" || type == "raxis" || type == "taxis" || type == "lightgun")
|
||||
return pcb_axis(root, ptr, type);
|
||||
else if(type == "key")
|
||||
return pcb_key(root, ptr);
|
||||
else
|
||||
(stringfmt() << "Unknown type '" << type << "' for '" << ptr << "'").throwex();
|
||||
return pcb_null(root, ptr); //NOTREACHED.
|
||||
|
@ -153,6 +187,22 @@ namespace
|
|||
ret.cclass = cclass;
|
||||
ret.type = type;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -202,6 +252,7 @@ namespace
|
|||
case port_controller_button::TYPE_RAXIS: s << "RAXIS"; break;
|
||||
case port_controller_button::TYPE_TAXIS: s << "TAXIS"; 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 << ", "
|
||||
<< b.rmax << ", " << b.centers << ", " << quote(b.macro) << ", " << (int)b.msymbol << "}";
|
||||
|
@ -216,7 +267,10 @@ namespace
|
|||
write_button(s, i);
|
||||
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)
|
||||
|
@ -249,6 +303,7 @@ namespace
|
|||
case port_controller_button::TYPE_NULL: break;
|
||||
case port_controller_button::TYPE_RAXIS: 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;
|
||||
|
@ -266,6 +321,7 @@ namespace
|
|||
case port_controller_button::TYPE_NULL: break;
|
||||
case port_controller_button::TYPE_RAXIS: break;
|
||||
case port_controller_button::TYPE_TAXIS: break;
|
||||
case port_controller_button::TYPE_KEYBOARD: break;
|
||||
};
|
||||
}
|
||||
return (x + 7) / 8;
|
||||
|
@ -297,6 +353,7 @@ namespace
|
|||
case port_controller_button::TYPE_RAXIS:
|
||||
case port_controller_button::TYPE_TAXIS:
|
||||
case port_controller_button::TYPE_LIGHTGUN:
|
||||
case port_controller_button::TYPE_KEYBOARD:
|
||||
ii.type = 2;
|
||||
ii.offset = aoffset + 2 * axisidx2;
|
||||
axisidx2++;
|
||||
|
@ -343,6 +400,7 @@ namespace
|
|||
case port_controller_button::TYPE_RAXIS:
|
||||
case port_controller_button::TYPE_TAXIS:
|
||||
case port_controller_button::TYPE_LIGHTGUN:
|
||||
case port_controller_button::TYPE_KEYBOARD:
|
||||
ins.type = 1;
|
||||
ins.offset = aoffset + 2 * axisidx;
|
||||
ret.push_back(ins);
|
||||
|
|
|
@ -120,7 +120,7 @@ void movie::next_frame() throw(std::bad_alloc)
|
|||
}
|
||||
|
||||
//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
|
||||
//frame 0 and 0 for frame 1.
|
||||
|
@ -346,7 +346,7 @@ void movie::reset_state() throw()
|
|||
readonly = true;
|
||||
current_frame = 0;
|
||||
current_frame_first_subframe = 0;
|
||||
pollcounters.clear();
|
||||
pollcounters.clear_all();
|
||||
lag_frames = 0;
|
||||
clear_caches();
|
||||
}
|
||||
|
|
|
@ -465,6 +465,7 @@ namespace
|
|||
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_LIGHTGUN: L.pushstring("lightgun"); break;
|
||||
case port_controller_button::TYPE_KEYBOARD: L.pushstring("keyboard"); break;
|
||||
};
|
||||
L.rawset(-3);
|
||||
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");
|
||||
mainloop_restore_state(u2->state, u2->secs, u2->ssecs);
|
||||
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);
|
||||
delete reinterpret_cast<lua::objpin<lua_unsaferewind>*>(u);
|
||||
} catch(...) {
|
||||
|
@ -460,13 +464,16 @@ void lua_state::callback_do_unsafe_rewind(const std::vector<char>& save, uint64_
|
|||
}
|
||||
} else {
|
||||
//Save
|
||||
run_callback(*on_set_rewind, lua::state::fn_tag([&core, save, secs, ssecs, &mov](lua::state& L) ->
|
||||
int {
|
||||
run_callback(*on_set_rewind, lua::state::fn_tag([&core, save, secs, ssecs, &mov](lua::state& L)
|
||||
-> int {
|
||||
lua_unsaferewind* u2 = lua::_class<lua_unsaferewind>::create(*core.lua);
|
||||
u2->state = save;
|
||||
u2->secs = secs,
|
||||
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);
|
||||
return 1;
|
||||
}));
|
||||
|
|
|
@ -13,6 +13,13 @@ namespace
|
|||
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)
|
||||
{
|
||||
auto& m = CORE().mlogic->get_movie();
|
||||
|
@ -136,6 +143,7 @@ namespace
|
|||
|
||||
lua::functions LUA_movie_fns(lua_func_misc, "movie", {
|
||||
{"currentframe", currentframe},
|
||||
{"currentvi", currentvi},
|
||||
{"lagcount", lagcounter},
|
||||
{"framecount", framecount},
|
||||
{"rerecords", rerecords},
|
||||
|
|
|
@ -74,6 +74,16 @@ namespace
|
|||
uint64_t divsl[] = {1000000, 100000, 10000, 1000, 100, 10, 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
|
||||
{
|
||||
public:
|
||||
|
@ -110,7 +120,7 @@ struct control_info
|
|||
unsigned position_left;
|
||||
unsigned reserved; //Must be at least 6 for axes.
|
||||
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;
|
||||
std::u32string title;
|
||||
unsigned port;
|
||||
|
@ -124,6 +134,7 @@ struct control_info
|
|||
unsigned port, unsigned controller);
|
||||
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);
|
||||
//TODO: keyinfo().
|
||||
};
|
||||
|
||||
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,
|
||||
pcb.type, pcb.rmin, pcb.rmax));
|
||||
last_multibyte = true;
|
||||
} else if(pcb.type == port_controller_button::TYPE_KEYBOARD) {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
if(nextp > c)
|
||||
|
@ -322,7 +335,7 @@ void frame_controls::format_lines()
|
|||
//Line2
|
||||
for(auto i : controlinfo) {
|
||||
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]);
|
||||
if(i.type == 0)
|
||||
cp2[i.position_left + off] = i.ch;
|
||||
|
@ -389,6 +402,9 @@ namespace
|
|||
first = false;
|
||||
last_axis = true;
|
||||
break;
|
||||
case 2: //key
|
||||
//TODO.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return x.str();
|
||||
|
@ -450,6 +466,9 @@ namespace
|
|||
first = false;
|
||||
last_axis = true;
|
||||
break;
|
||||
case 2: //Key.
|
||||
//TODO.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -496,7 +515,7 @@ namespace
|
|||
{
|
||||
std::set<unsigned> r;
|
||||
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);
|
||||
}
|
||||
return r;
|
||||
|
@ -1016,6 +1035,9 @@ void wxeditor_movie::_moviepanel::render_linen(text_framebuffer& fb, controller_
|
|||
char c[7];
|
||||
sprintf(c, "%6d", fcontrols.read_index(f, i.index));
|
||||
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
|
||||
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 {
|
||||
for(auto i : fcontrols.get_controlinfo())
|
||||
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 = i;
|
||||
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 econtroller_low = ebutton_low;
|
||||
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));
|
||||
|
||||
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)));
|
||||
//Sweep axis is enabled if change axis is enabled and lines don't match.
|
||||
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.
|
||||
enable_insert_frame = (!not_editable && press_line + 1 >= eframe_low && press_line < linecount &&
|
||||
press_line == rpress_line);
|
||||
|
|
|
@ -522,6 +522,8 @@ void wxeditor_tasinput::update_controls()
|
|||
current->Add(t.check);
|
||||
t.check->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED,
|
||||
wxCommandEventHandler(wxeditor_tasinput::on_control), NULL, this);
|
||||
} else if(i.type == port_controller_button::TYPE_KEYBOARD) {
|
||||
//TODO.
|
||||
} else {
|
||||
t.panel = new xypanel(current_p, inst, current, i, this,
|
||||
wxCommandEventHandler(wxeditor_tasinput::on_control), next_id);
|
||||
|
|
|
@ -1253,6 +1253,8 @@ void wxwin_mainwindow::update_statusbar()
|
|||
s << "Frame: " << vars.curframe;
|
||||
else
|
||||
s << "Frame: " << vars.curframe << "/" << vars.length;
|
||||
if(vars.vi_valid)
|
||||
s << " VI: " << vars.vi_counter;
|
||||
s << " Lag: " << vars.lag;
|
||||
if(vars.subframe == _lsnes_status::subframe_savepoint)
|
||||
s << " Subframe: S";
|
||||
|
|
Loading…
Add table
Reference in a new issue