Settings-based controllers
This commit is contained in:
parent
8d1b67338c
commit
981df4010c
25 changed files with 1571 additions and 1538 deletions
|
@ -60,10 +60,9 @@ public:
|
|||
* Set types of ports.
|
||||
*
|
||||
* Parameter ptype: The new types for ports.
|
||||
* Parameter set_core: If true, set the core port types too, otherwise don't do that.
|
||||
* Throws std::runtime_error: Illegal port type.
|
||||
*/
|
||||
void set_ports(const port_type_set& ptype, bool set_core) throw(std::runtime_error);
|
||||
void set_ports(const port_type_set& ptype) throw(std::runtime_error);
|
||||
/**
|
||||
* Get status of current controls (with autohold/autofire factored in).
|
||||
*
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <vector>
|
||||
#include "library/framebuffer.hpp"
|
||||
#include "library/controller-data.hpp"
|
||||
#include "core/romtype.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
|
||||
|
||||
//Get the CPU rate.
|
||||
|
@ -62,10 +62,8 @@ unsigned core_get_poll_flag();
|
|||
void core_set_poll_flag(unsigned pflag);
|
||||
//Request reset on next frame.
|
||||
void core_request_reset(long delay);
|
||||
//The port type group.
|
||||
extern port_type_group core_portgroup;
|
||||
//Number of user ports.
|
||||
extern unsigned core_userports;
|
||||
//Valid port types.
|
||||
extern port_type* core_port_types[];
|
||||
//Core supports resets.
|
||||
extern const bool core_supports_reset;
|
||||
//Core supports delayed resets.
|
||||
|
|
|
@ -50,9 +50,9 @@ struct moviefile
|
|||
*/
|
||||
core_sysregion* gametype;
|
||||
/**
|
||||
* The set of port types.
|
||||
* Settings.
|
||||
*/
|
||||
const port_type_set* ports;
|
||||
std::map<std::string, std::string> settings;
|
||||
/**
|
||||
* Emulator Core version string.
|
||||
*/
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include "core/misc.hpp"
|
||||
#include "core/romtype.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
|
||||
/**
|
||||
* Some loaded data or indication of no data.
|
||||
|
@ -144,7 +144,8 @@ struct loaded_rom
|
|||
* throws std::bad_alloc: Not enough memory
|
||||
* throws std::runtime_error: Switching cartridges failed.
|
||||
*/
|
||||
void load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_alloc, std::runtime_error);
|
||||
void load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
throw(std::bad_alloc, std::runtime_error);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
#ifndef _romtype__hpp__included__
|
||||
#define _romtype__hpp__included__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
struct core_region;
|
||||
struct core_type;
|
||||
struct core_sysregion;
|
||||
|
||||
struct core_region
|
||||
{
|
||||
public:
|
||||
core_region(const std::string& iname, const std::string& hname, unsigned priority, unsigned handle,
|
||||
bool multi, uint64_t* fmagic, int (*compatible)(unsigned rom, unsigned run));
|
||||
static core_region& lookup(const std::string& name);
|
||||
const std::string& get_iname();
|
||||
const std::string& get_hname();
|
||||
unsigned get_priority();
|
||||
unsigned get_handle();
|
||||
bool is_multi();
|
||||
void fill_framerate_magic(uint64_t* magic); //4 elements filled.
|
||||
double approx_framerate();
|
||||
bool compatible_with(core_region& run);
|
||||
private:
|
||||
core_region(const core_region&);
|
||||
core_region& operator=(const core_region&);
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
bool multi;
|
||||
unsigned handle;
|
||||
unsigned priority;
|
||||
uint64_t magic[4];
|
||||
int (*compatible)(unsigned rom, unsigned run);
|
||||
};
|
||||
|
||||
struct core_romimage_info
|
||||
{
|
||||
//If headersize is NULL, always use 0.
|
||||
core_romimage_info(const std::string& iname, const std::string& hname, unsigned mandatory,
|
||||
unsigned (*headersize)(size_t imagesize));
|
||||
//This sets pass_by_filename!
|
||||
core_romimage_info(const std::string& iname, const std::string& hname, unsigned mandatory);
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
unsigned mandatory;
|
||||
bool pass_by_filename;
|
||||
unsigned (*headersize)(size_t imagesize);
|
||||
};
|
||||
|
||||
struct core_romimage
|
||||
{
|
||||
const char* markup;
|
||||
const unsigned char* data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct core_type
|
||||
{
|
||||
public:
|
||||
core_type(const std::string& iname, const std::string& hname, unsigned id, int (*_load)(core_romimage* images,
|
||||
uint64_t rtc_sec, uint64_t rtc_subsec), const std::string& extensions);
|
||||
static std::list<core_type*> get_core_types();
|
||||
void add_region(core_region& reg);
|
||||
void add_romimage(core_romimage_info& info, unsigned index);
|
||||
core_region& get_preferred_region();
|
||||
std::list<core_region*> get_regions();
|
||||
core_sysregion& combine_region(core_region& reg);
|
||||
const std::string& get_iname();
|
||||
const std::string& get_hname();
|
||||
const std::list<std::string>& get_extensions();
|
||||
bool is_known_extension(const std::string& ext);
|
||||
std::string get_biosname();
|
||||
unsigned get_id();
|
||||
unsigned get_image_count();
|
||||
core_romimage_info get_image_info(unsigned index);
|
||||
bool load(core_romimage* images, uint64_t rtc_sec, uint64_t rtc_subsec);
|
||||
private:
|
||||
int (*loadimg)(core_romimage* images, uint64_t rtc_sec, uint64_t rtc_subsec);
|
||||
core_type(const core_type&);
|
||||
core_type& operator=(const core_type&);
|
||||
unsigned id;
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
std::string biosname;
|
||||
std::list<std::string> extensions;
|
||||
std::list<core_region*> regions;
|
||||
std::vector<core_romimage_info*> imageinfo;
|
||||
};
|
||||
|
||||
struct core_type_region_bind
|
||||
{
|
||||
public:
|
||||
core_type_region_bind(core_type& type, core_region& region);
|
||||
private:
|
||||
core_type_region_bind(const core_type_region_bind&);
|
||||
core_type_region_bind& operator=(const core_type_region_bind&);
|
||||
};
|
||||
|
||||
struct core_type_image_bind
|
||||
{
|
||||
public:
|
||||
core_type_image_bind(core_type& type, core_romimage_info& imageinfo, unsigned index);
|
||||
private:
|
||||
core_type_image_bind(const core_type_image_bind&);
|
||||
core_type_image_bind& operator=(const core_type_image_bind&);
|
||||
};
|
||||
|
||||
struct core_sysregion
|
||||
{
|
||||
public:
|
||||
core_sysregion(const std::string& name, core_type& type, core_region& region);
|
||||
static core_sysregion& lookup(const std::string& name);
|
||||
const std::string& get_name();
|
||||
core_region& get_region();
|
||||
core_type& get_type();
|
||||
void fill_framerate_magic(uint64_t* magic); //4 elements filled.
|
||||
private:
|
||||
core_sysregion(const core_sysregion&);
|
||||
core_sysregion& operator=(const core_sysregion&);
|
||||
std::string name;
|
||||
core_type& type;
|
||||
core_region& region;
|
||||
};
|
||||
|
||||
#endif
|
17
include/interface/controller.hpp
Normal file
17
include/interface/controller.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef _interface__controller__hpp__included__
|
||||
#define _interface__controller__hpp__included__
|
||||
|
||||
#include "library/controller-data.hpp"
|
||||
|
||||
struct controller_set
|
||||
{
|
||||
struct port_index_map portindex;
|
||||
std::vector<port_type*> ports;
|
||||
};
|
||||
|
||||
struct core_port_types
|
||||
{
|
||||
port_type** types;
|
||||
};
|
||||
|
||||
#endif
|
154
include/interface/romtype.hpp
Normal file
154
include/interface/romtype.hpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
#ifndef _interface__romtype__hpp__included__
|
||||
#define _interface__romtype__hpp__included__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "interface/controller.hpp"
|
||||
#include "interface/setting.hpp"
|
||||
|
||||
struct core_region;
|
||||
struct core_type;
|
||||
struct core_sysregion;
|
||||
struct core_romimage;
|
||||
struct core_romimage_info;
|
||||
|
||||
struct core_region_params
|
||||
{
|
||||
const char* iname;
|
||||
const char* hname;
|
||||
unsigned priority;
|
||||
unsigned handle;
|
||||
bool multi;
|
||||
uint64_t framemagic[4];
|
||||
//Ended by UINT_MAX.
|
||||
unsigned* compatible_runs;
|
||||
};
|
||||
|
||||
struct core_romimage_info_params
|
||||
{
|
||||
const char* iname;
|
||||
const char* hname;
|
||||
unsigned mandatory;
|
||||
int pass_mode; //0 => Content, 1 => File, 2 => Directory.
|
||||
unsigned headersize; //Header size to remove (0 if there is never header to remove).
|
||||
};
|
||||
|
||||
struct core_type_params
|
||||
{
|
||||
const char* iname;
|
||||
const char* hname;
|
||||
unsigned id;
|
||||
unsigned reset_support;
|
||||
int (*load_rom)(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec);
|
||||
controller_set (*controllerconfig)(std::map<std::string, std::string>& settings);
|
||||
const char* extensions; //Separate by ;
|
||||
const char* bios; //Name of BIOS. NULL if none.
|
||||
core_region** regions; //Terminate with NULL.
|
||||
core_romimage_info** images; //Terminate with NULL.
|
||||
core_setting_group* settings;
|
||||
bool (*set_region)(core_region& region);
|
||||
};
|
||||
|
||||
struct core_region
|
||||
{
|
||||
public:
|
||||
core_region(const core_region_params& params);
|
||||
const std::string& get_iname();
|
||||
const std::string& get_hname();
|
||||
unsigned get_priority();
|
||||
unsigned get_handle();
|
||||
bool is_multi();
|
||||
void fill_framerate_magic(uint64_t* magic); //4 elements filled.
|
||||
double approx_framerate();
|
||||
bool compatible_with(core_region& run);
|
||||
private:
|
||||
core_region(const core_region&);
|
||||
core_region& operator=(const core_region&);
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
bool multi;
|
||||
unsigned handle;
|
||||
unsigned priority;
|
||||
uint64_t magic[4];
|
||||
std::vector<unsigned> compatible;
|
||||
};
|
||||
|
||||
struct core_romimage_info
|
||||
{
|
||||
core_romimage_info(const core_romimage_info_params& params);
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
unsigned mandatory;
|
||||
int pass_mode;
|
||||
unsigned headersize;
|
||||
size_t get_headnersize(size_t imagesize);
|
||||
};
|
||||
|
||||
struct core_romimage
|
||||
{
|
||||
const char* markup;
|
||||
const unsigned char* data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct core_type
|
||||
{
|
||||
public:
|
||||
core_type(core_type_params& params);
|
||||
static std::list<core_type*> get_core_types();
|
||||
core_region& get_preferred_region();
|
||||
std::list<core_region*> get_regions();
|
||||
core_sysregion& combine_region(core_region& reg);
|
||||
const std::string& get_iname();
|
||||
const std::string& get_hname();
|
||||
const std::list<std::string>& get_extensions();
|
||||
bool is_known_extension(const std::string& ext);
|
||||
std::string get_biosname();
|
||||
unsigned get_id();
|
||||
unsigned get_image_count();
|
||||
core_romimage_info get_image_info(unsigned index);
|
||||
bool load(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec);
|
||||
controller_set controllerconfig(std::map<std::string, std::string>& settings);
|
||||
unsigned get_reset_support();
|
||||
core_setting_group& get_settings();
|
||||
bool set_region(core_region& region);
|
||||
private:
|
||||
core_type(const core_type&);
|
||||
core_type& operator=(const core_type&);
|
||||
int (*loadimg)(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec);
|
||||
controller_set (*_controllerconfig)(std::map<std::string, std::string>& settings);
|
||||
bool (*_set_region)(core_region& region);
|
||||
unsigned id;
|
||||
unsigned reset_support;
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
std::string biosname;
|
||||
std::list<std::string> extensions;
|
||||
std::list<core_region*> regions;
|
||||
std::vector<core_romimage_info*> imageinfo;
|
||||
core_setting_group* settings;
|
||||
};
|
||||
|
||||
struct core_sysregion
|
||||
{
|
||||
public:
|
||||
core_sysregion(const std::string& name, core_type& type, core_region& region);
|
||||
static core_sysregion& lookup(const std::string& name);
|
||||
const std::string& get_name();
|
||||
core_region& get_region();
|
||||
core_type& get_type();
|
||||
void fill_framerate_magic(uint64_t* magic); //4 elements filled.
|
||||
private:
|
||||
core_sysregion(const core_sysregion&);
|
||||
core_sysregion& operator=(const core_sysregion&);
|
||||
std::string name;
|
||||
core_type& type;
|
||||
core_region& region;
|
||||
};
|
||||
|
||||
#endif
|
184
include/interface/setting.hpp
Normal file
184
include/interface/setting.hpp
Normal file
|
@ -0,0 +1,184 @@
|
|||
#ifndef _interface__setting__hpp__included__
|
||||
#define _interface__setting__hpp__included__
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
struct core_setting;
|
||||
struct core_setting_group;
|
||||
|
||||
/**
|
||||
* A value for setting.
|
||||
*/
|
||||
struct core_setting_value
|
||||
{
|
||||
/**
|
||||
* Create a new setting value.
|
||||
*
|
||||
* Parameter _setting: The setting this value is for.
|
||||
* Parameter _iname: The internal value for setting.
|
||||
* Parameter _hname: The human-readable value for setting.
|
||||
*/
|
||||
core_setting_value(struct core_setting& _setting, const std::string& _iname, const std::string& _hname,
|
||||
signed index)
|
||||
throw(std::bad_alloc);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~core_setting_value();
|
||||
/**
|
||||
* Setting this is for.
|
||||
*/
|
||||
core_setting& setting;
|
||||
/**
|
||||
* Internal value.
|
||||
*/
|
||||
const std::string iname;
|
||||
/**
|
||||
* Human-readable value.
|
||||
*/
|
||||
const std::string hname;
|
||||
/**
|
||||
* Index.
|
||||
*/
|
||||
signed index;
|
||||
private:
|
||||
core_setting_value(core_setting_value&);
|
||||
core_setting_value& operator=(core_setting_value&);
|
||||
};
|
||||
|
||||
/**
|
||||
* A setting.
|
||||
*/
|
||||
struct core_setting
|
||||
{
|
||||
/**
|
||||
* Create a new setting.
|
||||
*
|
||||
* Parameter _group: The group setting is in.
|
||||
* Parameter _iname: The internal name of setting.
|
||||
* Parameter _hname: The human-readable name of setting.
|
||||
* Parameter _dflt: The default value.
|
||||
*/
|
||||
core_setting(core_setting_group& _group, const std::string& _iname, const std::string& _hname,
|
||||
const std::string& _dflt) throw(std::bad_alloc);
|
||||
/**
|
||||
* Create a new setting with regex.
|
||||
*
|
||||
* Parameter _group: The group setting is in.
|
||||
* Parameter _iname: The internal name of setting.
|
||||
* Parameter _hname: The human-readable name of setting.
|
||||
* Parameter _dflt: The default value.
|
||||
* Parameter _regex: The regular expression used for validation.
|
||||
*/
|
||||
core_setting(core_setting_group& _group, const std::string& _iname, const std::string& _hname,
|
||||
const std::string& _dflt, const std::string& _regex) throw(std::bad_alloc);
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~core_setting();
|
||||
/**
|
||||
* Internal name.
|
||||
*/
|
||||
const std::string iname;
|
||||
/**
|
||||
* Human-readable name.
|
||||
*/
|
||||
const std::string hname;
|
||||
/**
|
||||
* Regular expression for validation of fretext setting.
|
||||
*/
|
||||
const std::string regex;
|
||||
/**
|
||||
* The default value.
|
||||
*/
|
||||
const std::string dflt;
|
||||
/**
|
||||
* The values.
|
||||
*/
|
||||
std::vector<core_setting_value*> values;
|
||||
/**
|
||||
* Is this setting a boolean?
|
||||
*/
|
||||
bool is_boolean() const throw();
|
||||
/**
|
||||
* Is this setting a freetext setting?
|
||||
*/
|
||||
bool is_freetext() const throw();
|
||||
/**
|
||||
* Get set of human-readable strings.
|
||||
*/
|
||||
std::vector<std::string> hvalues() const throw(std::runtime_error);
|
||||
/**
|
||||
* Translate hvalue to ivalue.
|
||||
*/
|
||||
std::string hvalue_to_ivalue(const std::string& hvalue) const throw(std::runtime_error);
|
||||
/**
|
||||
* Translate ivalue to index.
|
||||
*/
|
||||
signed ivalue_to_index(const std::string& ivalue) const throw(std::runtime_error);
|
||||
/**
|
||||
* Validate a value.
|
||||
*
|
||||
* Parameter value: The value to validate.
|
||||
*/
|
||||
bool validate(const std::string& value) const;
|
||||
/**
|
||||
* Register a value.
|
||||
*/
|
||||
void do_register(const std::string& name, core_setting_value& value);
|
||||
/**
|
||||
* Unregister a value.
|
||||
*/
|
||||
void do_unregister(const std::string& name);
|
||||
/**
|
||||
* The group setting belongs to.
|
||||
*/
|
||||
struct core_setting_group& group;
|
||||
private:
|
||||
core_setting(core_setting&);
|
||||
core_setting& operator=(core_setting&);
|
||||
};
|
||||
|
||||
/**
|
||||
* A group of settings.
|
||||
*/
|
||||
struct core_setting_group
|
||||
{
|
||||
/**
|
||||
* Create a new group of settings.
|
||||
*/
|
||||
core_setting_group() throw();
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~core_setting_group() throw();
|
||||
/**
|
||||
* Register a setting.
|
||||
*/
|
||||
void do_register(const std::string& name, core_setting& setting);
|
||||
/**
|
||||
* Unregister a setting.
|
||||
*/
|
||||
void do_unregister(const std::string& name);
|
||||
/**
|
||||
* The settings.
|
||||
*/
|
||||
std::map<std::string, core_setting*> settings;
|
||||
/**
|
||||
* Fill a map of settings with defaults.
|
||||
*/
|
||||
void fill_defaults(std::map<std::string, std::string>& values) throw(std::bad_alloc);
|
||||
/**
|
||||
* Get set of settings.
|
||||
*/
|
||||
std::set<std::string> get_setting_set();
|
||||
private:
|
||||
core_setting_group(core_setting_group&);
|
||||
core_setting_group& operator=(core_setting_group&);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -168,71 +168,6 @@ struct port_index_map
|
|||
std::vector<std::pair<unsigned, unsigned>> pcid_map;
|
||||
};
|
||||
|
||||
/**
|
||||
* Group of port types.
|
||||
*/
|
||||
class port_type_group
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct a group.
|
||||
*
|
||||
* Throws std::bad_alloc: Not enough memory.
|
||||
*/
|
||||
port_type_group() throw(std::bad_alloc);
|
||||
/**
|
||||
* Destroy a group.
|
||||
*/
|
||||
~port_type_group() throw();
|
||||
/**
|
||||
* Get port type with specified name.
|
||||
*
|
||||
* Parameter name: The name of port type.
|
||||
* Returns: The port type structure.
|
||||
* Throws std::runtime_error: Specified port type unknown.
|
||||
*/
|
||||
port_type& get_type(const std::string& name) const throw(std::runtime_error);
|
||||
/**
|
||||
* Get set of all port types.
|
||||
*
|
||||
* Returns: The set of all port types.
|
||||
* Throws std::bad_alloc: Not enough memory.
|
||||
*/
|
||||
std::set<port_type*> get_types() const throw(std::bad_alloc);
|
||||
/**
|
||||
* Get default port type for specified port.
|
||||
*
|
||||
* Parameter port: The port.
|
||||
* Returns: The default port type.
|
||||
* Throws std::runtime_error: Bad port.
|
||||
*/
|
||||
port_type& get_default_type(unsigned port) const throw(std::runtime_error);
|
||||
/**
|
||||
* Add a port type.
|
||||
*
|
||||
* Parameter type: Name of the type.
|
||||
* Parameter port: The port type structure.
|
||||
* Throws std::bad_alloc: Not enough memory.
|
||||
*/
|
||||
void register_type(const std::string& type, port_type& port);
|
||||
/**
|
||||
* Remove a port type.
|
||||
*
|
||||
* Parameter type: Name of the type.
|
||||
* Throws std::bad_alloc: Not enough memory.
|
||||
*/
|
||||
void unregister_type(const std::string& type);
|
||||
/**
|
||||
* Set default type for port.
|
||||
*
|
||||
* Parameter port: The port.
|
||||
* Parameter ptype: The port type to make default.
|
||||
*/
|
||||
void set_default(unsigned port, port_type& ptype);
|
||||
private:
|
||||
std::map<std::string, port_type*> types;
|
||||
std::map<unsigned, port_type*> defaults;
|
||||
};
|
||||
|
||||
class port_type_set;
|
||||
|
||||
|
@ -307,14 +242,13 @@ public:
|
|||
/**
|
||||
* Create a new port type.
|
||||
*
|
||||
* Parameter group: The group the type will belong to.
|
||||
* Parameter iname: Internal name of the port type.
|
||||
* Parameter hname: Human-readable name of the port type.
|
||||
* Parameter id: Identifier.
|
||||
* Parameter ssize: The storage size in bytes.
|
||||
* Throws std::bad_alloc: Not enough memory.
|
||||
*/
|
||||
port_type(port_type_group& group, const std::string& iname, const std::string& hname, unsigned id,
|
||||
port_type(const std::string& iname, const std::string& hname, unsigned id,
|
||||
size_t ssize) throw(std::bad_alloc);
|
||||
/**
|
||||
* Unregister a port type.
|
||||
|
@ -378,12 +312,6 @@ public:
|
|||
* Controller info.
|
||||
*/
|
||||
port_controller_set* controller_info;
|
||||
/**
|
||||
* Set this controller as core controller.
|
||||
*
|
||||
* Parameter port: Port to set to.
|
||||
*/
|
||||
void (*set_core_controller)(unsigned port);
|
||||
/**
|
||||
* Get number of used control indices on controller.
|
||||
*
|
||||
|
@ -391,13 +319,6 @@ public:
|
|||
* Returns: Number of used control indices.
|
||||
*/
|
||||
unsigned (*used_indices)(unsigned controller);
|
||||
/**
|
||||
* Construct index map. Only called for port0.
|
||||
*
|
||||
* Parameter types: The port types to construct the map for.
|
||||
* Returns: The index map.
|
||||
*/
|
||||
struct port_index_map (*construct_map)(std::vector<port_type*> types);
|
||||
/**
|
||||
* Human-readable name.
|
||||
*/
|
||||
|
@ -418,10 +339,6 @@ public:
|
|||
* Is given controller present?
|
||||
*/
|
||||
bool is_present(unsigned controller) const throw();
|
||||
/**
|
||||
* Group this port is in.
|
||||
*/
|
||||
port_type_group& ingroup;
|
||||
private:
|
||||
port_type(const port_type&);
|
||||
port_type& operator=(const port_type&);
|
||||
|
@ -441,10 +358,12 @@ public:
|
|||
* Make a port type set with specified types. If called again with the same parameters, returns the same object.
|
||||
*
|
||||
* Parameter types: The types.
|
||||
* Parameter control_map: The control map
|
||||
* Throws std::bad_alloc: Not enough memory.
|
||||
* Throws std::runtime_error: Illegal port types.
|
||||
*/
|
||||
static port_type_set& make(std::vector<port_type*> types) throw(std::bad_alloc, std::runtime_error);
|
||||
static port_type_set& make(std::vector<port_type*> types, struct port_index_map control_map)
|
||||
throw(std::bad_alloc, std::runtime_error);
|
||||
/**
|
||||
* Compare sets for equality.
|
||||
*/
|
||||
|
@ -611,7 +530,7 @@ public:
|
|||
}
|
||||
}
|
||||
private:
|
||||
port_type_set(std::vector<class port_type*> types);
|
||||
port_type_set(std::vector<class port_type*> types, struct port_index_map control_map);
|
||||
size_t* port_offsets;
|
||||
class port_type** port_types;
|
||||
unsigned port_count;
|
||||
|
@ -1268,14 +1187,6 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a dummy port type.
|
||||
*
|
||||
* Return value: Dummy port type.
|
||||
*/
|
||||
port_type& get_dummy_port_type() throw(std::bad_alloc);
|
||||
|
||||
|
||||
/**
|
||||
* Generic port control index function.
|
||||
*/
|
||||
|
|
|
@ -20,8 +20,8 @@ CFLAGS += -DWITH_OPUS_CODEC
|
|||
LDFLAGS += -lopus
|
||||
endif
|
||||
|
||||
DUMMY_LIBRARY=core lua fonts library video dummy
|
||||
PLATFORM_LIBRARY=core lua fonts library video platform
|
||||
DUMMY_LIBRARY=core lua fonts library interface video dummy
|
||||
PLATFORM_LIBRARY=core lua fonts library interface video platform
|
||||
ALLOBJECT=__all__.$(OBJECT_SUFFIX)
|
||||
ALLFLAGS=__all__.ldflags
|
||||
DUMMY_LIBRARY_OBJS=$(patsubst %,%/$(ALLOBJECT),$(DUMMY_LIBRARY))
|
||||
|
@ -42,6 +42,9 @@ fonts/$(ALLOBJECT): forcelook
|
|||
library/$(ALLOBJECT): forcelook
|
||||
$(MAKE) -C library
|
||||
|
||||
interface/$(ALLOBJECT): forcelook
|
||||
$(MAKE) -C interface
|
||||
|
||||
lua/$(ALLOBJECT): forcelook
|
||||
$(MAKE) -C lua
|
||||
|
||||
|
@ -72,6 +75,7 @@ precheck:
|
|||
$(MAKE) -C lua precheck
|
||||
$(MAKE) -C dummy precheck
|
||||
$(MAKE) -C library precheck
|
||||
$(MAKE) -C interface precheck
|
||||
$(MAKE) -C platform precheck
|
||||
$(MAKE) -C util precheck
|
||||
$(MAKE) -C video precheck
|
||||
|
@ -85,6 +89,7 @@ clean:
|
|||
$(MAKE) -C lua clean
|
||||
$(MAKE) -C dummy clean
|
||||
$(MAKE) -C library clean
|
||||
$(MAKE) -C interface clean
|
||||
$(MAKE) -C platform clean
|
||||
$(MAKE) -C util clean
|
||||
$(MAKE) -C video clean
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -148,13 +148,16 @@ namespace
|
|||
static int done = 0;
|
||||
if(done)
|
||||
return;
|
||||
process_port(0, core_portgroup.get_default_type(0));
|
||||
for(unsigned i = 0; i < core_userports; i++) {
|
||||
for(auto j : core_portgroup.get_types()) {
|
||||
if(!j->legal(i))
|
||||
for(unsigned i = 0;; i++) {
|
||||
bool any = false;
|
||||
for(unsigned j = 0; core_port_types[j]; j++) {
|
||||
if(!core_port_types[j]->legal(i))
|
||||
continue;
|
||||
process_port(i + 1, *j);
|
||||
any = true;
|
||||
process_port(i, *core_port_types[j]);
|
||||
}
|
||||
if(!any)
|
||||
break;
|
||||
}
|
||||
done = 1;
|
||||
}
|
||||
|
|
|
@ -90,14 +90,10 @@ void controller_state::autofire(std::vector<controller_frame> pattern) throw(std
|
|||
|
||||
void reread_active_buttons();
|
||||
|
||||
void controller_state::set_ports(const port_type_set& ptype, bool set_core) throw(std::runtime_error)
|
||||
void controller_state::set_ports(const port_type_set& ptype) throw(std::runtime_error)
|
||||
{
|
||||
const port_type_set* oldtype = types;
|
||||
types = &ptype;
|
||||
if(set_core) {
|
||||
for(unsigned i = 1; i < types->ports(); i++)
|
||||
types->port_type(i).set_core_controller(i);
|
||||
}
|
||||
if(oldtype != types) {
|
||||
_input.set_types(ptype);
|
||||
_autohold.set_types(ptype);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "core/dispatch.hpp"
|
||||
#include "core/framebuffer.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
#include "library/pixfmt-rgb32.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/portfn.hpp"
|
||||
|
@ -33,7 +34,6 @@
|
|||
#define LOGICAL_BUTTON_SELECT 6
|
||||
#define LOGICAL_BUTTON_START 7
|
||||
|
||||
port_type_group core_portgroup;
|
||||
unsigned core_userports = 0;
|
||||
extern const bool core_supports_reset = true;
|
||||
extern const bool core_supports_dreset = false;
|
||||
|
@ -61,6 +61,8 @@ namespace
|
|||
uint32_t accumulator_r = 0;
|
||||
unsigned accumulator_s = 0;
|
||||
|
||||
core_setting_group gambatte_settings;
|
||||
|
||||
void init_norom_framebuffer()
|
||||
{
|
||||
static bool done = false;
|
||||
|
@ -95,93 +97,8 @@ namespace
|
|||
};
|
||||
} getinput;
|
||||
|
||||
int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec,
|
||||
core_type* inttype)
|
||||
{
|
||||
const char* markup = img[0].markup;
|
||||
int flags2 = 0;
|
||||
if(markup) {
|
||||
flags2 = atoi(markup);
|
||||
flags2 &= 4;
|
||||
}
|
||||
flags |= flags2;
|
||||
const unsigned char* data = img[0].data;
|
||||
size_t size = img[0].size;
|
||||
|
||||
//Reset it really.
|
||||
instance->~GB();
|
||||
memset(instance, 0, sizeof(gambatte::GB));
|
||||
new(instance) gambatte::GB;
|
||||
instance->setInputGetter(&getinput);
|
||||
instance->set_walltime_fn(walltime_fn);
|
||||
memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
|
||||
frame_overflow = 0;
|
||||
|
||||
rtc_fixed = true;
|
||||
rtc_fixed_val = rtc_sec;
|
||||
instance->load(data, size, flags);
|
||||
rtc_fixed = false;
|
||||
romdata.resize(size);
|
||||
memcpy(&romdata[0], data, size);
|
||||
internal_rom = inttype;
|
||||
do_reset_flag = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int load_rom_dmg(core_romimage* img, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, gambatte::GB::FORCE_DMG, rtc_sec, rtc_subsec, &type_dmg);
|
||||
}
|
||||
|
||||
int load_rom_gbc(core_romimage* img, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, 0, rtc_sec, rtc_subsec, &type_gbc);
|
||||
}
|
||||
|
||||
int load_rom_gbc_gba(core_romimage* img, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, gambatte::GB::GBA_CGB, rtc_sec, rtc_subsec, &type_gbc_gba);
|
||||
}
|
||||
|
||||
uint64_t magic[4] = {35112, 2097152, 16742706, 626688};
|
||||
|
||||
core_region region_world("world", "World", 0, 0, false, magic, regions_compatible);
|
||||
core_romimage_info image_rom_dmg("rom", "Cartridge ROM", 1, NULL);
|
||||
core_romimage_info image_rom_gbc("rom", "Cartridge ROM", 1, NULL);
|
||||
core_romimage_info image_rom_gbca("rom", "Cartridge ROM", 1, NULL);
|
||||
core_type type_dmg("dmg", "Game Boy", 1, load_rom_dmg, "gb;dmg");
|
||||
core_type type_gbc("gbc", "Game Boy Color", 0, load_rom_gbc, "gbc;cgb");
|
||||
core_type type_gbc_gba("gbc_gba", "Game Boy Color (GBA)", 2, load_rom_gbc_gba, "");
|
||||
core_type_region_bind bind_A(type_dmg, region_world);
|
||||
core_type_region_bind bind_B(type_gbc, region_world);
|
||||
core_type_region_bind bind_C(type_gbc_gba, region_world);
|
||||
core_type_image_bind bind_D(type_dmg, image_rom_dmg, 0);
|
||||
core_type_image_bind bind_E(type_gbc, image_rom_gbc, 0);
|
||||
core_type_image_bind bind_F(type_gbc_gba, image_rom_gbca, 0);
|
||||
core_sysregion sr1("gdmg", type_dmg, region_world);
|
||||
core_sysregion sr2("ggbc", type_gbc, region_world);
|
||||
core_sysregion sr3("ggbca", type_gbc_gba, region_world);
|
||||
|
||||
const char* buttonnames[] = {"left", "right", "up", "down", "A", "B", "select", "start"};
|
||||
|
||||
void _set_core_controller(unsigned port) throw() {}
|
||||
|
||||
int get_button_id(unsigned controller, unsigned lbid) throw()
|
||||
{
|
||||
if(controller != 1)
|
||||
return -1;
|
||||
if(lbid == LOGICAL_BUTTON_A) return 0;
|
||||
if(lbid == LOGICAL_BUTTON_B) return 1;
|
||||
if(lbid == LOGICAL_BUTTON_SELECT) return 2;
|
||||
if(lbid == LOGICAL_BUTTON_START) return 3;
|
||||
if(lbid == LOGICAL_BUTTON_RIGHT) return 4;
|
||||
if(lbid == LOGICAL_BUTTON_LEFT) return 5;
|
||||
if(lbid == LOGICAL_BUTTON_UP) return 6;
|
||||
if(lbid == LOGICAL_BUTTON_DOWN) return 7;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void system_write(unsigned char* buffer, unsigned idx, unsigned ctrl, short x) throw()
|
||||
{
|
||||
if(idx < 2 && ctrl < 8)
|
||||
|
@ -241,21 +158,11 @@ namespace
|
|||
return len;
|
||||
}
|
||||
|
||||
void set_core_controller_system(unsigned port) throw()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned _used_indices(unsigned c)
|
||||
{
|
||||
return c ? ((c == 1) ? 8 : 0) : 2;
|
||||
}
|
||||
|
||||
const char* _controller_name(unsigned c)
|
||||
{
|
||||
return c ? ((c == 1) ? "gamepad" : NULL) : "(system)";
|
||||
}
|
||||
struct port_index_map build_indices(std::vector<port_type*> types);
|
||||
|
||||
port_controller_button gamepad_A = {port_controller_button::TYPE_BUTTON, "A"};
|
||||
port_controller_button gamepad_B = {port_controller_button::TYPE_BUTTON, "B"};
|
||||
port_controller_button gamepad_s = {port_controller_button::TYPE_BUTTON, "select"};
|
||||
|
@ -276,41 +183,136 @@ namespace
|
|||
|
||||
struct porttype_system : public port_type
|
||||
{
|
||||
porttype_system() : port_type(core_portgroup, "<SYSTEM>", "<SYSTEM>", 9999, 2)
|
||||
porttype_system() : port_type("<SYSTEM>", "<SYSTEM>", 9999, 2)
|
||||
{
|
||||
write = system_write;
|
||||
read = system_read;
|
||||
display = system_display;
|
||||
serialize = system_serialize;
|
||||
deserialize = system_deserialize;
|
||||
legal = generic_port_legal<0>;
|
||||
construct_map = build_indices;
|
||||
legal = generic_port_legal<1>;
|
||||
used_indices = _used_indices;
|
||||
controller_info = &_controller_info;
|
||||
set_core_controller = set_core_controller_system;
|
||||
core_portgroup.set_default(0, *this);
|
||||
}
|
||||
} psystem;
|
||||
|
||||
struct port_index_map build_indices(std::vector<port_type*> types)
|
||||
int load_rom_common(core_romimage* img, unsigned flags, uint64_t rtc_sec, uint64_t rtc_subsec,
|
||||
core_type* inttype)
|
||||
{
|
||||
struct port_index_map i;
|
||||
i.indices.resize(100);
|
||||
for(unsigned j = 0; j < 100; j++) {
|
||||
i.indices[j].valid = (j < 12) && j != 2 && j != 3;
|
||||
i.indices[j].port = 0;
|
||||
i.indices[j].controller = (j < 4) ? 0 : 1;
|
||||
i.indices[j].control = (j < 4) ? j : (j - 4);;
|
||||
i.indices[j].marks_nonlag = (j >= 4);
|
||||
const char* markup = img[0].markup;
|
||||
int flags2 = 0;
|
||||
if(markup) {
|
||||
flags2 = atoi(markup);
|
||||
flags2 &= 4;
|
||||
}
|
||||
i.logical_map.resize(1);
|
||||
i.logical_map[0] = std::make_pair(0, 1);
|
||||
i.pcid_map.resize(1);
|
||||
i.pcid_map[0] = std::make_pair(0, 1);
|
||||
return i;
|
||||
flags |= flags2;
|
||||
const unsigned char* data = img[0].data;
|
||||
size_t size = img[0].size;
|
||||
|
||||
//Reset it really.
|
||||
instance->~GB();
|
||||
memset(instance, 0, sizeof(gambatte::GB));
|
||||
new(instance) gambatte::GB;
|
||||
instance->setInputGetter(&getinput);
|
||||
instance->set_walltime_fn(walltime_fn);
|
||||
memset(primary_framebuffer, 0, sizeof(primary_framebuffer));
|
||||
frame_overflow = 0;
|
||||
|
||||
rtc_fixed = true;
|
||||
rtc_fixed_val = rtc_sec;
|
||||
instance->load(data, size, flags);
|
||||
rtc_fixed = false;
|
||||
romdata.resize(size);
|
||||
memcpy(&romdata[0], data, size);
|
||||
internal_rom = inttype;
|
||||
do_reset_flag = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int load_rom_dmg(core_romimage* img, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, gambatte::GB::FORCE_DMG, rtc_sec, rtc_subsec, &type_dmg);
|
||||
}
|
||||
|
||||
int load_rom_gbc(core_romimage* img, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, 0, rtc_sec, rtc_subsec, &type_gbc);
|
||||
}
|
||||
|
||||
int load_rom_gbc_gba(core_romimage* img, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec)
|
||||
{
|
||||
return load_rom_common(img, gambatte::GB::GBA_CGB, rtc_sec, rtc_subsec, &type_gbc_gba);
|
||||
}
|
||||
|
||||
port_index_triple t(unsigned p, unsigned c, unsigned i, bool nl)
|
||||
{
|
||||
port_index_triple x;
|
||||
x.port = p;
|
||||
x.controller = c;
|
||||
x.control = i;
|
||||
x.marks_nonlag = nl;
|
||||
return x;
|
||||
}
|
||||
|
||||
controller_set _controllerconfig(std::map<std::string, std::string>& settings)
|
||||
{
|
||||
std::map<std::string, std::string> _settings = settings;
|
||||
controller_set r;
|
||||
r.ports.push_back(&psystem);
|
||||
for(unsigned i = 0; i < 4; i++)
|
||||
r.portindex.indices.push_back(t(0, 0, i, false));
|
||||
for(unsigned i = 0; i < 8; i++)
|
||||
r.portindex.indices.push_back(t(0, 1, i, true));
|
||||
r.portindex.logical_map.push_back(std::make_pair(0, 1));
|
||||
r.portindex.pcid_map.push_back(std::make_pair(0, 1));
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
unsigned world_compatible[] = {0, UINT_MAX};
|
||||
core_region_params _region_world = {
|
||||
"world", "World", 1, 0, false, {35112, 2097152, 16742706, 626688}, world_compatible
|
||||
};
|
||||
core_romimage_info_params _image_rom = {
|
||||
"rom", "Cartridge ROM", 1, 0, 0
|
||||
};
|
||||
|
||||
core_region region_world(_region_world);
|
||||
core_romimage_info image_rom_dmg(_image_rom);
|
||||
core_romimage_info image_rom_gbc(_image_rom);
|
||||
core_romimage_info image_rom_gbca(_image_rom);
|
||||
core_region* regions_gambatte[] = {®ion_world, NULL};
|
||||
core_romimage_info* dmg_images[] = {&image_rom_dmg, NULL};
|
||||
core_romimage_info* gbc_images[] = {&image_rom_gbc, NULL};
|
||||
core_romimage_info* gbca_images[] = {&image_rom_gbca, NULL};
|
||||
|
||||
core_type_params _type_dmg = {
|
||||
"dmg", "Game Boy", 1, 1, load_rom_dmg, _controllerconfig, "gb;dmg", NULL,
|
||||
regions_gambatte, dmg_images, &gambatte_settings, core_set_region
|
||||
};
|
||||
core_type_params _type_gbc = {
|
||||
"gbc", "Game Boy Color", 0, 1, load_rom_gbc, _controllerconfig, "gbc;cgb", NULL,
|
||||
regions_gambatte, gbc_images, &gambatte_settings, core_set_region
|
||||
};
|
||||
core_type_params _type_gbc_gba = {
|
||||
"gbc_gba", "Game Boy Color (GBA)", 2, 1, load_rom_gbc_gba, _controllerconfig, "", NULL,
|
||||
regions_gambatte, gbca_images, &gambatte_settings, core_set_region
|
||||
};
|
||||
core_type type_dmg(_type_dmg);
|
||||
core_type type_gbc(_type_gbc);
|
||||
core_type type_gbc_gba(_type_gbc_gba);
|
||||
core_sysregion sr1("gdmg", type_dmg, region_world);
|
||||
core_sysregion sr2("ggbc", type_gbc, region_world);
|
||||
core_sysregion sr3("ggbca", type_gbc_gba, region_world);
|
||||
}
|
||||
|
||||
port_type* core_port_types[] = {
|
||||
&psystem, NULL
|
||||
};
|
||||
|
||||
std::string get_logical_button_name(unsigned lbid) throw(std::bad_alloc)
|
||||
{
|
||||
if(lbid >= sizeof(buttonnames) / sizeof(buttonnames[0]))
|
||||
|
|
|
@ -232,6 +232,7 @@ extern time_t random_seed_value;
|
|||
|
||||
void do_load_beginning(bool reload) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
bool force_rw = false;
|
||||
if(!our_movie.gametype && !reload) {
|
||||
messages << "Can't load movie without a ROM" << std::endl;
|
||||
return;
|
||||
|
@ -243,16 +244,23 @@ void do_load_beginning(bool reload) throw(std::bad_alloc, std::runtime_error)
|
|||
//Force unlazy rrdata.
|
||||
rrdata::read_base(our_movie.projectid, false);
|
||||
rrdata::add_internal();
|
||||
} else {
|
||||
auto ctrldata = our_rom->rtype->controllerconfig(our_movie.settings);
|
||||
port_type_set& portset = port_type_set::make(ctrldata.ports, ctrldata.portindex);
|
||||
controls.set_ports(portset);
|
||||
if(our_movie.input.get_types() != portset) {
|
||||
//The input type changes, so set the types.
|
||||
force_rw = true;
|
||||
our_movie.input.clear(portset);
|
||||
movb.get_movie().load(our_movie.rerecords, our_movie.projectid, our_movie.input);
|
||||
}
|
||||
}
|
||||
try {
|
||||
bool ro = movb.get_movie().readonly_mode();
|
||||
bool ro = movb.get_movie().readonly_mode() && !force_rw;
|
||||
movb.get_movie().reset_state();
|
||||
random_seed_value = our_movie.movie_rtc_second;
|
||||
our_rom->load(our_movie.movie_rtc_second, our_movie.movie_rtc_subsecond);
|
||||
if(our_rom->rtype)
|
||||
our_rom->load(our_movie.settings, our_movie.movie_rtc_second, our_movie.movie_rtc_subsecond);
|
||||
our_movie.gametype = &our_rom->rtype->combine_region(*our_rom->region);
|
||||
else
|
||||
our_movie.gametype = NULL;
|
||||
if(reload)
|
||||
movb.get_movie().readonly_mode(ro);
|
||||
|
||||
|
@ -329,6 +337,9 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
newmovie.restore_state(_movie.save_frame, _movie.lagged_frames, _movie.pollcounters, true,
|
||||
(lmode == LOAD_STATE_PRESERVE) ? &_movie.input : NULL, _movie.projectid);
|
||||
|
||||
auto ctrldata = our_rom->rtype->controllerconfig(_movie.settings);
|
||||
port_type_set& portset = port_type_set::make(ctrldata.ports, ctrldata.portindex);
|
||||
|
||||
//Negative return.
|
||||
rrdata::read_base(_movie.projectid, _movie.lazy_project_create);
|
||||
rrdata::read(_movie.c_rrdata);
|
||||
|
@ -336,17 +347,17 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
try {
|
||||
our_rom->region = _movie.gametype ? &(_movie.gametype->get_region()) : NULL;
|
||||
random_seed_value = _movie.movie_rtc_second;
|
||||
our_rom->load(_movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||
our_rom->load(_movie.settings, _movie.movie_rtc_second, _movie.movie_rtc_subsecond);
|
||||
|
||||
if(will_load_state) {
|
||||
//Load the savestate and movie state.
|
||||
//Set the core ports in order to avoid port state being reinitialized when loading.
|
||||
controls.set_ports(*_movie.ports, true);
|
||||
controls.set_ports(portset);
|
||||
load_core_state(_movie.savestate);
|
||||
core_set_poll_flag(_movie.poll_flag);
|
||||
} else {
|
||||
load_sram(_movie.movie_sram);
|
||||
controls.set_ports(*_movie.ports, true);
|
||||
controls.set_ports(portset);
|
||||
_movie.rtc_second = _movie.movie_rtc_second;
|
||||
_movie.rtc_subsecond = _movie.movie_rtc_subsecond;
|
||||
if(!_movie.anchor_savestate.empty())
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#define DEFAULT_RTC_SECOND 1000000000ULL
|
||||
#define DEFAULT_RTC_SUBSECOND 0ULL
|
||||
|
||||
|
||||
void read_linefile(zip_reader& r, const std::string& member, std::string& out, bool conditional = false)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
|
@ -30,17 +29,6 @@ void read_linefile(zip_reader& r, const std::string& member, std::string& out, b
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void read_numeric_file(zip_reader& r, const std::string& member, T& out, bool conditional = false)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
std::string _out;
|
||||
read_linefile(r, member, _out, conditional);
|
||||
if(conditional && _out == "")
|
||||
return;
|
||||
out = parse_value<int64_t>(_out);
|
||||
}
|
||||
|
||||
void write_linefile(zip_writer& w, const std::string& member, const std::string& value, bool conditional = false)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
|
@ -56,6 +44,53 @@ void write_linefile(zip_writer& w, const std::string& member, const std::string&
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
std::map<std::string, std::string> read_settings(zip_reader& r)
|
||||
{
|
||||
std::map<std::string, std::string> x;
|
||||
for(auto i : r) {
|
||||
if(!regex_match("port[0-9]+|setting\\..+", i))
|
||||
continue;
|
||||
std::string s;
|
||||
if(i.substr(0, 4) == "port")
|
||||
s = i;
|
||||
else
|
||||
s = i.substr(8);
|
||||
read_linefile(r, i, x[s], true);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void write_settings(zip_writer& w, const std::map<std::string, std::string>& settings,
|
||||
core_setting_group& sgroup)
|
||||
{
|
||||
for(auto i : settings) {
|
||||
if(!sgroup.settings.count(i.first))
|
||||
continue;
|
||||
if(sgroup.settings[i.first]->dflt == i.second)
|
||||
continue;
|
||||
if(regex_match("port[0-9]+", i.first))
|
||||
write_linefile(w, i.first, i.second);
|
||||
else
|
||||
write_linefile(w, "setting." + i.first, i.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void read_numeric_file(zip_reader& r, const std::string& member, T& out, bool conditional = false)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
std::string _out;
|
||||
read_linefile(r, member, _out, conditional);
|
||||
if(conditional && _out == "")
|
||||
return;
|
||||
out = parse_value<int64_t>(_out);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void write_numeric_file(zip_writer& w, const std::string& member, T value) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
|
@ -322,24 +357,11 @@ void write_pollcounters(zip_writer& w, const std::string& file, const std::vecto
|
|||
}
|
||||
}
|
||||
|
||||
port_type& parse_controller_type(const std::string& type, unsigned port) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
try {
|
||||
port_type& i = core_portgroup.get_type(type);
|
||||
if(!i.legal || !(i.legal(port - 1)))
|
||||
throw 42;
|
||||
return i;
|
||||
} catch(...) {
|
||||
(stringfmt() << "Illegal port " << port << " device '" << type << "'").throwex();
|
||||
}
|
||||
}
|
||||
|
||||
moviefile::moviefile() throw(std::bad_alloc)
|
||||
{
|
||||
static port_type_set dummy_types;
|
||||
force_corrupt = false;
|
||||
gametype = NULL;
|
||||
ports = &dummy_types;
|
||||
coreversion = "";
|
||||
projectid = "";
|
||||
rerecords = "0";
|
||||
|
@ -374,15 +396,11 @@ moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtim
|
|||
} catch(std::exception& e) {
|
||||
throw std::runtime_error("Illegal game type '" + tmp + "'");
|
||||
}
|
||||
std::vector<port_type*> pt;
|
||||
pt.push_back(&core_portgroup.get_default_type(0));
|
||||
for(unsigned i = 0; i < core_userports; i++) {
|
||||
tmp = core_portgroup.get_default_type(i + 1).name;
|
||||
read_linefile(r, (stringfmt() << "port" << (i + 1)).str(), tmp, true);
|
||||
pt.push_back(&core_portgroup.get_type(tmp));
|
||||
}
|
||||
ports = &port_type_set::make(pt);
|
||||
input.clear(*ports);
|
||||
settings = read_settings(r);
|
||||
auto ctrldata = gametype->get_type().controllerconfig(settings);
|
||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex);
|
||||
|
||||
input.clear(ports);
|
||||
read_linefile(r, "gamename", gamename, true);
|
||||
read_linefile(r, "projectid", projectid);
|
||||
rerecords = read_rrdata(r, c_rrdata);
|
||||
|
@ -447,9 +465,7 @@ void moviefile::save(const std::string& movie, unsigned compression) throw(std::
|
|||
{
|
||||
zip_writer w(movie, compression);
|
||||
write_linefile(w, "gametype", gametype->get_name());
|
||||
for(unsigned i = 0; i < core_userports; i++)
|
||||
if(ports->port_type(i + 1).name != core_portgroup.get_default_type(i + 1).name)
|
||||
write_linefile(w, (stringfmt() << "port" << (i + 1)).str(), ports->port_type(i + 1).name);
|
||||
write_settings(w, settings, gametype->get_type().get_settings());
|
||||
write_linefile(w, "gamename", gamename, true);
|
||||
write_linefile(w, "systemid", "lsnes-rr1");
|
||||
write_linefile(w, "controlsversion", "0");
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "core/rom.hpp"
|
||||
#include "core/settings.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/portfn.hpp"
|
||||
#include "library/patch.hpp"
|
||||
#include "library/sha256.hpp"
|
||||
#include "library/string.hpp"
|
||||
|
@ -39,8 +40,67 @@ namespace boost_fs = boost::filesystem;
|
|||
|
||||
namespace
|
||||
{
|
||||
core_type* current_rom_type = NULL;
|
||||
core_region* current_region = NULL;
|
||||
const char* null_chars = "F";
|
||||
|
||||
port_controller_button* null_buttons[] = {};
|
||||
port_controller simple_controller = {"(system)", "system", 0, null_buttons};
|
||||
port_controller* simple_controllers[] = {&simple_controller};
|
||||
port_controller_set simple_port = {1, simple_controllers};
|
||||
|
||||
struct porttype_null : public port_type
|
||||
{
|
||||
porttype_null() : port_type("null", "null", 999997, 1)
|
||||
{
|
||||
write = generic_port_write<1, 0, 1>;
|
||||
read = generic_port_read<1, 0, 1>;
|
||||
display = generic_port_display<1, 0, 1, &null_chars>;
|
||||
serialize = generic_port_serialize<1, 0, 1, &null_chars>;
|
||||
deserialize = generic_port_deserialize<1, 0, 1>;
|
||||
legal = generic_port_legal<1>;
|
||||
controller_info = &simple_port;
|
||||
used_indices = generic_used_indices<1, 1>;
|
||||
}
|
||||
} pnull;
|
||||
|
||||
port_index_triple sync_triple = {true, 0, 0, 0, false };
|
||||
|
||||
controller_set null_controllerconfig(std::map<std::string, std::string>& settings)
|
||||
{
|
||||
controller_set x;
|
||||
x.ports.push_back(&pnull);
|
||||
x.portindex.indices.push_back(sync_triple);
|
||||
return x;
|
||||
}
|
||||
|
||||
bool set_region_null(core_region& reg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int load_rom_null(core_romimage* img, std::map<std::string, std::string>& settings,
|
||||
uint64_t secs, uint64_t subsecs)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
core_setting_group null_settings;
|
||||
|
||||
unsigned null_compatible[] = {0, UINT_MAX};
|
||||
struct core_region_params _null_region = {
|
||||
"null", "(null)", 0, 0, false, {1, 60, 16666666, 40}, null_compatible
|
||||
};
|
||||
core_region null_region(_null_region);
|
||||
core_region* null_regions[] = {&null_region, NULL};
|
||||
core_romimage_info* null_images[] = {NULL};
|
||||
core_type_params _type_null = {
|
||||
"null", "(null)", 9999, 0, load_rom_null, null_controllerconfig,
|
||||
"", NULL, null_regions, null_images, &null_settings, set_region_null
|
||||
};
|
||||
core_type type_null(_type_null);
|
||||
core_sysregion sysregion_null("null", type_null, null_region);
|
||||
|
||||
core_type* current_rom_type = &type_null;
|
||||
core_region* current_region = &null_region;
|
||||
}
|
||||
|
||||
loaded_slot::loaded_slot() throw(std::bad_alloc)
|
||||
|
@ -59,11 +119,11 @@ loaded_slot::loaded_slot(const std::string& filename, const std::string& base,
|
|||
if(filename == "") {
|
||||
valid = false;
|
||||
sha_256 = "";
|
||||
filename_flag = (!xml && imginfo.pass_by_filename);
|
||||
filename_flag = (!xml && imginfo.pass_mode);
|
||||
return;
|
||||
}
|
||||
//XMLs are always loaded, no matter what.
|
||||
if(!xml && imginfo.pass_by_filename) {
|
||||
if(!xml && imginfo.pass_mode) {
|
||||
std::string _filename = filename;
|
||||
//Translate the passed filename to absolute one.
|
||||
_filename = resolve_file_relative(_filename, base);
|
||||
|
@ -86,8 +146,8 @@ loaded_slot::loaded_slot(const std::string& filename, const std::string& base,
|
|||
filename_flag = false;
|
||||
valid = true;
|
||||
data = read_file_relative(filename, base);
|
||||
if(!xml)
|
||||
headered = imginfo.headersize(data.size());
|
||||
if(!xml && imginfo.headersize)
|
||||
headered = ((data.size() % (2 * imginfo.headersize)) == imginfo.headersize) ? imginfo.headersize : 0;
|
||||
if(headered && !xml) {
|
||||
if(data.size() >= headered) {
|
||||
memmove(&data[0], &data[headered], data.size() - headered);
|
||||
|
@ -136,8 +196,8 @@ std::pair<core_type*, core_region*> get_current_rom_info() throw()
|
|||
|
||||
loaded_rom::loaded_rom() throw()
|
||||
{
|
||||
rtype = NULL;
|
||||
region = orig_region = NULL;
|
||||
rtype = &type_null;
|
||||
region = orig_region = &null_region;
|
||||
}
|
||||
|
||||
loaded_rom::loaded_rom(const std::string& file) throw(std::bad_alloc, std::runtime_error)
|
||||
|
@ -187,11 +247,11 @@ loaded_rom::loaded_rom(const std::string& file) throw(std::bad_alloc, std::runti
|
|||
}
|
||||
|
||||
//Detect type.
|
||||
rtype = NULL;
|
||||
rtype = &type_null;
|
||||
for(auto i : possible)
|
||||
if(i->get_iname() == platname)
|
||||
rtype = i;
|
||||
if(!rtype)
|
||||
if(rtype == &type_null)
|
||||
(stringfmt() << "Not a valid system type '" << platname << "'").throwex();
|
||||
|
||||
//Detect region.
|
||||
|
@ -272,16 +332,17 @@ loaded_rom::loaded_rom(const std::string& file) throw(std::bad_alloc, std::runti
|
|||
msu1_base = resolve_file_relative(cromimg[0], file);
|
||||
}
|
||||
|
||||
void loaded_rom::load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_alloc, std::runtime_error)
|
||||
void loaded_rom::load(std::map<std::string, std::string>& settings, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
current_rom_type = NULL;
|
||||
if(!orig_region && rtype)
|
||||
current_rom_type = &type_null;
|
||||
if(!orig_region && rtype != &type_null)
|
||||
orig_region = &rtype->get_preferred_region();
|
||||
if(!region)
|
||||
region = orig_region;
|
||||
if(rtype && !orig_region->compatible_with(*region))
|
||||
throw std::runtime_error("Trying to force incompatible region");
|
||||
if(rtype && !core_set_region(*region))
|
||||
if(rtype && !rtype->set_region(*region))
|
||||
throw std::runtime_error("Trying to force unknown region");
|
||||
|
||||
core_romimage images[sizeof(romimg)/sizeof(romimg[0])];
|
||||
|
@ -291,13 +352,17 @@ void loaded_rom::load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_allo
|
|||
images[i].size = (size_t)romimg[i];
|
||||
}
|
||||
if(rtype) {
|
||||
if(!rtype->load(images, rtc_sec, rtc_subsec))
|
||||
if(!rtype->load(images, settings, rtc_sec, rtc_subsec))
|
||||
throw std::runtime_error("Can't load cartridge ROM");
|
||||
} else
|
||||
core_unload_cartridge();
|
||||
|
||||
if(rtype == &type_null) {
|
||||
region = &null_region;
|
||||
} else {
|
||||
region = &core_get_region();
|
||||
core_power();
|
||||
}
|
||||
auto nominal_fps = get_video_rate();
|
||||
auto nominal_hz = get_audio_rate();
|
||||
set_nominal_framerate(1.0 * nominal_fps.first / nominal_fps.second);
|
||||
|
|
16
src/interface/Makefile
Normal file
16
src/interface/Makefile
Normal file
|
@ -0,0 +1,16 @@
|
|||
OBJECTS=$(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard *.cpp))
|
||||
|
||||
.PRECIOUS: %.$(OBJECT_SUFFIX)
|
||||
|
||||
__all__.$(OBJECT_SUFFIX): $(OBJECTS)
|
||||
$(REALLD) -r -o $@ $^
|
||||
touch __all__.ldflags
|
||||
|
||||
%.$(OBJECT_SUFFIX): %.cpp
|
||||
$(REALCC) $(CFLAGS) -c -o $@ $< -I../../include
|
||||
|
||||
precheck:
|
||||
@true
|
||||
|
||||
clean:
|
||||
rm -f *.$(OBJECT_SUFFIX) *.ldflags
|
|
@ -1,4 +1,4 @@
|
|||
#include "core/romtype.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include <map>
|
||||
|
@ -7,6 +7,7 @@
|
|||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <list>
|
||||
#include <limits>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -22,58 +23,6 @@ namespace
|
|||
return x;
|
||||
}
|
||||
|
||||
std::map<std::string, core_region*>& regionss()
|
||||
{
|
||||
static std::map<std::string, core_region*> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
std::list<std::pair<core_type*, core_region*>>& reglist1()
|
||||
{
|
||||
static std::list<std::pair<core_type*, core_region*>> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
std::list<std::pair<core_type*, std::pair<core_romimage_info*, unsigned>>>& reglist2()
|
||||
{
|
||||
static std::list<std::pair<core_type*, std::pair<core_romimage_info*, unsigned>>> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
void process_registrations()
|
||||
{
|
||||
auto& l = reglist1();
|
||||
for(auto i = l.begin(); i != l.end();) {
|
||||
auto& m = types();
|
||||
bool done = false;
|
||||
for(auto j : m)
|
||||
if(j.second == i->first) {
|
||||
auto iold = i;
|
||||
i->first->add_region(*i->second);
|
||||
i++;
|
||||
l.erase(iold);
|
||||
done = true;
|
||||
}
|
||||
if(!done)
|
||||
i++;
|
||||
}
|
||||
auto& l2 = reglist2();
|
||||
for(auto i = l2.begin(); i != l2.end();) {
|
||||
auto& m = types();
|
||||
bool done = false;
|
||||
for(auto j : m)
|
||||
if(j.second == i->first) {
|
||||
auto iold = i;
|
||||
i->first->add_romimage(*i->second.first, i->second.second);
|
||||
i++;
|
||||
l2.erase(iold);
|
||||
done = true;
|
||||
}
|
||||
if(!done)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
bool compare_coretype(core_type* a, core_type* b)
|
||||
{
|
||||
return (a->get_id() < b->get_id());
|
||||
|
@ -90,27 +39,29 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
core_region::core_region(const std::string& _iname, const std::string& _hname, unsigned _priority, unsigned _handle,
|
||||
bool _multi, uint64_t* _fmagic, int (*_compatible)(unsigned rom, unsigned run))
|
||||
: iname(_iname), hname(_hname), priority(_priority), handle(_handle), compatible(_compatible),
|
||||
multi(_multi)
|
||||
core_region::core_region(const core_region_params& params)
|
||||
{
|
||||
iname = params.iname;
|
||||
hname = params.hname;
|
||||
multi = params.multi;
|
||||
handle = params.handle;
|
||||
priority = params.priority;
|
||||
for(size_t i = 0; i < 4; i++)
|
||||
magic[i] = _fmagic[i];
|
||||
regionss()[_iname] = this;
|
||||
magic[i] = params.framemagic[4];
|
||||
for(size_t i = 0;; i++)
|
||||
if(params.compatible_runs[i] == std::numeric_limits<unsigned>::max())
|
||||
break;
|
||||
else
|
||||
compatible.push_back(params.compatible_runs[i]);
|
||||
}
|
||||
|
||||
|
||||
bool core_region::compatible_with(core_region& run)
|
||||
{
|
||||
return (compatible(handle, run.handle) != 0);
|
||||
}
|
||||
|
||||
core_region& core_region::lookup(const std::string& name)
|
||||
{
|
||||
if(regionss().count(name))
|
||||
return *(regionss()[name]);
|
||||
else
|
||||
throw std::runtime_error("Bad region");
|
||||
for(auto i : compatible)
|
||||
if(i == run.handle)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool core_region::is_multi()
|
||||
|
@ -149,6 +100,160 @@ double core_region::approx_framerate()
|
|||
return (double)magic[1] / magic[0];
|
||||
}
|
||||
|
||||
core_romimage_info::core_romimage_info(const core_romimage_info_params& params)
|
||||
{
|
||||
iname = params.iname;
|
||||
hname = params.hname;
|
||||
mandatory = params.mandatory;
|
||||
pass_mode = params.pass_mode;
|
||||
headersize = params.headersize;
|
||||
}
|
||||
|
||||
size_t core_romimage_info::get_headnersize(size_t imagesize)
|
||||
{
|
||||
if(headersize && imagesize % (2 * headersize) == headersize)
|
||||
return headersize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
core_type::core_type(core_type_params& params)
|
||||
{
|
||||
iname = params.iname;
|
||||
hname = params.hname;
|
||||
id = params.id;
|
||||
reset_support = params.reset_support;
|
||||
loadimg = params.load_rom;
|
||||
_controllerconfig = params.controllerconfig;
|
||||
_set_region = params.set_region;
|
||||
settings = params.settings;
|
||||
if(params.bios)
|
||||
biosname = params.bios;
|
||||
for(size_t i = 0; params.regions[i]; i++)
|
||||
regions.push_back(params.regions[i]);
|
||||
for(size_t i = 0; params.images[i]; i++)
|
||||
imageinfo.push_back(params.images[i]);
|
||||
if(params.extensions) {
|
||||
std::string tmp = params.extensions;
|
||||
while(tmp != "") {
|
||||
std::string ext;
|
||||
extract_token(tmp, ext, ";");
|
||||
extensions.push_back(ext);
|
||||
}
|
||||
}
|
||||
types()[iname] = this;
|
||||
}
|
||||
|
||||
unsigned core_type::get_id()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
const std::string& core_type::get_iname()
|
||||
{
|
||||
return iname;
|
||||
}
|
||||
|
||||
const std::string& core_type::get_hname()
|
||||
{
|
||||
return hname;
|
||||
}
|
||||
|
||||
unsigned core_type::get_image_count()
|
||||
{
|
||||
return imageinfo.size();
|
||||
}
|
||||
|
||||
core_setting_group& core_type::get_settings()
|
||||
{
|
||||
return *settings;
|
||||
}
|
||||
|
||||
core_romimage_info core_type::get_image_info(unsigned index)
|
||||
{
|
||||
if(index >= imageinfo.size())
|
||||
throw std::runtime_error("Requested invalid image index");
|
||||
return *imageinfo[index];
|
||||
}
|
||||
|
||||
std::list<core_type*> core_type::get_core_types()
|
||||
{
|
||||
std::list<core_type*> ret;
|
||||
for(auto i : types())
|
||||
ret.push_back(i.second);
|
||||
ret.sort(compare_coretype);
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned core_type::get_reset_support()
|
||||
{
|
||||
return reset_support;
|
||||
}
|
||||
|
||||
std::list<core_region*> core_type::get_regions()
|
||||
{
|
||||
std::list<core_region*> ret = regions;
|
||||
ret.sort(compare_regions);
|
||||
return ret;
|
||||
}
|
||||
|
||||
core_region& core_type::get_preferred_region()
|
||||
{
|
||||
core_region* p = NULL;
|
||||
unsigned cutoff = 0;
|
||||
for(auto i : regions) {
|
||||
unsigned pri = i->get_priority();
|
||||
if(pri >= cutoff) {
|
||||
cutoff = max(pri + 1, pri);
|
||||
p = i;
|
||||
}
|
||||
}
|
||||
return *p;
|
||||
}
|
||||
|
||||
bool core_type::load(core_romimage* images, std::map<std::string, std::string>& settings, uint64_t rtc_sec,
|
||||
uint64_t rtc_subsec)
|
||||
{
|
||||
return (loadimg(images, settings, rtc_sec, rtc_subsec) >= 0);
|
||||
}
|
||||
|
||||
core_sysregion& core_type::combine_region(core_region& reg)
|
||||
{
|
||||
for(auto i : sysregions())
|
||||
if(&(i.second->get_type()) == this && &(i.second->get_region()) == ®)
|
||||
return *(i.second);
|
||||
throw std::runtime_error("Invalid region for system type");
|
||||
}
|
||||
|
||||
const std::list<std::string>& core_type::get_extensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
std::string core_type::get_biosname()
|
||||
{
|
||||
return biosname;
|
||||
}
|
||||
|
||||
bool core_type::is_known_extension(const std::string& ext)
|
||||
{
|
||||
std::string _ext = ext;
|
||||
std::transform(_ext.begin(), _ext.end(), _ext.begin(), ::tolower);
|
||||
for(auto i : extensions)
|
||||
if(i == _ext)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
controller_set core_type::controllerconfig(std::map<std::string, std::string>& settings)
|
||||
{
|
||||
return _controllerconfig(settings);
|
||||
}
|
||||
|
||||
bool core_type::set_region(core_region& region)
|
||||
{
|
||||
return _set_region(region);
|
||||
}
|
||||
|
||||
core_sysregion::core_sysregion(const std::string& _name, core_type& _type, core_region& _region)
|
||||
: name(_name), type(_type), region(_region)
|
||||
{
|
||||
|
@ -182,145 +287,3 @@ void core_sysregion::fill_framerate_magic(uint64_t* magic)
|
|||
{
|
||||
region.fill_framerate_magic(magic);
|
||||
}
|
||||
|
||||
unsigned core_type::get_id()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
void core_type::add_region(core_region& reg)
|
||||
{
|
||||
regions.push_back(®);
|
||||
}
|
||||
|
||||
void core_type::add_romimage(core_romimage_info& info, unsigned index)
|
||||
{
|
||||
if(imageinfo.size() <= index)
|
||||
imageinfo.resize(index + 1);
|
||||
imageinfo[index] = &info;
|
||||
}
|
||||
|
||||
const std::string& core_type::get_iname()
|
||||
{
|
||||
return iname;
|
||||
}
|
||||
|
||||
const std::string& core_type::get_hname()
|
||||
{
|
||||
return hname;
|
||||
}
|
||||
|
||||
unsigned core_type::get_image_count()
|
||||
{
|
||||
return imageinfo.size();
|
||||
}
|
||||
|
||||
core_romimage_info::core_romimage_info(const std::string& _iname, const std::string& _hname, unsigned _mandatory,
|
||||
unsigned (*_headersize)(size_t imagesize))
|
||||
: iname(_iname), hname(_hname), headersize(_headersize ? _headersize : default_headersize),
|
||||
mandatory(_mandatory), pass_by_filename(false)
|
||||
{
|
||||
}
|
||||
|
||||
core_romimage_info::core_romimage_info(const std::string& _iname, const std::string& _hname, unsigned _mandatory)
|
||||
: iname(_iname), hname(_hname), headersize(NULL), mandatory(_mandatory), pass_by_filename(true)
|
||||
{
|
||||
}
|
||||
|
||||
core_romimage_info core_type::get_image_info(unsigned index)
|
||||
{
|
||||
if(index >= imageinfo.size())
|
||||
throw std::runtime_error("Requested invalid image index");
|
||||
return *imageinfo[index];
|
||||
}
|
||||
|
||||
std::list<core_type*> core_type::get_core_types()
|
||||
{
|
||||
std::list<core_type*> ret;
|
||||
for(auto i : types())
|
||||
ret.push_back(i.second);
|
||||
ret.sort(compare_coretype);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::list<core_region*> core_type::get_regions()
|
||||
{
|
||||
std::list<core_region*> ret = regions;
|
||||
ret.sort(compare_regions);
|
||||
return ret;
|
||||
}
|
||||
|
||||
core_region& core_type::get_preferred_region()
|
||||
{
|
||||
core_region* p = NULL;
|
||||
unsigned cutoff = 0;
|
||||
for(auto i : regions) {
|
||||
unsigned pri = i->get_priority();
|
||||
if(pri >= cutoff) {
|
||||
cutoff = max(pri + 1, pri);
|
||||
p = i;
|
||||
}
|
||||
}
|
||||
return *p;
|
||||
}
|
||||
|
||||
bool core_type::load(core_romimage* images, uint64_t rtc_sec, uint64_t rtc_subsec)
|
||||
{
|
||||
return (loadimg(images, rtc_sec, rtc_subsec) >= 0);
|
||||
}
|
||||
|
||||
core_sysregion& core_type::combine_region(core_region& reg)
|
||||
{
|
||||
for(auto i : sysregions())
|
||||
if(&(i.second->get_type()) == this && &(i.second->get_region()) == ®)
|
||||
return *(i.second);
|
||||
throw std::runtime_error("Invalid region for system type");
|
||||
}
|
||||
|
||||
core_type::core_type(const std::string& _iname, const std::string& _hname, unsigned _id,
|
||||
int (*_load)(core_romimage* images, uint64_t rtc_sec, uint64_t rtc_subsec), const std::string& _extensions)
|
||||
: iname(_iname), hname(_hname), loadimg(_load), id(_id)
|
||||
{
|
||||
types()[iname] = this;
|
||||
std::string ext;
|
||||
std::string ext2 = _extensions;
|
||||
if(ext2.find_first_of("!") < ext2.length())
|
||||
extract_token(ext2, biosname, "!");
|
||||
while(ext2 != "") {
|
||||
extract_token(ext2, ext, ";");
|
||||
extensions.push_back(ext);
|
||||
}
|
||||
process_registrations();
|
||||
}
|
||||
|
||||
const std::list<std::string>& core_type::get_extensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
std::string core_type::get_biosname()
|
||||
{
|
||||
return biosname;
|
||||
}
|
||||
|
||||
bool core_type::is_known_extension(const std::string& ext)
|
||||
{
|
||||
std::string _ext = ext;
|
||||
std::transform(_ext.begin(), _ext.end(), _ext.begin(), ::tolower);
|
||||
for(auto i : extensions)
|
||||
if(i == _ext)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
core_type_region_bind::core_type_region_bind(core_type& type, core_region& region)
|
||||
{
|
||||
reglist1().push_back(std::make_pair(&type, ®ion));
|
||||
process_registrations();
|
||||
}
|
||||
|
||||
core_type_image_bind::core_type_image_bind(core_type& type, core_romimage_info& imageinfo, unsigned index)
|
||||
{
|
||||
reglist2().push_back(std::make_pair(&type, std::make_pair(&imageinfo, index)));
|
||||
process_registrations();
|
||||
}
|
138
src/interface/setting.cpp
Normal file
138
src/interface/setting.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
#include "interface/setting.hpp"
|
||||
#include "library/register-queue.hpp"
|
||||
#include "library/string.hpp"
|
||||
|
||||
core_setting_value::core_setting_value(struct core_setting& _setting, const std::string& _iname,
|
||||
const std::string& _hname, signed _index) throw(std::bad_alloc)
|
||||
: setting(_setting), iname(_iname), hname(_hname), index(_index)
|
||||
{
|
||||
register_queue<core_setting, core_setting_value>::do_register(setting, iname, *this);
|
||||
}
|
||||
|
||||
core_setting_value::~core_setting_value()
|
||||
{
|
||||
register_queue<core_setting, core_setting_value>::do_unregister(setting, iname);
|
||||
}
|
||||
|
||||
core_setting::core_setting(core_setting_group& _group, const std::string& _iname, const std::string& _hname,
|
||||
const std::string& _dflt) throw(std::bad_alloc)
|
||||
: group(_group), iname(_iname), hname(_hname), dflt(_dflt), regex(".*")
|
||||
{
|
||||
register_queue<core_setting, core_setting_value>::do_ready(*this, true);
|
||||
register_queue<core_setting_group, core_setting>::do_register(group, iname, *this);
|
||||
}
|
||||
|
||||
core_setting::core_setting(core_setting_group& _group, const std::string& _iname, const std::string& _hname,
|
||||
const std::string& _dflt, const std::string& _regex) throw(std::bad_alloc)
|
||||
: group(_group), iname(_iname), hname(_hname), dflt(_dflt), regex(_regex)
|
||||
{
|
||||
register_queue<core_setting, core_setting_value>::do_ready(*this, true);
|
||||
register_queue<core_setting_group, core_setting>::do_register(group, iname, *this);
|
||||
}
|
||||
|
||||
core_setting::~core_setting()
|
||||
{
|
||||
register_queue<core_setting, core_setting_value>::do_ready(*this, false);
|
||||
register_queue<core_setting_group, core_setting>::do_unregister(group, iname);
|
||||
}
|
||||
|
||||
void core_setting::do_register(const std::string& name, core_setting_value& value)
|
||||
{
|
||||
values.push_back(&value);
|
||||
}
|
||||
|
||||
void core_setting::do_unregister(const std::string& name)
|
||||
{
|
||||
for(auto i = values.begin(); i != values.end(); i++)
|
||||
if((*i)->iname == name) {
|
||||
values.erase(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool core_setting::is_boolean() const throw()
|
||||
{
|
||||
if(values.size() != 2)
|
||||
return false;
|
||||
std::string a = values[0]->iname;
|
||||
std::string b = values[1]->iname;
|
||||
if(a < b)
|
||||
std::swap(a, b);
|
||||
return (a == "0" && b == "1");
|
||||
}
|
||||
|
||||
bool core_setting::is_freetext() const throw()
|
||||
{
|
||||
return (values.size() == 0);
|
||||
}
|
||||
|
||||
bool core_setting::validate(const std::string& value) const
|
||||
{
|
||||
if(values.size() != 0) {
|
||||
for(auto i : values)
|
||||
if(i->iname == value)
|
||||
return true;
|
||||
return false;
|
||||
} else
|
||||
return regex_match(regex, value);
|
||||
}
|
||||
|
||||
core_setting_group::core_setting_group() throw()
|
||||
{
|
||||
register_queue<core_setting_group, core_setting>::do_ready(*this, true);
|
||||
}
|
||||
core_setting_group::~core_setting_group() throw()
|
||||
{
|
||||
register_queue<core_setting_group, core_setting>::do_ready(*this, false);
|
||||
}
|
||||
|
||||
void core_setting_group::do_register(const std::string& name, core_setting& setting)
|
||||
{
|
||||
settings[name] = &setting;
|
||||
}
|
||||
|
||||
void core_setting_group::do_unregister(const std::string& name)
|
||||
{
|
||||
settings.erase(name);
|
||||
}
|
||||
|
||||
void core_setting_group::fill_defaults(std::map<std::string, std::string>& values) throw(std::bad_alloc)
|
||||
{
|
||||
for(auto i : settings)
|
||||
if(!values.count(i.first))
|
||||
values[i.first] = i.second->dflt;
|
||||
}
|
||||
|
||||
std::set<std::string> core_setting_group::get_setting_set()
|
||||
{
|
||||
std::set<std::string> r;
|
||||
for(auto i : settings)
|
||||
r.insert(i.first);
|
||||
return r;
|
||||
}
|
||||
|
||||
std::vector<std::string> core_setting::hvalues() const throw(std::runtime_error)
|
||||
{
|
||||
std::vector<std::string> x;
|
||||
if(values.size() == 0)
|
||||
throw std::runtime_error("hvalues() not valid for freetext settings");
|
||||
for(auto i : values)
|
||||
x.push_back(i->hname);
|
||||
return x;
|
||||
}
|
||||
|
||||
std::string core_setting::hvalue_to_ivalue(const std::string& hvalue) const throw(std::runtime_error)
|
||||
{
|
||||
for(auto i : values)
|
||||
if(i->hname == hvalue)
|
||||
return i->iname;
|
||||
throw std::runtime_error("Invalid hvalue for setting");
|
||||
}
|
||||
|
||||
signed core_setting::ivalue_to_index(const std::string& ivalue) const throw(std::runtime_error)
|
||||
{
|
||||
for(auto i : values)
|
||||
if(i->iname == ivalue)
|
||||
return i->index;
|
||||
throw std::runtime_error("Invalid ivalue for setting");
|
||||
}
|
|
@ -8,34 +8,6 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
void set_core_controller_illegal(unsigned port) throw()
|
||||
{
|
||||
std::cerr << "Attempt to set core port type to INVALID port type" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int button_id_illegal(unsigned controller, unsigned lbid)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct port_index_map invalid_construct_map(std::vector<port_type*> types)
|
||||
{
|
||||
struct port_index_map i;
|
||||
i.indices.resize(1);
|
||||
i.indices[0].valid = true;
|
||||
i.indices[0].port = 0;
|
||||
i.indices[0].controller = 0;
|
||||
i.indices[0].control = 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
inline const char* invalid_controller_name(unsigned c)
|
||||
{
|
||||
return c ? NULL : "(system)";
|
||||
}
|
||||
|
||||
const char* invalid_chars = "";
|
||||
const char* basecontrol_chars = "F";
|
||||
|
||||
port_controller_button* null_buttons[] = {};
|
||||
|
@ -43,38 +15,18 @@ namespace
|
|||
port_controller* simple_controllers[] = {&simple_controller};
|
||||
port_controller_set simple_port = {1, simple_controllers};
|
||||
|
||||
struct port_type_group invalid_group;
|
||||
struct porttype_invalid : public port_type
|
||||
{
|
||||
porttype_invalid() : port_type(invalid_group, "invalid-port-type", "invalid-port-type", 999999, 0)
|
||||
{
|
||||
write = generic_port_write<0, 0, 0>;
|
||||
read = generic_port_read<0, 0, 0>;
|
||||
display = generic_port_display<0, 0, 0, &invalid_chars>;
|
||||
serialize = generic_port_serialize<0, 0, 0, &invalid_chars>;
|
||||
deserialize = generic_port_deserialize<0, 0, 0>;
|
||||
legal = generic_port_legal<0xFFFFFFFFU>;
|
||||
controller_info = &simple_port;
|
||||
used_indices = generic_used_indices<0, 0>;
|
||||
construct_map = invalid_construct_map;
|
||||
set_core_controller = set_core_controller_illegal;
|
||||
}
|
||||
};
|
||||
|
||||
struct porttype_basecontrol : public port_type
|
||||
{
|
||||
porttype_basecontrol() : port_type(invalid_group, "basecontrol", "basecontrol", 999998, 0)
|
||||
porttype_basecontrol() : port_type("basecontrol", "basecontrol", 999998, 0)
|
||||
{
|
||||
write = generic_port_write<1, 0, 1>;
|
||||
read = generic_port_read<1, 0, 1>;
|
||||
display = generic_port_display<1, 0, 1, &basecontrol_chars>;
|
||||
serialize = generic_port_serialize<1, 0, 1, &basecontrol_chars>;
|
||||
deserialize = generic_port_deserialize<1, 0, 1>;
|
||||
legal = generic_port_legal<0>;
|
||||
legal = generic_port_legal<1>;
|
||||
controller_info = &simple_port;
|
||||
construct_map = invalid_construct_map;
|
||||
used_indices = generic_used_indices<1, 1>;
|
||||
set_core_controller = set_core_controller_illegal;
|
||||
}
|
||||
static port_type& get()
|
||||
{
|
||||
|
@ -82,128 +34,16 @@ namespace
|
|||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
struct pending_registration
|
||||
{
|
||||
port_type_group* group;
|
||||
std::string name;
|
||||
port_type* toreg;
|
||||
};
|
||||
|
||||
globalwrap<mutex_class> reg_mutex;
|
||||
globalwrap<std::set<port_type_group*>> ready_groups;
|
||||
globalwrap<std::list<pending_registration>> pending_registrations;
|
||||
|
||||
void run_pending_registrations()
|
||||
{
|
||||
umutex_class m(reg_mutex());
|
||||
auto i = pending_registrations().begin();
|
||||
while(i != pending_registrations().end()) {
|
||||
auto entry = i++;
|
||||
if(ready_groups().count(entry->group)) {
|
||||
entry->group->register_type(entry->name, *entry->toreg);
|
||||
pending_registrations().erase(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void add_registration(port_type_group& group, const std::string& name, port_type& type)
|
||||
{
|
||||
{
|
||||
umutex_class m(reg_mutex());
|
||||
pending_registration p;
|
||||
p.group = &group;
|
||||
p.name = name;
|
||||
p.toreg = &type;
|
||||
pending_registrations().push_back(p);
|
||||
}
|
||||
run_pending_registrations();
|
||||
}
|
||||
|
||||
void delete_registration(port_type_group& group, const std::string& name)
|
||||
{
|
||||
{
|
||||
umutex_class m(reg_mutex());
|
||||
if(ready_groups().count(&group))
|
||||
group.unregister_type(name);
|
||||
else {
|
||||
auto i = pending_registrations().begin();
|
||||
while(i != pending_registrations().end()) {
|
||||
auto entry = i++;
|
||||
if(entry->group == &group && entry->name == name)
|
||||
pending_registrations().erase(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
port_type_group::port_type_group() throw(std::bad_alloc)
|
||||
{
|
||||
{
|
||||
umutex_class m(reg_mutex());
|
||||
ready_groups().insert(this);
|
||||
}
|
||||
run_pending_registrations();
|
||||
}
|
||||
|
||||
port_type_group::~port_type_group() throw()
|
||||
{
|
||||
{
|
||||
umutex_class m(reg_mutex());
|
||||
ready_groups().erase(this);
|
||||
}
|
||||
}
|
||||
|
||||
port_type& port_type_group::get_type(const std::string& name) const throw(std::runtime_error)
|
||||
{
|
||||
if(types.count(name))
|
||||
return *(types.find(name)->second);
|
||||
else
|
||||
throw std::runtime_error("Unknown port type");
|
||||
}
|
||||
|
||||
port_type& port_type_group::get_default_type(unsigned port) const throw(std::runtime_error)
|
||||
{
|
||||
if(defaults.count(port))
|
||||
return *(defaults.find(port)->second);
|
||||
else
|
||||
throw std::runtime_error("No default for this port");
|
||||
}
|
||||
|
||||
std::set<port_type*> port_type_group::get_types() const throw(std::bad_alloc)
|
||||
{
|
||||
std::set<port_type*> p;
|
||||
for(auto i : types)
|
||||
p.insert(i.second);
|
||||
return p;
|
||||
}
|
||||
|
||||
void port_type_group::set_default(unsigned port, port_type& ptype)
|
||||
{
|
||||
defaults[port] = &ptype;
|
||||
}
|
||||
|
||||
void port_type_group::register_type(const std::string& type, port_type& port)
|
||||
{
|
||||
types[type] = &port;
|
||||
}
|
||||
|
||||
void port_type_group::unregister_type(const std::string& type)
|
||||
{
|
||||
types.erase(type);
|
||||
}
|
||||
|
||||
port_type::port_type(port_type_group& group, const std::string& iname, const std::string& _hname, unsigned id,
|
||||
port_type::port_type(const std::string& iname, const std::string& _hname, unsigned id,
|
||||
size_t ssize) throw(std::bad_alloc)
|
||||
: ingroup(group), name(iname), hname(_hname), pt_id(id), storage_size(ssize)
|
||||
: name(iname), hname(_hname), pt_id(id), storage_size(ssize)
|
||||
{
|
||||
add_registration(ingroup, name, *this);
|
||||
}
|
||||
|
||||
port_type::~port_type() throw()
|
||||
{
|
||||
delete_registration(ingroup, name);
|
||||
}
|
||||
|
||||
bool port_type::is_present(unsigned controller) const throw()
|
||||
|
@ -257,13 +97,14 @@ port_type_set::port_type_set() throw()
|
|||
indices_tab = &dummy_index;
|
||||
}
|
||||
|
||||
port_type_set& port_type_set::make(std::vector<class port_type*> types) throw(std::bad_alloc, std::runtime_error)
|
||||
port_type_set& port_type_set::make(std::vector<class port_type*> types, struct port_index_map control_map)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
for(auto i : bindings())
|
||||
if(i.matches(types))
|
||||
return *(i.stype);
|
||||
//Not found, create new.
|
||||
port_type_set& ret = *new port_type_set(types);
|
||||
port_type_set& ret = *new port_type_set(types, control_map);
|
||||
binding b;
|
||||
b.types = types;
|
||||
b.stype = &ret;
|
||||
|
@ -271,12 +112,12 @@ port_type_set& port_type_set::make(std::vector<class port_type*> types) throw(st
|
|||
return ret;
|
||||
}
|
||||
|
||||
port_type_set::port_type_set(std::vector<class port_type*> types)
|
||||
port_type_set::port_type_set(std::vector<class port_type*> types, struct port_index_map control_map)
|
||||
{
|
||||
port_count = types.size();
|
||||
//Verify legality of port types.
|
||||
for(size_t i = 0; i < port_count; i++)
|
||||
if(!types[i] || (i > 0 && !types[i]->legal(i - 1)))
|
||||
if(!types[i] || !types[i]->legal(i))
|
||||
throw std::runtime_error("Illegal port types");
|
||||
//Count maximum number of controller indices to determine the controller multiplier.
|
||||
controller_multiplier = 1;
|
||||
|
@ -288,8 +129,6 @@ port_type_set::port_type_set(std::vector<class port_type*> types)
|
|||
for(size_t i = 0; i < port_count; i++)
|
||||
port_multiplier = max(port_multiplier, controller_multiplier *
|
||||
(size_t)types[i]->controller_info->controller_count);
|
||||
//Query core about maps.
|
||||
struct port_index_map control_map = types[0]->construct_map(types);
|
||||
//Allocate the per-port tables.
|
||||
port_offsets = new size_t[types.size()];
|
||||
port_types = new class port_type*[types.size()];
|
||||
|
@ -351,12 +190,6 @@ short read_axis_value(const char* buf, size_t& idx) throw()
|
|||
return static_cast<short>(numval);
|
||||
}
|
||||
|
||||
port_type& get_dummy_port_type() throw(std::bad_alloc)
|
||||
{
|
||||
static porttype_invalid inv;
|
||||
return inv;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
port_type_set& dummytypes()
|
||||
|
|
|
@ -388,6 +388,7 @@ private:
|
|||
bool settings_mode;
|
||||
std::string c_rom;
|
||||
std::string c_file;
|
||||
std::map<std::string, std::string> c_settings;
|
||||
};
|
||||
|
||||
IMPLEMENT_APP(lsnes_app)
|
||||
|
@ -416,6 +417,8 @@ bool lsnes_app::OnCmdLineParsed(wxCmdLineParser& parser)
|
|||
c_rom = r[1];
|
||||
if(r = regex("--load=(.+)", i))
|
||||
c_file = r[1];
|
||||
if(r = regex("--set=([^=]+)=(.+)", i))
|
||||
c_settings[r[1]] = r[2];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,12 +442,12 @@ bool lsnes_app::OnInit()
|
|||
messages << "BSNES version: " << bsnes_core_version << std::endl;
|
||||
messages << "lsnes version: lsnes rr" << lsnes_version << std::endl;
|
||||
|
||||
std::vector<class port_type*> pt;
|
||||
for(unsigned i = 0; i <= core_userports; i++)
|
||||
pt.push_back(&core_portgroup.get_default_type(i));
|
||||
port_type_set* pset = &port_type_set::make(pt);
|
||||
loaded_rom dummy_rom;
|
||||
std::map<std::string, std::string> settings;
|
||||
auto ctrldata = dummy_rom.rtype->controllerconfig(settings);
|
||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex);
|
||||
|
||||
controls.set_ports(*pset, false);
|
||||
controls.set_ports(ports);
|
||||
|
||||
std::string cfgpath = get_config_path();
|
||||
messages << "Saving per-user data to: " << get_config_path() << std::endl;
|
||||
|
@ -480,7 +483,7 @@ bool lsnes_app::OnInit()
|
|||
try {
|
||||
moviefile mov;
|
||||
rom = new loaded_rom(c_rom);
|
||||
rom->load(mov.movie_rtc_second, mov.movie_rtc_subsecond);
|
||||
rom->load(c_settings, mov.movie_rtc_second, mov.movie_rtc_subsecond);
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "Can't load ROM: " << e.what() << std::endl;
|
||||
return false;
|
||||
|
@ -492,15 +495,17 @@ bool lsnes_app::OnInit()
|
|||
try {
|
||||
mov = new moviefile(c_file);
|
||||
if(c_rom != "")
|
||||
rom->load(mov->movie_rtc_second, mov->movie_rtc_subsecond);
|
||||
rom->load(mov->settings, mov->movie_rtc_second, mov->movie_rtc_subsecond);
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "Can't load state: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
mov = new moviefile;
|
||||
mov->ports = pset;
|
||||
mov->input.clear(*mov->ports);
|
||||
mov->settings = c_settings;
|
||||
auto ctrldata = rom->rtype->controllerconfig(mov->settings);
|
||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex);
|
||||
mov->input.clear(ports);
|
||||
if(c_rom != "") {
|
||||
//Initialize the remainder.
|
||||
mov->coreversion = bsnes_core_version;
|
||||
|
@ -510,8 +515,8 @@ bool lsnes_app::OnInit()
|
|||
mov->romimg_sha256[i] = rom->romimg[i].sha_256;
|
||||
mov->romxml_sha256[i] = rom->romxml[i].sha_256;
|
||||
}
|
||||
mov->gametype = &rom->rtype->combine_region(*rom->region);
|
||||
}
|
||||
mov->gametype = &rom->rtype->combine_region(*rom->region);
|
||||
}
|
||||
mov->start_paused = true;
|
||||
boot_emulator(*rom, *mov);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "core/framerate.hpp"
|
||||
#include "core/settings.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "interface/setting.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include "library/zip.hpp"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
@ -32,118 +33,6 @@ void patching_done(struct loaded_rom& rom, wxWindow* modwin);
|
|||
|
||||
namespace
|
||||
{
|
||||
port_type& get_controller_type(const std::string& s)
|
||||
{
|
||||
auto types = core_portgroup.get_types();
|
||||
for(auto i : types)
|
||||
if(s == i->hname)
|
||||
return *i;
|
||||
return get_dummy_port_type();
|
||||
}
|
||||
|
||||
void load_cchoices(std::vector<wxString>& cc, unsigned port, unsigned& dfltidx)
|
||||
{
|
||||
cc.clear();
|
||||
port_type& dflt = core_portgroup.get_default_type(port);
|
||||
dfltidx = 0;
|
||||
auto types = core_portgroup.get_types();
|
||||
for(auto i : types)
|
||||
if(i->legal && i->legal(port - 1)) {
|
||||
cc.push_back(towxstring(i->hname));
|
||||
if(i == &dflt)
|
||||
dfltidx = cc.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
struct loaded_slot& get_rom_slot(struct loaded_rom& rom, unsigned index)
|
||||
{
|
||||
if(index >= 2 * sizeof(rom.romimg) / sizeof(rom.romimg[0]))
|
||||
return rom.romimg[0];
|
||||
if(index & 1)
|
||||
return rom.romxml[index / 2];
|
||||
else
|
||||
return rom.romimg[index / 2];
|
||||
}
|
||||
|
||||
core_region& region_from_string(core_type& rtype, const std::string& str)
|
||||
{
|
||||
core_region* x = NULL;
|
||||
for(auto i : rtype.get_regions())
|
||||
if(i->get_hname() == str)
|
||||
return *i;
|
||||
return *x;
|
||||
}
|
||||
|
||||
unsigned populate_region_choices(std::vector<wxString>& array)
|
||||
{
|
||||
array.push_back(wxT("(Default)"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned populate_system_choices(std::vector<wxString>& array)
|
||||
{
|
||||
for(auto i : core_type::get_core_types())
|
||||
array.push_back(towxstring(i->get_hname()));
|
||||
return array.size();
|
||||
}
|
||||
|
||||
bool check_present_roms(core_type& rtype, unsigned flags)
|
||||
{
|
||||
unsigned a = 0;
|
||||
unsigned b = 0;
|
||||
for(size_t i = 0; i < ROMSELECT_ROM_COUNT && i < rtype.get_image_count(); i++) {
|
||||
if((flags >> i) & 1)
|
||||
a |= rtype.get_image_info(i).mandatory;
|
||||
b |= rtype.get_image_info(i).mandatory;
|
||||
}
|
||||
return (a == b);
|
||||
}
|
||||
|
||||
std::string romname(core_type& rtype, unsigned index)
|
||||
{
|
||||
if(index >= rtype.get_image_count())
|
||||
return "";
|
||||
return rtype.get_image_info(index).hname;
|
||||
}
|
||||
|
||||
unsigned romname_to_index(core_type& rtype, const wxString& _name)
|
||||
{
|
||||
std::string name = tostdstring(_name);
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++) {
|
||||
if(romname(rtype, i) == name)
|
||||
return 2 * i;
|
||||
if(romname(rtype, i) + MARKUP_POSTFIX == name)
|
||||
return 2 * i + 1;
|
||||
}
|
||||
return 2 * ROMSELECT_ROM_COUNT;
|
||||
}
|
||||
|
||||
unsigned fill_rom_names(core_type& rtype, std::string* array)
|
||||
{
|
||||
unsigned r = 0;
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++) {
|
||||
std::string s = romname(rtype, i);
|
||||
if(s.length())
|
||||
array[r++] = s;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
core_type& romtype_from_string(const std::string& str)
|
||||
{
|
||||
core_type* x = NULL;
|
||||
for(auto i : core_type::get_core_types())
|
||||
if(i->get_hname() == str)
|
||||
return *i;
|
||||
return *x;
|
||||
}
|
||||
|
||||
bool has_forced_region(const std::string& str)
|
||||
{
|
||||
core_type& rtype = romtype_from_string(str);
|
||||
return (rtype.get_regions().size() == 1);
|
||||
}
|
||||
|
||||
class textboxloadfilename : public wxFileDropTarget
|
||||
{
|
||||
public:
|
||||
|
@ -162,6 +51,64 @@ namespace
|
|||
private:
|
||||
wxTextCtrl* ctrl;
|
||||
};
|
||||
|
||||
struct setting_select
|
||||
{
|
||||
setting_select() {}
|
||||
setting_select(wxWindow* parent, const core_setting& s);
|
||||
wxWindow* get_label() { return label; }
|
||||
wxWindow* get_control();
|
||||
const core_setting* get_setting() { return setting; }
|
||||
std::string read();
|
||||
private:
|
||||
wxStaticText* label;
|
||||
wxTextCtrl* text;
|
||||
wxCheckBox* check;
|
||||
wxComboBox* combo;
|
||||
const core_setting* setting;
|
||||
};
|
||||
|
||||
setting_select::setting_select(wxWindow* parent, const core_setting& s)
|
||||
: setting(&s)
|
||||
{
|
||||
label = new wxStaticText(parent, wxID_ANY, towxstring(setting->hname));
|
||||
text = NULL;
|
||||
combo = NULL;
|
||||
check = NULL;
|
||||
if(setting->is_boolean()) {
|
||||
check = new wxCheckBox(parent, wxID_ANY, towxstring(""));
|
||||
check->SetValue(s.dflt != "0");
|
||||
} else if(setting->is_freetext()) {
|
||||
text = new wxTextCtrl(parent, wxID_ANY, towxstring(setting->dflt), wxDefaultPosition,
|
||||
wxSize(400, -1));
|
||||
} else {
|
||||
std::vector<wxString> _hvalues;
|
||||
std::string dflt = "";
|
||||
for(auto i : setting->values) {
|
||||
_hvalues.push_back(towxstring(i->hname));
|
||||
if(i->iname == setting->dflt)
|
||||
dflt = i->hname;
|
||||
}
|
||||
combo = new wxComboBox(parent, wxID_ANY, towxstring(dflt), wxDefaultPosition,
|
||||
wxDefaultSize, _hvalues.size(), &_hvalues[0], wxCB_READONLY);
|
||||
}
|
||||
}
|
||||
|
||||
wxWindow* setting_select::get_control()
|
||||
{
|
||||
if(text) return text;
|
||||
if(check) return check;
|
||||
if(combo) return combo;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string setting_select::read()
|
||||
{
|
||||
if(text) return tostdstring(text->GetValue());
|
||||
if(check) return check->GetValue() ? "1" : "0";
|
||||
if(combo) return setting->hvalue_to_ivalue(tostdstring(combo->GetValue()));
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
class wxwin_project : public wxDialog
|
||||
|
@ -179,7 +126,7 @@ private:
|
|||
struct moviefile make_movie();
|
||||
std::map<std::string, wxTextCtrl*> sram_files;
|
||||
std::map<std::string, wxButton*> sram_choosers;
|
||||
wxComboBox** controllertypes;
|
||||
std::map<std::string, setting_select> settings;
|
||||
wxTextCtrl* projectname;
|
||||
wxTextCtrl* prefix;
|
||||
wxTextCtrl* rtc_sec;
|
||||
|
@ -230,14 +177,12 @@ wxwin_project::wxwin_project()
|
|||
wxFlexGridSizer* new_sizer = new wxFlexGridSizer(3, 1, 0, 0);
|
||||
new_panel->SetSizer(new_sizer);
|
||||
//Controllertypes/Gamename/initRTC/SRAMs.
|
||||
wxFlexGridSizer* mainblock = new wxFlexGridSizer(4 + core_userports + sram_set.size(), 2, 0, 0);
|
||||
controllertypes = new wxComboBox*[core_userports];
|
||||
for(unsigned i = 1; i <= core_userports; i++) {
|
||||
mainblock->Add(new wxStaticText(new_panel, wxID_ANY, towxstring((stringfmt() << "Controller " << i
|
||||
<< " Type:").str())), 0, wxGROW);
|
||||
load_cchoices(cchoices, i, dfltidx);
|
||||
mainblock->Add(controllertypes[i - 1] = new wxComboBox(new_panel, wxID_ANY, cchoices[dfltidx],
|
||||
wxDefaultPosition, wxDefaultSize, cchoices.size(), &cchoices[0], wxCB_READONLY), 0, wxGROW);
|
||||
wxFlexGridSizer* mainblock = new wxFlexGridSizer(4 + our_rom->rtype->get_settings().settings.size() +
|
||||
sram_set.size(), 2, 0, 0);
|
||||
for(auto i : our_rom->rtype->get_settings().settings) {
|
||||
settings[i.second->iname] = setting_select(new_panel, *i.second);
|
||||
mainblock->Add(settings[i.second->iname].get_label());
|
||||
mainblock->Add(settings[i.second->iname].get_control());
|
||||
}
|
||||
mainblock->Add(new wxStaticText(new_panel, wxID_ANY, wxT("Initial RTC value:")), 0, wxGROW);
|
||||
wxFlexGridSizer* initrtc = new wxFlexGridSizer(1, 3, 0, 0);
|
||||
|
@ -367,11 +312,11 @@ struct moviefile wxwin_project::make_movie()
|
|||
moviefile f;
|
||||
f.force_corrupt = false;
|
||||
f.gametype = &our_rom->rtype->combine_region(*our_rom->region);
|
||||
std::vector<class port_type*> pt;
|
||||
pt.push_back(&core_portgroup.get_default_type(0));
|
||||
for(unsigned i = 1; i <= core_userports; i++)
|
||||
pt.push_back(&get_controller_type(tostdstring(controllertypes[i - 1]->GetValue())));
|
||||
f.ports = &port_type_set::make(pt);
|
||||
for(auto i : settings) {
|
||||
f.settings[i.first] = i.second.read();
|
||||
if(!i.second.get_setting()->validate(f.settings[i.first]))
|
||||
throw std::runtime_error((stringfmt() << "Bad value for setting " << i.first).str());
|
||||
}
|
||||
f.coreversion = bsnes_core_version;
|
||||
f.gamename = tostdstring(projectname->GetValue());
|
||||
f.prefix = sanitize_prefix(tostdstring(prefix->GetValue()));
|
||||
|
@ -402,7 +347,9 @@ struct moviefile wxwin_project::make_movie()
|
|||
f.movie_rtc_subsecond = f.rtc_subsecond = boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue()));
|
||||
if(f.movie_rtc_subsecond < 0)
|
||||
throw std::runtime_error("RTC subsecond must be positive");
|
||||
f.input.clear(*f.ports);
|
||||
auto ctrldata = our_rom->rtype->controllerconfig(f.settings);
|
||||
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex);
|
||||
f.input.clear(ports);
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
|
@ -269,8 +269,9 @@ int main(int argc, char** argv)
|
|||
messages << "--- Loading ROM ---" << std::endl;
|
||||
struct loaded_rom r;
|
||||
try {
|
||||
std::map<std::string, std::string> tmp;
|
||||
r = load_rom_from_commandline(cmdline);
|
||||
r.load(1000000000, 0);
|
||||
r.load(tmp, 1000000000, 0);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
|
@ -308,7 +309,7 @@ int main(int argc, char** argv)
|
|||
//Load ROM before starting the dumper.
|
||||
our_rom = &r;
|
||||
our_rom->region = &movie.gametype->get_region();
|
||||
our_rom->load(movie.movie_rtc_second, movie.movie_rtc_subsecond);
|
||||
our_rom->load(movie.settings, movie.movie_rtc_second, movie.movie_rtc_subsecond);
|
||||
startup_lua_scripts(cmdline);
|
||||
dumper_startup(dumper, mode, prefix, length);
|
||||
main_loop(r, movie, true);
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
#include "core/moviefile.hpp"
|
||||
#include "core/rrdata.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
std::string name_subrom(core_type& major, unsigned romnumber) throw(std::bad_alloc)
|
||||
{
|
||||
std::string name = "UNKNOWN";
|
||||
if(romnumber < 2 * major.get_image_count())
|
||||
name = major.get_image_info(romnumber / 2).hname;
|
||||
if(romnumber % 2)
|
||||
return name + " XML";
|
||||
else if(name != "ROM")
|
||||
return name + " ROM";
|
||||
else
|
||||
return "ROM";
|
||||
}
|
||||
|
||||
std::string escape_string(std::string x)
|
||||
{
|
||||
std::ostringstream out;
|
||||
for(size_t i = 0; i < x.length(); i++)
|
||||
if((x[i] < 0 || x[i] > 31) && x[i] != '\\')
|
||||
out << x[i];
|
||||
else {
|
||||
unsigned char y = static_cast<unsigned char>(x[i]);
|
||||
out << "\\" << ('0' + static_cast<char>((y >> 6) & 7))
|
||||
<< ('0' + static_cast<char>((y >> 3) & 7))
|
||||
<< ('0' + static_cast<char>(y & 7));
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
reached_main();
|
||||
if(argc != 2) {
|
||||
std::cerr << "Syntax: " << argv[0] << " <moviefile>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
uint64_t starting_point = 0;
|
||||
struct moviefile m(argv[1]);
|
||||
core_type* rtype = &m.gametype->get_type();
|
||||
core_region* reg = &m.gametype->get_region();
|
||||
std::cout << "Console: " << rtype->get_hname() << std::endl;
|
||||
std::cout << "Region: " << reg->get_hname() << std::endl;
|
||||
for(unsigned i = 0; i < m.ports->ports(); i++)
|
||||
std::cout << "Port #" << i << ": " << m.ports->port_type(i).hname << std::endl;
|
||||
std::cout << "Used emulator core: " << escape_string(m.coreversion) << std::endl;
|
||||
if(m.gamename != "")
|
||||
std::cout << "Game name: " << escape_string(m.gamename) << std::endl;
|
||||
else
|
||||
std::cout << "No game name available" << std::endl;
|
||||
std::cout << "Project ID: " << escape_string(m.projectid) << std::endl;
|
||||
for(size_t i = 0; i < sizeof(m.romimg_sha256)/sizeof(m.romimg_sha256[0]); i++) {
|
||||
if(m.romimg_sha256[i] != "") {
|
||||
std::cout << name_subrom(*rtype, 2 * i + 0) << " checksum: "
|
||||
<< escape_string(m.romimg_sha256[i]) << std::endl;
|
||||
if(m.romxml_sha256[i] != "") {
|
||||
std::cout << name_subrom(*rtype, 2 * i + 1) << " checksum: "
|
||||
<< escape_string(m.romimg_sha256[i]) << std::endl;
|
||||
}
|
||||
} else
|
||||
std::cout << "No " << name_subrom(*rtype, 2 * i + 0) << " present" << std::endl;
|
||||
}
|
||||
for(auto i = m.authors.begin(); i != m.authors.end(); i++) {
|
||||
if(i->first != "" && i->second != "")
|
||||
std::cout << "Author: " << escape_string(i->first) << " (" << escape_string(i->second)
|
||||
<< ")" << std::endl;
|
||||
else if(i->first != "" && i->second == "")
|
||||
std::cout << "Author: " << escape_string(i->first) << std::endl;
|
||||
else if(i->first == "" && i->second != "")
|
||||
std::cout << "Author: (" << escape_string(i->second) << ")" << std::endl;
|
||||
}
|
||||
if(m.authors.size() == 0)
|
||||
std::cout << "No author info available" << std::endl;
|
||||
if(m.is_savestate) {
|
||||
std::cout << "Movie starts from savestate" << std::endl;
|
||||
for(auto i = m.movie_sram.begin(); i != m.movie_sram.end(); i++)
|
||||
std::cout << "Start SRAM: " << escape_string(i->first) << ": [" << i->second.size()
|
||||
<< " bytes of binary data]" << std::endl;
|
||||
if(!m.movie_sram.size())
|
||||
std::cout << "No starting SRAM" << std::endl;
|
||||
for(auto i = m.sram.begin(); i != m.sram.end(); i++)
|
||||
std::cout << "Saved SRAM: " << escape_string(i->first) << ": [" << i->second.size()
|
||||
<< " bytes of binary data]" << std::endl;
|
||||
if(!m.sram.size())
|
||||
std::cout << "No saved SRAM" << std::endl;
|
||||
std::cout << "Savestate: [" << m.savestate.size() << " bytes of binary data]" << std::endl;
|
||||
std::cout << "Host memory: [" << m.host_memory.size() << " bytes of binary data]"
|
||||
<< std::endl;
|
||||
std::cout << "Screenshot: [" << m.screenshot.size() << " bytes of binary data]" << std::endl;
|
||||
if(m.screenshot.size() >= 4) {
|
||||
uint16_t a = static_cast<uint8_t>(m.screenshot[0]);
|
||||
uint16_t b = static_cast<uint8_t>(m.screenshot[1]);
|
||||
std::cout << "Screenshot size: " << (a * 256 + b) << "*" << (m.screenshot.size() - 2)
|
||||
/ (a * 256 + b) / 3 << std::endl;
|
||||
} else
|
||||
std::cout << "Screenshot is corrupt" << std::endl;
|
||||
starting_point = m.save_frame;
|
||||
std::cout << "Starting frame: " << starting_point << std::endl;
|
||||
std::cout << "Lag frames so far: " << m.lagged_frames << std::endl;
|
||||
} else if(m.movie_sram.size() > 0) {
|
||||
std::cout << "Movie starts from SRAM" << std::endl;
|
||||
for(auto i = m.movie_sram.begin(); i != m.movie_sram.end(); i++)
|
||||
std::cout << "Start SRAM: " << escape_string(i->first) << " (" << i->second.size()
|
||||
<< " bytes)" << std::endl;
|
||||
} else
|
||||
std::cout << "Movie starts from clean state" << std::endl;
|
||||
std::cout << "Movie frame count: " << m.get_frame_count() << std::endl;
|
||||
uint64_t length = m.get_movie_length();
|
||||
{
|
||||
std::ostringstream x;
|
||||
if(length >= 3600000000000ULL) {
|
||||
x << (length / 3600000000000ULL) << ":";
|
||||
length %= 3600000000000ULL;
|
||||
}
|
||||
x << std::setw(2) << std::setfill('0') << (length / 60000000000ULL) << ":";
|
||||
length %= 60000000000ULL;
|
||||
x << std::setw(2) << std::setfill('0') << (length / 1000000000ULL) << ".";
|
||||
length %= 1000000000ULL;
|
||||
x << std::setw(3) << std::setfill('0') << (length + 500000) / 1000000;
|
||||
std::cout << "Movie length: " << x.str() << std::endl;
|
||||
}
|
||||
std::cout << "Rerecord count: " << rrdata::count(m.c_rrdata) << std::endl;
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "ERROR: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue