lsnes rr0-β20

This commit is contained in:
Ilari Liusvaara 2011-11-09 00:05:57 +02:00
parent 44d8822af2
commit ff4d045882
5 changed files with 941 additions and 2 deletions

2
.gitignore vendored
View file

@ -5,4 +5,4 @@
*.exe
docs
rom
core
/core

409
include/core/dispatch.hpp Normal file
View file

@ -0,0 +1,409 @@
#ifndef _dispatch__hpp__included__
#define _dispatch__hpp__included__
#include "render.hpp"
#include "keymapper.hpp"
#include <cstdint>
#include <string>
#include <stdexcept>
#include <set>
#include <map>
/**
* Video data region is NTSC.
*/
#define VIDEO_REGION_NTSC 0
/**
* Video data region is PAL.
*/
#define VIDEO_REGION_PAL 1
/**
* Information about run.
*/
struct gameinfo_struct
{
public:
/**
* Construct game info.
*/
gameinfo_struct() throw(std::bad_alloc);
/**
* Game name.
*/
std::string gamename;
/**
* Run length in seconds.
*/
double length;
/**
* Rerecord count (base 10 ASCII)
*/
std::string rerecords;
/**
* Authors. The first components are real names, the second components are nicknames. Either (but not both) may be
* blank.
*/
std::vector<std::pair<std::string, std::string>> authors;
/**
* Format human-redable representation of the length.
*
* Parameter digits: Number of sub-second digits to use.
* Returns: The time formated.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_readable_time(unsigned digits) const throw(std::bad_alloc);
/**
* Get number of authors.
*
* Returns: Number of authors.
*/
size_t get_author_count() const throw();
/**
* Get short name of author (nickname if present, otherwise full name).
*
* Parameter idx: Index of author (0-based).
* Returns: The short name.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_author_short(size_t idx) const throw(std::bad_alloc);
/**
* Get rerecord count as a number. If rerecord count is too high, returns the maximum representatible count.
*
* Returns: The rerecord count.
*/
uint64_t get_rerecords() const throw();
};
/**
* Information dispatch.
*
* This class handles dispatching information between the components of the emulator.
*
* Each kind of information has virtual method on_foo() which can be overridden to handle events of that type, and
* static method do_foo(), which calls on_foo on all known objects.
*
* The information is delivered to each instance of this class.
*/
class information_dispatch
{
public:
/**
* Create new object to receive information dispatch events.
*
* Parameter name: The name for the object.
* Throws std::bad_alloc: Not enough memory.
*/
information_dispatch(const std::string& name) throw(std::bad_alloc);
/**
* Destroy object.
*/
~information_dispatch() throw();
/**
* Window close event received (this is not emulator close!)
*
* The default handler does nothing.
*/
virtual void on_close();
/**
* Call all on_close() handlers.
*/
static void do_close() throw();
/**
* Click or release on window was receivied.
*
* The default handler does nothing.
*
* Parameter x: The x-coordinate of the click. May be negative or otherwise out of screen.
* Parameter y: The y-coordinate of the click. May be negative or otherwise out of screen.
* Parameter buttonmask: Bitfield giving current buttons held:
* Bit 0 => Left button is down/held.
* Bit 1 => Middle button is down/held.
* Bit 2 => Middle button is down/held.
*/
virtual void on_click(int32_t x, int32_t y, uint32_t buttonmask);
/**
* Call all on_click() handlers.
*/
static void do_click(int32_t x, int32_t y, uint32_t buttonmask) throw();
/**
* Sound mute/unmute status might have been changed.
*
* The default handler does nothing.
*
* Parameter unmuted: If true, the sound is now enabled. If false, the sound is now disabled.
*/
virtual void on_sound_unmute(bool unmuted);
/**
* Call all on_sound_unmute() handlers.
*/
static void do_sound_unmute(bool unmuted) throw();
/**
* Sound device might have been changed.
*
* The default handler does nothing.
*
* Parameter dev: The device name sound is now playing (if enabled) from.
*/
virtual void on_sound_change(const std::string& dev);
/**
* Call all on_sound_change() handlers.
*/
static void do_sound_change(const std::string& dev) throw();
/**
* Emulator mode might have been changed.
*
* The default handler does nothing.
*
* Parameter readonly: True if readonly mode is now active, false if now in readwrite mode.
*/
virtual void on_mode_change(bool readonly);
/**
* Call all on_mode_change() handlers.
*/
static void do_mode_change(bool readonly) throw();
/**
* Autohold on button might have been changed.
*
* The default handler does nothing.
*
* Parameter pid: The physical ID of controller (0-7).
* Parameter ctrlnum: Physical control number (0-15).
* Parameter newstate: True if autohold is now active, false if autohold is now inactive.
*/
virtual void on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate);
/**
* Call all on_autohold_update() handlers.
*/
static void do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw();
/**
* Controller configuration may have been changed.
*
* The default handler does nothing.
*/
virtual void on_autohold_reconfigure();
/**
* Call all on_autohold_reconfigure() handlers.
*/
static void do_autohold_reconfigure() throw();
/**
* A setting may have changed.
*
* The default handler does nothing.
*
* Parameter setting: The setting that has possibly changed.
* Parameter value: The new value for the setting.
*/
virtual void on_setting_change(const std::string& setting, const std::string& value);
/**
* Call all on_setting_change() handlers.
*/
static void do_setting_change(const std::string& setting, const std::string& value) throw();
/**
* A setting has been cleared (but it might have been cleared already).
*
* The default handler does nothing.
*
* Parameter setting: The setting that is now clear.
*/
virtual void on_setting_clear(const std::string& setting);
/**
* Call all on_setting_clear() handlers
*/
static void do_setting_clear(const std::string& setting) throw();
/**
* A raw frame has been received.
*
* The default handler does nothing.
*
* Parameter raw: The raw frame data. 512*512 element array.
* Parameter hires: True if in hires mode (512 wide), false if not (256-wide).
* Parameter interlaced: True if in interlaced mode (448/478 high), false if not (224/239 high).
* Parameter overscan: True if overscan is active, false if not.
* Parameter region: One of VIDEO_REGION_* contstants, giving the region this frame is from.
*/
virtual void on_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, unsigned region);
/**
* Call all on_raw_frame() handlers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, unsigned region)
throw();
/**
* A frame has been received.
*
* The default handler does nothing.
*
* Parameter _frame: The frame object.
* Parameter fps_n: Numerator of current video fps.
* Parameter fps_d: Denominator of current video fps.
*/
virtual void on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d);
/**
* Call all on_frame() handlers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw();
/**
* A sample has been received.
*
* The default handler does nothing.
*
* Parameter l: The left channel sample (16 bit signed).
* Parameter r: The right channel sample (16 bit signed).
*/
virtual void on_sample(short l, short r);
/**
* Call all on_sample() handlers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_sample(short l, short r) throw();
/**
* Dump is ending.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*
* The default handler does nothing.
*/
virtual void on_dump_end();
/**
* Call all on_dump_end() handlers.
*/
static void do_dump_end() throw();
/**
* Sound sampling rate is changing
*
* The default handler prints warning if dumper flag is set.
*
* Parameter rate_n: Numerator of the new sampling rate in Hz.
* Parameter rate_d: Denominator of the new sampling rate in Hz.
*/
virtual void on_sound_rate(uint32_t rate_n, uint32_t rate_d);
/**
* Call all on_sound_rate() methods and save the parameters.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_sound_rate(uint32_t rate_n, uint32_t rate_d) throw();
/**
* Get the sound rate most recently set by on_sound_rate().
*
* Returns: The first component is the numerator, the second is the denominator.
*/
static std::pair<uint32_t, uint32_t> get_sound_rate() throw();
/**
* Game information is changing.
*
* The default handler does nothing.
*
* Parameter gi: The new game info.
*/
virtual void on_gameinfo(const struct gameinfo_struct& gi);
/**
* Call all on_gameinfo() handlers and save the gameinfo.
*/
static void do_gameinfo(const struct gameinfo_struct& gi) throw();
/**
* Get the gameinfo most recently set by do_gameinfo().
*
* Returns: The gameinfo.
*/
static const struct gameinfo_struct& get_gameinfo() throw();
/**
* Return the dumper flag for this dispatch target.
*
* The default implementation returns false.
*
* If dumper flag is set:
* - on_sound_rate() default handler prints a warning.
* - All dumping related do_* functions triggers calls to to on_new_dumper() on all handlers the next time they
* are called.
* - Destroying the handler triggers calls to on_destroy_dumper() on all handlers (if on_new_dumper() has been
* called).
*/
virtual bool get_dumper_flag() throw();
/**
* Notify that a new dumper is joining.
*
* Parameter dumper: The name of the dumper object.
*/
virtual void on_new_dumper(const std::string& dumper);
/**
* Notify that a dumper is leaving.
*
* Parameter dumper: The name of the dumper object.
*/
virtual void on_destroy_dumper(const std::string& dumper);
/**
* Get number of active dumpers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*
* Returns: The dumper count.
*/
static unsigned get_dumper_count() throw();
/**
* Get set of active dumpers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*
* Returns: The set of dumper names.
* Throws std::bad_alloc: Not enough memory.
*/
static std::set<std::string> get_dumpers() throw(std::bad_alloc);
/**
* (Pseudo-)key has been pressed or released.
*
* Parameter modifiers: The modifier set currently active.
* Parameter keygroup: The key group the (pseudo-)key is from.
* Parameter subkey: Subkey index within the key group.
* Parameter polarity: True if key is being pressed, false if being released.
* Parameter name: Name of the key being pressed/released.
*/
virtual void on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name);
/**
* Call on_key_event() for all event handlers (or just one if keys are being grabbed).
*/
static void do_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name) throw();
/**
* Grab all key events.
*
* While key events are grabbed, do_key_event() only calls on_key_event() for the grabbing object.
*/
void grab_keys() throw();
/**
* Ungrab all key events.
*
* While key events are grabbed, do_key_event() only calls on_key_event() for the grabbing object.
*/
void ungrab_keys() throw();
/**
* Get name of target.
*/
const std::string& get_name() throw();
/**
* Set window main screen compensation parameters. This is used for mouse click reporting.
*
* parameter xoffset: X coordinate of origin.
* parameter yoffset: Y coordinate of origin.
* parameter hscl: Horizontal scaling factor.
* parameter vscl: Vertical scaling factor.
*/
static void do_click_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl);
private:
static void update_dumpers(bool nocalls = false) throw();
bool known_if_dumper;
bool marked_as_dumper;
std::string target_name;
bool notified_as_dumper;
bool grabbing_keys;
};
#endif

View file

@ -4499,5 +4499,41 @@ Finish pending saves before load/quit.
Wxwidgets graphics plugin.
\end_layout
\begin_layout Subsection
rr0-beta20
\end_layout
\begin_layout Itemize
Get rid of win32-crap.[ch]pp.
\end_layout
\begin_layout Itemize
Move files around a lot.
\end_layout
\begin_layout Itemize
Get rid of need for host C++ compiler.
\end_layout
\begin_layout Itemize
Bsnes v084 core.
\end_layout
\begin_layout Itemize
Refactor inter-component communication.
\end_layout
\begin_layout Itemize
Fix zero luma.
\end_layout
\begin_layout Itemize
Fix crash on multiline aliases.
\end_layout
\begin_layout Itemize
Load/Save settings in wxwidgets gui.
\end_layout
\end_body
\end_document

494
src/core/dispatch.cpp Normal file
View file

@ -0,0 +1,494 @@
#include "core/dispatch.hpp"
#include "core/globalwrap.hpp"
#include "core/misc.hpp"
#include <sstream>
#include <iomanip>
#include <cmath>
#define START_EH_BLOCK try {
#define END_EH_BLOCK(obj, call) } catch(std::bad_alloc& e) { \
OOM_panic(); \
} catch(std::exception& e) { \
messages << messages << "[dumper " << obj->get_name() << "] Warning: " call ": " << e.what() \
<< std::endl; \
} catch(int code) { \
messages << messages << "[dumper " << obj->get_name() << "] Warning: " call ": Error code #" << code \
<< std::endl; \
}
gameinfo_struct::gameinfo_struct() throw(std::bad_alloc)
{
length = 0;
rerecords = "0";
}
std::string gameinfo_struct::get_readable_time(unsigned digits) const throw(std::bad_alloc)
{
double bias = 0.5 * pow(10, -static_cast<int>(digits));
double len = length + bias;
std::ostringstream str;
if(length >= 3600) {
double hours = floor(len / 3600);
str << hours << ":";
len -= hours * 3600;
}
double minutes = floor(len / 60);
len -= minutes * 60;
double seconds = floor(len);
len -= seconds;
str << std::setw(2) << std::setfill('0') << minutes << ":" << seconds;
if(digits > 0)
str << ".";
while(digits > 0) {
len = 10 * len;
str << '0' + static_cast<int>(len);
len -= floor(len);
digits--;
}
}
size_t gameinfo_struct::get_author_count() const throw()
{
return authors.size();
}
std::string gameinfo_struct::get_author_short(size_t idx) const throw(std::bad_alloc)
{
if(idx >= authors.size())
return "";
const std::pair<std::string, std::string>& x = authors[idx];
if(x.second != "")
return x.second;
else
return x.first;
}
uint64_t gameinfo_struct::get_rerecords() const throw()
{
uint64_t v = 0;
uint64_t max = 0xFFFFFFFFFFFFFFFFULL;
for(size_t i = 0; i < rerecords.length(); i++) {
if(v < max / 10)
//No risk of overflow.
v = v * 10 + static_cast<unsigned>(rerecords[i] - '0');
else if(v == max / 10) {
//THis may overflow.
v = v * 10;
if(v + static_cast<unsigned>(rerecords[i] - '0') < v)
return max;
v = v + static_cast<unsigned>(rerecords[i] - '0');
} else
//Definite overflow.
return max;
}
return v;
}
namespace
{
globalwrap<std::list<information_dispatch*>> dispatch;
uint32_t srate_n = 32000;
uint32_t srate_d = 1;
struct gameinfo_struct sgi;
information_dispatch* exclusive_key = NULL;
int32_t vc_xoffset = 0;
int32_t vc_yoffset = 0;
uint32_t vc_hscl = 1;
uint32_t vc_vscl = 1;
bool recursive = false;
}
information_dispatch::information_dispatch(const std::string& name) throw(std::bad_alloc)
{
target_name = name;
dispatch().push_back(this);
known_if_dumper = false;
marked_as_dumper = false;
notified_as_dumper = false;
grabbing_keys = false;
}
information_dispatch::~information_dispatch() throw()
{
for(auto i = dispatch().begin(); i != dispatch().end(); ++i) {
if(*i == this) {
dispatch().erase(i);
break;
}
}
if(notified_as_dumper)
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_destroy_dumper(target_name);
END_EH_BLOCK(i, "on_destroy_dumper");
}
}
void information_dispatch::on_close()
{
//Do nothing.
}
void information_dispatch::do_close() throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_close();
END_EH_BLOCK(i, "on_close");
}
}
void information_dispatch::on_click(int32_t x, int32_t y, uint32_t buttonmask)
{
//Do nothing.
}
void information_dispatch::do_click(int32_t x, int32_t y, uint32_t buttonmask) throw()
{
x = (x - vc_xoffset) / vc_hscl;
y = (y - vc_yoffset) / vc_vscl;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_click(x, y, buttonmask);
END_EH_BLOCK(i, "on_click");
}
}
void information_dispatch::on_sound_unmute(bool unmuted)
{
//Do nothing.
}
void information_dispatch::do_sound_unmute(bool unmuted) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_sound_unmute(unmuted);
END_EH_BLOCK(i, "on_sound_unmute");
}
}
void information_dispatch::on_sound_change(const std::string& dev)
{
//Do nothing.
}
void information_dispatch::do_sound_change(const std::string& dev) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_sound_change(dev);
END_EH_BLOCK(i, "on_sound_change");
}
}
void information_dispatch::on_mode_change(bool readonly)
{
//Do nothing.
}
void information_dispatch::do_mode_change(bool readonly) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_mode_change(readonly);
END_EH_BLOCK(i, "on_mode_change");
}
}
void information_dispatch::on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate)
{
//Do nothing.
}
void information_dispatch::do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_autohold_update(pid, ctrlnum, newstate);
END_EH_BLOCK(i, "on_autohold_update");
}
}
void information_dispatch::on_autohold_reconfigure()
{
//Do nothing.
}
void information_dispatch::do_autohold_reconfigure() throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_autohold_reconfigure();
END_EH_BLOCK(i, "on_autohold_reconfigure");
}
}
void information_dispatch::on_setting_change(const std::string& setting, const std::string& value)
{
//Do nothing.
}
void information_dispatch::do_setting_change(const std::string& setting, const std::string& value) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_setting_change(setting, value);
END_EH_BLOCK(i, "on_setting_change");
}
}
void information_dispatch::on_setting_clear(const std::string& setting)
{
//Do nothing.
}
void information_dispatch::do_setting_clear(const std::string& setting) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_setting_clear(setting);
END_EH_BLOCK(i, "on_setting_clear");
}
}
void information_dispatch::on_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan,
unsigned region)
{
//Do nothing.
}
void information_dispatch::do_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan,
unsigned region) throw()
{
update_dumpers();
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_raw_frame(raw, hires, interlaced, overscan, region);
END_EH_BLOCK(i, "on_raw_frame");
}
}
void information_dispatch::on_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d)
{
//Do nothing.
}
void information_dispatch::do_frame(struct lcscreen& _frame, uint32_t fps_n, uint32_t fps_d) throw()
{
update_dumpers();
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_frame(_frame, fps_n, fps_d);
END_EH_BLOCK(i, "on_frame");
}
}
void information_dispatch::on_sample(short l, short r)
{
//Do nothing.
}
void information_dispatch::do_sample(short l, short r) throw()
{
update_dumpers();
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_sample(l, r);
END_EH_BLOCK(i, "on_sample");
}
}
void information_dispatch::on_dump_end()
{
//Do nothing.
}
void information_dispatch::do_dump_end() throw()
{
update_dumpers();
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_dump_end();
END_EH_BLOCK(i, "on_dump_end");
}
}
void information_dispatch::on_sound_rate(uint32_t rate_n, uint32_t rate_d)
{
if(!known_if_dumper) {
marked_as_dumper = get_dumper_flag();
known_if_dumper = true;
}
if(marked_as_dumper) {
messages << "[dumper " << get_name() << "] Warning: Sound sample rate changing not supported!"
<< std::endl;
}
}
void information_dispatch::do_sound_rate(uint32_t rate_n, uint32_t rate_d) throw()
{
update_dumpers();
uint32_t g = gcd(rate_n, rate_d);
rate_n /= g;
rate_d /= g;
if(rate_n == srate_n && rate_d == srate_d)
return;
srate_n = rate_n;
srate_d = rate_d;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_sound_rate(rate_n, rate_d);
END_EH_BLOCK(i, "on_sound_rate");
}
}
std::pair<uint32_t, uint32_t> information_dispatch::get_sound_rate() throw()
{
return std::make_pair(srate_n, srate_d);
}
void information_dispatch::on_gameinfo(const struct gameinfo_struct& gi)
{
//Do nothing.
}
void information_dispatch::do_gameinfo(const struct gameinfo_struct& gi) throw()
{
update_dumpers();
try {
sgi = gi;
} catch(...) {
OOM_panic();
}
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_gameinfo(sgi);
END_EH_BLOCK(i, "on_gameinfo");
}
}
const struct gameinfo_struct& information_dispatch::get_gameinfo() throw()
{
return sgi;
}
bool information_dispatch::get_dumper_flag() throw()
{
return false;
}
void information_dispatch::on_new_dumper(const std::string& dumper)
{
//Do nothing.
}
void information_dispatch::on_destroy_dumper(const std::string& dumper)
{
//Do nothing.
}
unsigned information_dispatch::get_dumper_count() throw()
{
update_dumpers(true);
unsigned count = 0;
for(auto& i : dispatch())
if(i->marked_as_dumper)
count++;
if(!recursive) {
recursive = true;
update_dumpers();
recursive = false;
}
return count;
}
std::set<std::string> information_dispatch::get_dumpers() throw(std::bad_alloc)
{
update_dumpers();
std::set<std::string> r;
try {
for(auto& i : dispatch())
if(i->notified_as_dumper)
r.insert(i->get_name());
} catch(...) {
OOM_panic();
}
return r;
}
void information_dispatch::on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name)
{
//Do nothing.
}
void information_dispatch::do_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name) throw()
{
if(exclusive_key) {
START_EH_BLOCK
exclusive_key->on_key_event(modifiers, keygroup, subkey, polarity, name);
END_EH_BLOCK(exclusive_key, "on_key_event");
return;
}
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_key_event(modifiers, keygroup, subkey, polarity, name);
END_EH_BLOCK(i, "on_key_event");
}
}
void information_dispatch::grab_keys() throw()
{
if(grabbing_keys)
return;
exclusive_key = this;
grabbing_keys = true;
}
void information_dispatch::ungrab_keys() throw()
{
if(!grabbing_keys)
return;
exclusive_key = NULL;
grabbing_keys = false;
for(auto& i : dispatch())
if(i->grabbing_keys) {
exclusive_key = i;
break;
}
}
const std::string& information_dispatch::get_name() throw()
{
return target_name;
}
void information_dispatch::update_dumpers(bool nocalls) throw()
{
for(auto& i : dispatch()) {
if(!i->known_if_dumper) {
i->marked_as_dumper = i->get_dumper_flag();
i->known_if_dumper = true;
}
if(i->marked_as_dumper && !i->notified_as_dumper && !nocalls) {
for(auto& j : dispatch()) {
START_EH_BLOCK
j->on_new_dumper(i->target_name);
END_EH_BLOCK(j, "on_new_dumper");
}
i->notified_as_dumper = true;
}
}
}
void information_dispatch::do_click_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl)
{
vc_xoffset = xoffset;
vc_yoffset = yoffset;
vc_hscl = hscl;
vc_vscl = vscl;
}

View file

@ -306,4 +306,4 @@ uint32_t gcd(uint32_t a, uint32_t b) throw()
}
std::string bsnes_core_version;
std::string lsnes_version = "0-β19";
std::string lsnes_version = "0-β20";