Revamp ROM loading
This commit is contained in:
parent
d1210efe03
commit
e83e4eb4e1
17 changed files with 450 additions and 1050 deletions
|
@ -156,6 +156,10 @@ struct moviefile
|
|||
* Start paused flag.
|
||||
*/
|
||||
bool start_paused;
|
||||
/**
|
||||
* Lazy project create flag.
|
||||
*/
|
||||
bool lazy_project_create;
|
||||
/**
|
||||
* Get number of frames in movie.
|
||||
*
|
||||
|
|
|
@ -8,57 +8,6 @@
|
|||
#include "core/misc.hpp"
|
||||
#include "core/romtype.hpp"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This structure gives all files associated with given ROM image.
|
||||
*/
|
||||
struct rom_files
|
||||
{
|
||||
/**
|
||||
* Construct defaults
|
||||
*/
|
||||
rom_files() throw();
|
||||
|
||||
/**
|
||||
* Reads the filenames out of command line arguments given.
|
||||
*
|
||||
* parameter cmdline: The commmand line
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
* throws std::runtime_error: Failed to load ROM filenames.
|
||||
*/
|
||||
rom_files(const std::vector<std::string>& cmdline) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Resolve relative references.
|
||||
*
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
* throws std::runtime_error: Bad path.
|
||||
*/
|
||||
void resolve_relative() throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* The file to look other ROM files relative to. May be blank.
|
||||
*/
|
||||
std::string base_file;
|
||||
/**
|
||||
* Major ROM type.
|
||||
*/
|
||||
core_type* rtype;
|
||||
/**
|
||||
* Game region (the region ROM is to be loaded as)
|
||||
*/
|
||||
core_region* region;
|
||||
/**
|
||||
* Relative filename of main ROM file.
|
||||
*/
|
||||
std::string romimg[27];
|
||||
/**
|
||||
* Relative filename of main ROM XML file.
|
||||
*/
|
||||
std::string romxml[27];
|
||||
};
|
||||
|
||||
/**
|
||||
* Some loaded data or indication of no data.
|
||||
*/
|
||||
|
@ -76,12 +25,13 @@ struct loaded_slot
|
|||
*
|
||||
* parameter filename: The filename to read. If "", empty slot is constructed.
|
||||
* parameter base: Base filename to interpret the filename against. If "", no base filename is used.
|
||||
* parameter imginfo: Image information.
|
||||
* parameter xml_flag: If set, always keep trailing NUL.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Can't load the data.
|
||||
*/
|
||||
loaded_slot(const std::string& filename, const std::string& base, bool xml_flag = false)
|
||||
throw(std::bad_alloc, std::runtime_error);
|
||||
loaded_slot(const std::string& filename, const std::string& base, const struct core_romimage_info& imginfo,
|
||||
bool xml_flag = false) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* This method patches this slot using specified IPS patch.
|
||||
|
@ -149,13 +99,13 @@ struct loaded_rom
|
|||
*/
|
||||
loaded_rom() throw();
|
||||
/**
|
||||
* Takes in collection of ROM filenames and loads them into memory.
|
||||
* Take in ROM filename (or a bundle) and load it to memory.
|
||||
*
|
||||
* parameter files: The files to load
|
||||
* parameter file: The file to load
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Loading ROM files failed.
|
||||
* throws std::runtime_error: Loading ROM file failed.
|
||||
*/
|
||||
loaded_rom(const rom_files& files) throw(std::bad_alloc, std::runtime_error);
|
||||
loaded_rom(const std::string& file) throw(std::bad_alloc, std::runtime_error);
|
||||
/**
|
||||
* ROM type
|
||||
*/
|
||||
|
@ -181,14 +131,9 @@ struct loaded_rom
|
|||
*/
|
||||
std::string msu1_base;
|
||||
/**
|
||||
* Patch the ROM.
|
||||
*
|
||||
* parameter cmdline: The command line.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Failed to patch the ROM.
|
||||
* Load filename.
|
||||
*/
|
||||
void do_patch(const std::vector<std::string>& cmdline) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
std::string load_filename;
|
||||
/**
|
||||
* Switches the active cartridge to this cartridge. The compatiblity between selected region and original region
|
||||
* is checked. Region is updated after cartridge has been loaded.
|
||||
|
@ -199,16 +144,6 @@ struct loaded_rom
|
|||
void load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_alloc, std::runtime_error);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Name a sub-ROM.
|
||||
*
|
||||
* parameter major: The major type.
|
||||
* parameter romnumber: ROM number to name (as returned by recognize_commandline_rom).
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
*/
|
||||
std::string name_subrom(core_type& major, unsigned romnumber) throw(std::bad_alloc);
|
||||
|
||||
/**
|
||||
* Get major type and region of loaded ROM.
|
||||
*
|
||||
|
@ -259,23 +194,4 @@ std::vector<char> save_core_state(bool nochecksum = false) throw(std::bad_alloc)
|
|||
*/
|
||||
void load_core_state(const std::vector<char>& buf, bool nochecksum = false) throw(std::runtime_error);
|
||||
|
||||
/**
|
||||
* Read index of ROMs and add ROMs found to content-searchable storage.
|
||||
*
|
||||
* parameter filename: The filename of index file.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Loading index failed.
|
||||
*/
|
||||
void load_index_file(const std::string& filename) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
/**
|
||||
* Search all indices, looking for file with specified SHA-256 (specifying hash of "" results "").
|
||||
*
|
||||
* parameter hash: The hash of file.
|
||||
* returns: Absolute filename.
|
||||
* throws std::bad_alloc: Not enough memory.
|
||||
* throws std::runtime_error: Not found.
|
||||
*/
|
||||
std::string lookup_file_by_sha256(const std::string& hash) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,7 +57,7 @@ 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));
|
||||
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);
|
||||
|
@ -66,6 +66,8 @@ public:
|
|||
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);
|
||||
unsigned get_id();
|
||||
unsigned get_image_count();
|
||||
core_romimage_info get_image_info(unsigned index);
|
||||
|
@ -77,6 +79,7 @@ private:
|
|||
unsigned id;
|
||||
std::string iname;
|
||||
std::string hname;
|
||||
std::list<std::string> extensions;
|
||||
std::list<core_region*> regions;
|
||||
std::vector<core_romimage_info*> imageinfo;
|
||||
};
|
||||
|
|
|
@ -64,9 +64,10 @@ public:
|
|||
* Read the saved set of load IDs for specified project and switch to that project.
|
||||
*
|
||||
* parameter project: The name of project.
|
||||
* parameter lazy: If true, just switch to project, don't read the IDs.
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
*/
|
||||
static void read_base(const std::string& project) throw(std::bad_alloc);
|
||||
static void read_base(const std::string& project, bool lazy) throw(std::bad_alloc);
|
||||
/**
|
||||
* Switch to no project, closing the load IDs.
|
||||
*/
|
||||
|
|
|
@ -32,6 +32,7 @@ void initialize_wx_keyboard();
|
|||
void signal_program_exit();
|
||||
void signal_resize_needed();
|
||||
void _runuifun_async(void (*fn)(void*), void* arg);
|
||||
void show_projectwindow(wxWindow* modwin);
|
||||
|
||||
//Editor dialogs.
|
||||
void wxeditor_authors_display(wxWindow* parent);
|
||||
|
|
|
@ -55,6 +55,18 @@ const char* button_symbols = "BYsSudlrAXLRTSTCUP";
|
|||
|
||||
namespace
|
||||
{
|
||||
uint32_t norom_frame[512 * 448];
|
||||
|
||||
void init_norom_frame()
|
||||
{
|
||||
static bool done = false;
|
||||
if(done)
|
||||
return;
|
||||
done = true;
|
||||
for(size_t i = 0; i < 512 * 448; i++)
|
||||
norom_frame[i] = 0x7C21F;
|
||||
}
|
||||
|
||||
int regions_compatible(unsigned rom, unsigned run)
|
||||
{
|
||||
return (!rom || rom == run);
|
||||
|
@ -68,7 +80,7 @@ namespace
|
|||
return 0;
|
||||
}
|
||||
|
||||
core_type* internal_rom;
|
||||
core_type* internal_rom = NULL;
|
||||
extern core_type type_snes;
|
||||
extern core_type type_bsx;
|
||||
extern core_type type_bsxslotted;
|
||||
|
@ -144,11 +156,11 @@ namespace
|
|||
core_romimage_info image_stbios("rom", "ST BIOS", 1, header_fn);
|
||||
core_romimage_info image_stslota("slot-a", "ST Slot A ROM", 2, header_fn);
|
||||
core_romimage_info image_stslotb("slot-b", "ST Slot B ROM", 2, header_fn);
|
||||
core_type type_snes("snes", "SNES", 0, load_rom_snes);
|
||||
core_type type_bsx("bsx", "BS-X (non-slotted)", 1, load_rom_bsx);
|
||||
core_type type_bsxslotted("bsxslotted", "BS-X (slotted)", 2, load_rom_bsxslotted);
|
||||
core_type type_sufamiturbo("sufamiturbo", "Sufami Turbo", 3, load_rom_sufamiturbo);
|
||||
core_type type_sgb("sgb", "Super Game Boy", 4, load_rom_sgb);
|
||||
core_type type_snes("snes", "SNES", 0, load_rom_snes, "sfc;smc;swc;fig;ufo;sf2;gd3;gd7;dx2;mgd;mgh");
|
||||
core_type type_bsx("bsx", "BS-X (non-slotted)", 1, load_rom_bsx, "");
|
||||
core_type type_bsxslotted("bsxslotted", "BS-X (slotted)", 2, load_rom_bsxslotted, "");
|
||||
core_type type_sufamiturbo("sufamiturbo", "Sufami Turbo", 3, load_rom_sufamiturbo, "");
|
||||
core_type type_sgb("sgb", "Super Game Boy", 4, load_rom_sgb, "");
|
||||
core_type_region_bind bind_A(type_snes, region_auto);
|
||||
core_type_region_bind bind_B(type_snes, region_ntsc);
|
||||
core_type_region_bind bind_C(type_snes, region_pal);
|
||||
|
@ -664,6 +676,7 @@ namespace
|
|||
display = generic_port_display<1, 2, 4, 0>;
|
||||
serialize = generic_port_serialize<1, 2, 4, 14>;
|
||||
deserialize = generic_port_deserialize<1, 2, 4>;
|
||||
deviceflags = generic_port_deviceflags<1, 3>;
|
||||
legal = generic_port_legal<2>;
|
||||
ctrlname = "superscope";
|
||||
controllers = 1;
|
||||
|
@ -743,6 +756,8 @@ void do_basic_core_init()
|
|||
std::set<std::string> get_sram_set()
|
||||
{
|
||||
std::set<std::string> r;
|
||||
if(!internal_rom)
|
||||
return r;
|
||||
for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
|
||||
SNES::Cartridge::NonVolatileRAM& s = SNES::cartridge.nvram[i];
|
||||
r.insert(sram_name(s.id, s.slot));
|
||||
|
@ -766,18 +781,24 @@ core_region& core_get_region()
|
|||
|
||||
void core_power()
|
||||
{
|
||||
snes_power();
|
||||
if(internal_rom)
|
||||
snes_power();
|
||||
}
|
||||
|
||||
void core_unload_cartridge()
|
||||
{
|
||||
if(!internal_rom)
|
||||
return;
|
||||
snes_term();
|
||||
snes_unload_cartridge();
|
||||
internal_rom = NULL;
|
||||
}
|
||||
|
||||
//Get the current video rate.
|
||||
std::pair<uint32_t, uint32_t> get_video_rate()
|
||||
{
|
||||
if(!internal_rom)
|
||||
return std::make_pair(60, 1);
|
||||
uint32_t div;
|
||||
if(snes_get_region())
|
||||
div = last_interlace ? DURATION_PAL_FIELD : DURATION_PAL_FRAME;
|
||||
|
@ -789,12 +810,16 @@ std::pair<uint32_t, uint32_t> get_video_rate()
|
|||
//Get the current audio rate.
|
||||
std::pair<uint32_t, uint32_t> get_audio_rate()
|
||||
{
|
||||
if(!internal_rom)
|
||||
return std::make_pair(64081, 2);
|
||||
return std::make_pair(get_snes_apu_rate(), static_cast<uint32_t>(768));
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc)
|
||||
{
|
||||
std::map<std::string, std::vector<char>> out;
|
||||
if(!internal_rom)
|
||||
return out;
|
||||
for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
|
||||
SNES::Cartridge::NonVolatileRAM& r = SNES::cartridge.nvram[i];
|
||||
std::string savename = sram_name(r.id, r.slot);
|
||||
|
@ -809,6 +834,11 @@ std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc)
|
|||
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc)
|
||||
{
|
||||
std::set<std::string> used;
|
||||
if(!internal_rom) {
|
||||
for(auto i : sram)
|
||||
messages << "WARNING: SRAM '" << i.first << ": Not found on cartridge." << std::endl;
|
||||
return;
|
||||
}
|
||||
if(sram.empty())
|
||||
return;
|
||||
for(unsigned i = 0; i < SNES::cartridge.nvram.size(); i++) {
|
||||
|
@ -841,6 +871,8 @@ bool core_set_region(core_region& region)
|
|||
|
||||
void core_serialize(std::vector<char>& out)
|
||||
{
|
||||
if(!internal_rom)
|
||||
throw std::runtime_error("No ROM loaded");
|
||||
serializer s = SNES::system.serialize();
|
||||
out.resize(s.size());
|
||||
memcpy(&out[0], s.data(), s.size());
|
||||
|
@ -848,6 +880,8 @@ void core_serialize(std::vector<char>& out)
|
|||
|
||||
void core_unserialize(const char* in, size_t insize)
|
||||
{
|
||||
if(!internal_rom)
|
||||
throw std::runtime_error("No ROM loaded");
|
||||
serializer s(reinterpret_cast<const uint8_t*>(in), insize);
|
||||
if(!SNES::system.unserialize(s))
|
||||
throw std::runtime_error("SNES core rejected savestate");
|
||||
|
@ -855,34 +889,70 @@ void core_unserialize(const char* in, size_t insize)
|
|||
|
||||
std::pair<bool, uint32_t> core_emulate_cycles(uint32_t cycles)
|
||||
{
|
||||
#if defined(BSNES_V084) || defined(BSNES_V085)
|
||||
messages << "Executing delayed reset... This can take some time!" << std::endl;
|
||||
video_refresh_done = false;
|
||||
delayreset_cycles_run = 0;
|
||||
delayreset_cycles_target = cycles;
|
||||
SNES::cpu.step_event = delayreset_fn;
|
||||
SNES::system.run();
|
||||
SNES::cpu.step_event = nall::function<bool()>();
|
||||
return std::make_pair(!video_refresh_done, delayreset_cycles_run);
|
||||
#else
|
||||
messages << "Delayresets not supported on this bsnes version (needs v084 or v085)"
|
||||
<< std::endl;
|
||||
if(!internal_rom)
|
||||
return std::make_pair(false, 0);
|
||||
#if defined(BSNES_V084) || defined(BSNES_V085)
|
||||
messages << "Executing delayed reset... This can take some time!" << std::endl;
|
||||
video_refresh_done = false;
|
||||
delayreset_cycles_run = 0;
|
||||
delayreset_cycles_target = cycles;
|
||||
SNES::cpu.step_event = delayreset_fn;
|
||||
SNES::system.run();
|
||||
SNES::cpu.step_event = nall::function<bool()>();
|
||||
return std::make_pair(!video_refresh_done, delayreset_cycles_run);
|
||||
#else
|
||||
messages << "Delayresets not supported on this bsnes version (needs v084 or v085)"
|
||||
<< std::endl;
|
||||
return std::make_pair(false, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void core_emulate_frame()
|
||||
{
|
||||
static unsigned frame_modulus = 0;
|
||||
if(!internal_rom) {
|
||||
init_norom_frame();
|
||||
framebuffer_info inf;
|
||||
inf.type = &_pixel_format_lrgb;
|
||||
inf.mem = const_cast<char*>(reinterpret_cast<const char*>(norom_frame));
|
||||
inf.physwidth = 512;
|
||||
inf.physheight = 448;
|
||||
inf.physstride = 2048;
|
||||
inf.width = 512;
|
||||
inf.height = 448;
|
||||
inf.stride = 2048;
|
||||
inf.offset_x = 0;
|
||||
inf.offset_y = 0;
|
||||
|
||||
framebuffer_raw ls(inf);
|
||||
ecore_callbacks->output_frame(ls, 60, 1);
|
||||
|
||||
for(unsigned i = 0; i < 534; i++) {
|
||||
platform::audio_sample(32768, 32768);
|
||||
information_dispatch::do_sample(0, 0);
|
||||
}
|
||||
if(frame_modulus++ == 0) {
|
||||
platform::audio_sample(32768, 32768);
|
||||
information_dispatch::do_sample(0, 0);
|
||||
}
|
||||
frame_modulus %= 120;
|
||||
ecore_callbacks->timer_tick(1, 60);
|
||||
return;
|
||||
}
|
||||
SNES::system.run();
|
||||
}
|
||||
|
||||
void core_reset()
|
||||
{
|
||||
if(!internal_rom)
|
||||
return;
|
||||
SNES::system.reset();
|
||||
}
|
||||
|
||||
void core_runtosave()
|
||||
{
|
||||
if(!internal_rom)
|
||||
return;
|
||||
stepping_into_save = true;
|
||||
SNES::system.runtosave();
|
||||
stepping_into_save = false;
|
||||
|
|
|
@ -192,18 +192,19 @@ namespace
|
|||
{
|
||||
std::string filenam = filename;
|
||||
if(filenam == "")
|
||||
filenam = our_rom->msu1_base;
|
||||
filenam = our_rom->load_filename;
|
||||
if(filenam == "") {
|
||||
messages << "No ROM loaded" << std::endl;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
loaded_slot newrom(filenam, "");
|
||||
if(our_rom->romimg[1].sha256 != "")
|
||||
our_rom->romimg[1] = newrom;
|
||||
else
|
||||
our_rom->romimg[0] = newrom;
|
||||
our_rom->msu1_base = filenam;
|
||||
if(our_rom->romimg[1].sha256 != "")
|
||||
our_movie.romimg_sha256[1] = newrom.sha256;
|
||||
else
|
||||
our_movie.romimg_sha256[0] = newrom.sha256;
|
||||
messages << "Loading ROM " << filenam << std::endl;
|
||||
loaded_rom newrom(filenam);
|
||||
*our_rom = newrom;
|
||||
for(size_t i = 0; i < sizeof(our_rom->romimg)/sizeof(our_rom->romimg[0]); i++) {
|
||||
our_movie.romimg_sha256[i] = our_rom->romimg[i].sha256;
|
||||
our_movie.romxml_sha256[i] = our_rom->romxml[i].sha256;
|
||||
}
|
||||
} catch(std::exception& e) {
|
||||
messages << "Can't reload ROM: " << e.what() << std::endl;
|
||||
return false;
|
||||
|
@ -497,6 +498,12 @@ namespace
|
|||
mark_pending_load(args, LOAD_STATE_CURRENT);
|
||||
});
|
||||
|
||||
function_ptr_command<arg_filename> load_smart_c("load-smart", "Load savestate (heuristic mode)",
|
||||
"Syntax: load <file>\nLoads SNES state from <file> in heuristic mode\n",
|
||||
[](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
|
||||
mark_pending_load(args, LOAD_STATE_DEFAULT);
|
||||
});
|
||||
|
||||
function_ptr_command<arg_filename> load_state_c("load-state", "Load savestate (R/W)",
|
||||
"Syntax: load-state <file>\nLoads SNES state from <file> in Read/Write mode\n",
|
||||
[](arg_filename args) throw(std::bad_alloc, std::runtime_error) {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "core/threaddebug.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/sha256.hpp"
|
||||
#include "library/string.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
@ -97,27 +98,17 @@ void set_random_seed() throw(std::bad_alloc)
|
|||
struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
struct rom_files f;
|
||||
try {
|
||||
f = rom_files(cmdline);
|
||||
f.resolve_relative();
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error(std::string("Can't resolve ROM files: ") + e.what());
|
||||
}
|
||||
messages << "ROM type: " << f.rtype->get_hname() << " (" << f.region->get_hname() << ")" << std::endl;
|
||||
for(size_t i = 0; i < sizeof(f.romimg)/sizeof(f.romimg[0]); i++) {
|
||||
if(f.romimg[i] != "") messages << name_subrom(*f.rtype, 2 * i + 0) << " file: '" << f.romimg[i]
|
||||
<< "'" << std::endl;
|
||||
if(f.romxml[i] != "") messages << name_subrom(*f.rtype, 2 * i + 1) << " file: '" << f.romxml[i]
|
||||
<< "'" << std::endl;
|
||||
std::string f;
|
||||
regex_results optp;
|
||||
for(auto i : cmdline) {
|
||||
if(!(optp = regex("--rom=(.+)", i)))
|
||||
continue;
|
||||
f = optp[1];
|
||||
}
|
||||
|
||||
struct loaded_rom r;
|
||||
try {
|
||||
r = loaded_rom(f);
|
||||
r.do_patch(cmdline);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
|
@ -126,10 +117,15 @@ struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) th
|
|||
|
||||
std::string not_present = "N/A";
|
||||
for(size_t i = 0; i < sizeof(r.romimg)/sizeof(r.romimg[0]); i++) {
|
||||
if(r.romimg[i].valid) messages << name_subrom(*f.rtype, 2 * i + 0) << " hash: "
|
||||
<< r.romimg[i].sha256 << std::endl;
|
||||
if(r.romxml[i].valid) messages << name_subrom(*f.rtype, 2 * i + 1) << " hash: "
|
||||
<< r.romxml[i].sha256 << std::endl;
|
||||
std::string romname = "UNKNOWN ROM";
|
||||
std::string xmlname = "UNKNOWN XML";
|
||||
if(i < r.rtype->get_image_count()) {
|
||||
romname = (r.rtype->get_image_info(i).hname == "ROM") ? std::string("ROM") :
|
||||
(r.rtype->get_image_info(i).hname + " ROM");
|
||||
xmlname = r.rtype->get_image_info(i).hname + " XML";
|
||||
}
|
||||
if(r.romimg[i].valid) messages << romname << " hash: " << r.romimg[i].sha256 << std::endl;
|
||||
if(r.romxml[i].valid) messages << xmlname << " hash: " << r.romxml[i].sha256 << std::endl;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
|
@ -213,6 +213,10 @@ std::pair<std::string, std::string> split_author(const std::string& author) thro
|
|||
void do_save_state(const std::string& filename) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
if(!our_movie.gametype) {
|
||||
messages << "Can't save movie without a ROM" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string filename2 = translate_name_mprefix(filename, true);
|
||||
lua_callback_pre_save(filename2, true);
|
||||
try {
|
||||
|
@ -246,6 +250,10 @@ void do_save_state(const std::string& filename) throw(std::bad_alloc,
|
|||
//Save movie.
|
||||
void do_save_movie(const std::string& filename) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(!our_movie.gametype) {
|
||||
messages << "Can't save movie without a ROM" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string filename2 = translate_name_mprefix(filename, true);
|
||||
lua_callback_pre_save(filename2, false);
|
||||
try {
|
||||
|
@ -271,15 +279,27 @@ extern time_t random_seed_value;
|
|||
|
||||
void do_load_beginning(bool reload) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
if(!our_movie.gametype && !reload) {
|
||||
messages << "Can't load movie without a ROM" << std::endl;
|
||||
return;
|
||||
}
|
||||
set_preload_settings();
|
||||
|
||||
//Negative return.
|
||||
rrdata::add_internal();
|
||||
if(!reload) {
|
||||
//Force unlazy rrdata.
|
||||
rrdata::read_base(our_movie.projectid, false);
|
||||
rrdata::add_internal();
|
||||
}
|
||||
try {
|
||||
bool ro = movb.get_movie().readonly_mode();
|
||||
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_movie.gametype = &our_rom->rtype->combine_region(*our_rom->region);
|
||||
else
|
||||
our_movie.gametype = NULL;
|
||||
if(reload)
|
||||
movb.get_movie().readonly_mode(ro);
|
||||
|
||||
|
@ -313,12 +333,12 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
if(_movie.force_corrupt)
|
||||
throw std::runtime_error("Movie file invalid");
|
||||
bool will_load_state = _movie.is_savestate && lmode != LOAD_STATE_MOVIE;
|
||||
if(&(_movie.gametype->get_type()) != our_rom->rtype)
|
||||
if(our_rom->rtype && &(_movie.gametype->get_type()) != our_rom->rtype)
|
||||
throw std::runtime_error("ROM types of movie and loaded ROM don't match");
|
||||
if(!our_rom->orig_region->compatible_with(_movie.gametype->get_region()))
|
||||
if(our_rom->orig_region && !our_rom->orig_region->compatible_with(_movie.gametype->get_region()))
|
||||
throw std::runtime_error("NTSC/PAL select of movie and loaded ROM don't match");
|
||||
|
||||
if(_movie.coreversion != bsnes_core_version) {
|
||||
if(our_rom->rtype && _movie.coreversion != bsnes_core_version) {
|
||||
if(will_load_state) {
|
||||
std::ostringstream x;
|
||||
x << "ERROR: Emulator core version mismatch!" << std::endl
|
||||
|
@ -356,11 +376,11 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
(lmode == LOAD_STATE_PRESERVE) ? &_movie.input : NULL, _movie.projectid);
|
||||
|
||||
//Negative return.
|
||||
rrdata::read_base(_movie.projectid);
|
||||
rrdata::read_base(_movie.projectid, _movie.lazy_project_create);
|
||||
rrdata::read(_movie.c_rrdata);
|
||||
rrdata::add_internal();
|
||||
try {
|
||||
our_rom->region = &(_movie.gametype->get_region());
|
||||
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);
|
||||
|
||||
|
@ -410,13 +430,15 @@ void do_load_state(struct moviefile& _movie, int lmode)
|
|||
//Activate RW mode if needed.
|
||||
if(lmode == LOAD_STATE_RW)
|
||||
movb.get_movie().readonly_mode(false);
|
||||
if(lmode == LOAD_STATE_DEFAULT && movb.get_movie().get_frame_count() <= movb.get_movie().get_current_frame())
|
||||
if(lmode == LOAD_STATE_DEFAULT && !current_mode &&
|
||||
movb.get_movie().get_frame_count() <= movb.get_movie().get_current_frame())
|
||||
movb.get_movie().readonly_mode(false);
|
||||
if(lmode == LOAD_STATE_CURRENT && !current_mode)
|
||||
movb.get_movie().readonly_mode(false);
|
||||
information_dispatch::do_mode_change(movb.get_movie().readonly_mode());
|
||||
messages << "ROM Type " << our_rom->rtype->get_hname() << " region " << our_rom->region->get_hname()
|
||||
<< std::endl;
|
||||
if(our_rom->rtype)
|
||||
messages << "ROM Type " << our_rom->rtype->get_hname() << " region " << our_rom->region->get_hname()
|
||||
<< std::endl;
|
||||
uint64_t mlength = _movie.get_movie_length();
|
||||
{
|
||||
mlength += 999999;
|
||||
|
@ -473,6 +495,8 @@ bool do_load_state(const std::string& filename, int lmode)
|
|||
|
||||
void mainloop_restore_state(const std::vector<char>& state, uint64_t secs, uint64_t ssecs)
|
||||
{
|
||||
//Force unlazy rrdata.
|
||||
rrdata::read_base(our_movie.projectid, false);
|
||||
rrdata::add_internal();
|
||||
our_movie.rtc_second = secs;
|
||||
our_movie.rtc_subsecond = ssecs;
|
||||
|
|
|
@ -292,7 +292,6 @@ porttype_info& parse_controller_type(const std::string& type, unsigned port) thr
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
moviefile::moviefile() throw(std::bad_alloc)
|
||||
{
|
||||
force_corrupt = false;
|
||||
|
@ -306,6 +305,7 @@ moviefile::moviefile() throw(std::bad_alloc)
|
|||
movie_rtc_second = rtc_second = DEFAULT_RTC_SECOND;
|
||||
movie_rtc_subsecond = rtc_subsecond = DEFAULT_RTC_SUBSECOND;
|
||||
start_paused = false;
|
||||
lazy_project_create = true;
|
||||
}
|
||||
|
||||
moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtime_error)
|
||||
|
@ -313,6 +313,7 @@ moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtim
|
|||
start_paused = false;
|
||||
force_corrupt = false;
|
||||
is_savestate = false;
|
||||
lazy_project_create = false;
|
||||
std::string tmp;
|
||||
zip_reader r(movie);
|
||||
read_linefile(r, "systemid", tmp);
|
||||
|
@ -453,6 +454,9 @@ namespace
|
|||
uint64_t moviefile::get_movie_length() throw()
|
||||
{
|
||||
uint64_t frames = get_frame_count();
|
||||
if(!gametype) {
|
||||
return 100000000ULL * frames / 6;
|
||||
}
|
||||
uint64_t _magic[4];
|
||||
gametype->fill_framerate_magic(_magic);
|
||||
uint64_t t = _magic[BLOCK_SECONDS] * 1000000000ULL * (frames / _magic[BLOCK_FRAMES]);
|
||||
|
|
396
src/core/rom.cpp
396
src/core/rom.cpp
|
@ -28,109 +28,37 @@
|
|||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/device/back_inserter.hpp>
|
||||
|
||||
//Some anti-typo defs.
|
||||
#define SNES_TYPE "snes"
|
||||
#define SNES_PAL "snes_pal"
|
||||
#define SNES_NTSC "snes_ntsc"
|
||||
#define BSX "bsx"
|
||||
#define BSXSLOTTED "bsxslotted"
|
||||
#define SUFAMITURBO "sufamiturbo"
|
||||
#define SGB_TYPE "SGB"
|
||||
#define SGB_PAL "sgb_pal"
|
||||
#define SGB_NTSC "sgb_ntsc"
|
||||
|
||||
/**
|
||||
* Recognize the slot this ROM goes to.
|
||||
*
|
||||
* parameter major: The major type.
|
||||
* parameter romname: Name of the ROM type.
|
||||
* returns: Even if this is main rom, odd if XML. 0/1 for main slot, 2/3 for slot A, 4/5 for slot B. -1 if not valid
|
||||
* rom type.
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
*/
|
||||
int recognize_commandline_rom(core_type& major, const std::string& romname) throw(std::bad_alloc);
|
||||
|
||||
/**
|
||||
* Recognize major type from flags.
|
||||
*
|
||||
* parameter flags: Flags telling what ROM parameters are present.
|
||||
* returns: The recognzed major type.
|
||||
* throws std::bad_alloc: Not enough memory
|
||||
* throws std::runtime_error: Illegal flags.
|
||||
*/
|
||||
core_type& recognize_platform(const std::set<std::string>& present) throw(std::bad_alloc, std::runtime_error);
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
bool option_set(const std::vector<std::string>& cmdline, const std::string& option)
|
||||
{
|
||||
for(auto i : cmdline)
|
||||
if(i == option)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
core_type* current_rom_type = NULL;
|
||||
core_region* current_region = NULL;
|
||||
|
||||
std::string findoption(const std::vector<std::string>& cmdline, const std::string& option)
|
||||
{
|
||||
std::string value;
|
||||
regex_results optp;
|
||||
for(auto i : cmdline) {
|
||||
if(!(optp = regex("--([^=]+)=(.*)", i)) || optp[1] != option)
|
||||
continue;
|
||||
if(value == "")
|
||||
value = optp[2];
|
||||
else
|
||||
std::cerr << "WARNING: Ignored duplicate option for '" << option << "'." << std::endl;
|
||||
if(value == "")
|
||||
throw std::runtime_error("Empty value for '" + option + "' is not allowed");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::set<std::string> find_present_roms(const std::vector<std::string>& cmdline)
|
||||
{
|
||||
std::set<std::string> p;
|
||||
std::list<core_type*> types = core_type::get_core_types();
|
||||
for(auto i : types) {
|
||||
for(unsigned j = 0; j < i->get_image_count(); j++) {
|
||||
std::string iname = i->get_image_info(j).iname;
|
||||
if(findoption(cmdline, iname) != "")
|
||||
p.insert(iname);
|
||||
if(findoption(cmdline, iname + "-xml") != "")
|
||||
p.insert(iname + "-xml");
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
loaded_slot::loaded_slot() throw(std::bad_alloc)
|
||||
{
|
||||
valid = false;
|
||||
xml = false;
|
||||
sha256 = "";
|
||||
}
|
||||
|
||||
loaded_slot::loaded_slot(const std::string& filename, const std::string& base, bool xml_flag)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
loaded_slot::loaded_slot(const std::string& filename, const std::string& base,
|
||||
const struct core_romimage_info& imginfo, bool xml_flag) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
bool headered = false;
|
||||
unsigned headered = 0;
|
||||
xml = xml_flag;
|
||||
if(filename == "") {
|
||||
valid = false;
|
||||
sha256 = "";
|
||||
return;
|
||||
}
|
||||
valid = true;
|
||||
data = read_file_relative(filename, base);
|
||||
if(!xml && data.size() % 1024 == 512)
|
||||
//Assume headered.
|
||||
headered = true;
|
||||
if(!xml)
|
||||
headered = imginfo.headersize(data.size());
|
||||
if(headered && !xml) {
|
||||
if(data.size() >= 512) {
|
||||
memmove(&data[0], &data[512], data.size() - 512);
|
||||
data.resize(data.size() - 512);
|
||||
if(data.size() >= headered) {
|
||||
memmove(&data[0], &data[headered], data.size() - headered);
|
||||
data.resize(data.size() - headered);
|
||||
} else {
|
||||
data.resize(0);
|
||||
}
|
||||
|
@ -166,55 +94,6 @@ void loaded_slot::patch(const std::vector<char>& patch, int32_t offset) throw(st
|
|||
}
|
||||
}
|
||||
|
||||
rom_files::rom_files() throw()
|
||||
{
|
||||
rtype = NULL;
|
||||
region = NULL;
|
||||
}
|
||||
|
||||
rom_files::rom_files(const std::vector<std::string>& cmdline) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
for(size_t i = 0; i < sizeof(romimg) / sizeof(romimg[0]); i++) {
|
||||
romimg[i] = "";
|
||||
romxml[i] = "";
|
||||
}
|
||||
|
||||
auto opts = find_present_roms(cmdline);
|
||||
rtype = &recognize_platform(opts);
|
||||
for(auto i : opts) {
|
||||
std::string o = findoption(cmdline, i);
|
||||
if(o != "") {
|
||||
int j = recognize_commandline_rom(*rtype, i);
|
||||
if(j >= 0 && j & 1)
|
||||
romxml[j / 2] = o;
|
||||
else if(j >= 0)
|
||||
romimg[j / 2] = o;
|
||||
}
|
||||
}
|
||||
region = &rtype->get_preferred_region();
|
||||
std::string _region = findoption(cmdline, "region");
|
||||
if(_region != "") {
|
||||
bool isset = false;
|
||||
for(auto i : rtype->get_regions()) {
|
||||
if(i->get_iname() == _region) {
|
||||
region = i;
|
||||
isset = true;
|
||||
}
|
||||
}
|
||||
if(!isset)
|
||||
throw std::runtime_error("Unknown region for system type");
|
||||
}
|
||||
base_file = "";
|
||||
}
|
||||
|
||||
void rom_files::resolve_relative() throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
for(size_t i = 0; i < sizeof(romimg)/sizeof(romimg[0]); i++) {
|
||||
romimg[i] = resolve_file_relative(romimg[i], base_file);
|
||||
romxml[i] = resolve_file_relative(romxml[i], base_file);
|
||||
}
|
||||
base_file = "";
|
||||
}
|
||||
|
||||
|
||||
std::pair<core_type*, core_region*> get_current_rom_info() throw()
|
||||
|
@ -228,56 +107,139 @@ loaded_rom::loaded_rom() throw()
|
|||
region = orig_region = NULL;
|
||||
}
|
||||
|
||||
loaded_rom::loaded_rom(const rom_files& files) throw(std::bad_alloc, std::runtime_error)
|
||||
loaded_rom::loaded_rom(const std::string& file) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
std::string cromimg[sizeof(files.romimg)/sizeof(files.romimg[0])];
|
||||
std::string cromxml[sizeof(files.romimg)/sizeof(files.romimg[0])];
|
||||
for(size_t i = 0; i < sizeof(files.romimg)/sizeof(files.romimg[0]); i++) {
|
||||
cromimg[i] = files.romimg[i];
|
||||
cromxml[i] = files.romxml[i];
|
||||
}
|
||||
if(!files.rtype) {
|
||||
rtype = NULL;
|
||||
region = orig_region = files.region;
|
||||
std::list<core_type*> possible = core_type::get_core_types();
|
||||
std::istream& spec = open_file_relative(file, "");
|
||||
std::string s;
|
||||
std::getline(spec, s);
|
||||
load_filename = file;
|
||||
if(!spec || s != "[GAMEPACK FILE]") {
|
||||
//This is a Raw ROM image.
|
||||
regex_results tmp;
|
||||
std::string ext = regex(".*\\.([^.]*)?", file, "Unknown ROM file type")[1];
|
||||
core_type* coretype = NULL;
|
||||
for(auto i : possible) {
|
||||
if(i->is_known_extension(ext))
|
||||
coretype = i;
|
||||
}
|
||||
if(!coretype)
|
||||
throw std::runtime_error("Unknown ROM file type");
|
||||
rtype = coretype;
|
||||
region = orig_region = &rtype->get_preferred_region();
|
||||
romimg[0] = loaded_slot(file, "", coretype->get_image_info(0), false);
|
||||
msu1_base = resolve_file_relative(file, "");
|
||||
return;
|
||||
}
|
||||
for(size_t i = 0; i < sizeof(files.romimg)/sizeof(files.romimg[0]); i++) {
|
||||
if((cromimg[i] != "" || cromxml[i] != "") && i > files.rtype->get_image_count()) {
|
||||
messages << "Warning: ROM slot #" << (i + 1) << " is not used for this console" << std::endl;
|
||||
cromimg[i] = "";
|
||||
cromxml[i] = "";
|
||||
}
|
||||
if(cromimg[i] == "" && cromxml[i] != "") {
|
||||
messages << "WARNING: " << name_subrom(*files.rtype, 2 * i + 1) << " specified without "
|
||||
<< "corresponding " << name_subrom(*files.rtype, 2 * i + 0) << std::endl;
|
||||
cromxml[i] = "";
|
||||
}
|
||||
std::vector<std::string> lines;
|
||||
while(std::getline(spec, s))
|
||||
lines.push_back(s);
|
||||
std::string platname = "";
|
||||
std::string platreg = "";
|
||||
for(auto i : lines) {
|
||||
regex_results tmp;
|
||||
if(tmp = regex("type[ \t]+(.+)", i))
|
||||
platname = tmp[1];
|
||||
if(tmp = regex("region[ \t]+(.+)", i))
|
||||
platreg = tmp[1];
|
||||
}
|
||||
|
||||
rtype = files.rtype;
|
||||
for(size_t i = 0; i < sizeof(romimg) / sizeof(romimg[0]); i++) {
|
||||
romimg[i] = loaded_slot(cromimg[i], files.base_file, false);
|
||||
romxml[i] = loaded_slot(cromxml[i], files.base_file, true);
|
||||
//Detect type.
|
||||
rtype = NULL;
|
||||
for(auto i : possible)
|
||||
if(i->get_iname() == platname)
|
||||
rtype = i;
|
||||
if(!rtype)
|
||||
(stringfmt() << "Not a valid system type '" << platname << "'").throwex();
|
||||
|
||||
//Detect region.
|
||||
bool goodreg = false;
|
||||
orig_region = &rtype->get_preferred_region();
|
||||
for(auto i: rtype->get_regions())
|
||||
if(i->get_iname() == platreg) {
|
||||
orig_region = i;
|
||||
goodreg = true;
|
||||
}
|
||||
if(!goodreg && platreg != "")
|
||||
(stringfmt() << "Not a valid system region '" << platreg << "'").throwex();
|
||||
region = orig_region;
|
||||
|
||||
//ROM files.
|
||||
std::string cromimg[sizeof(romimg)/sizeof(romimg[0])];
|
||||
std::string cromxml[sizeof(romimg)/sizeof(romimg[0])];
|
||||
for(auto i : lines) {
|
||||
regex_results tmp;
|
||||
if(!(tmp = regex("(rom|xml)[ \t]+([^ \t]+)[ \t]+(.*)", i)))
|
||||
continue;
|
||||
size_t idxs = rtype->get_image_count();
|
||||
size_t idx = idxs;
|
||||
for(size_t i = 0; i < idxs; i++)
|
||||
if(rtype->get_image_info(i).iname == tmp[2])
|
||||
idx = i;
|
||||
if(idx == idxs)
|
||||
(stringfmt() << "Not a valid ROM name '" << tmp[2] << "'").throwex();
|
||||
if(tmp[1] == "rom")
|
||||
cromimg[idx] = tmp[3];
|
||||
else
|
||||
cromxml[idx] = tmp[3];
|
||||
}
|
||||
orig_region = region = files.region;
|
||||
|
||||
//Check ROMs.
|
||||
unsigned mask1 = 0, mask2 = 0;
|
||||
for(size_t i = 0; i < rtype->get_image_count(); i++) {
|
||||
auto ii = rtype->get_image_info(i);
|
||||
mask1 |= ii.mandatory;
|
||||
if(cromimg[i] != "")
|
||||
mask2 |= ii.mandatory;
|
||||
if(cromimg[i] == "" && cromxml[i] != "") {
|
||||
messages << "WARNING: Slot " << ii.iname << ": XML without ROM." << std::endl;
|
||||
cromxml[i] = "";
|
||||
}
|
||||
}
|
||||
if(mask1 != mask2)
|
||||
throw std::runtime_error("Required ROM missing");
|
||||
|
||||
//Load ROMs.
|
||||
for(size_t i = 0; i < rtype->get_image_count(); i++) {
|
||||
romimg[i] = loaded_slot(cromimg[i], file, rtype->get_image_info(i), false);
|
||||
romxml[i] = loaded_slot(cromxml[i], file, rtype->get_image_info(i), true);
|
||||
}
|
||||
|
||||
//Patch ROMs.
|
||||
for(auto i : lines) {
|
||||
regex_results tmp;
|
||||
if(!(tmp = regex("patch[ \t]+([^ \t]+)[ \t]+(.*)([ \t]+[+-][0-9]+)?", i)))
|
||||
continue;
|
||||
size_t idxs = rtype->get_image_count();
|
||||
size_t idx = idxs;
|
||||
for(size_t i = 0; i < idxs; i++)
|
||||
if(rtype->get_image_info(i).iname == tmp[1])
|
||||
idx = i;
|
||||
if(idx == idxs)
|
||||
(stringfmt() << "Not a valid ROM name '" << tmp[1] << "'").throwex();
|
||||
int32_t offset = 0;
|
||||
if(tmp[3] != "")
|
||||
offset = parse_value<int32_t>(tmp[3]);
|
||||
romimg[idx].patch(read_file_relative(tmp[2], ""), offset);
|
||||
}
|
||||
|
||||
//MSU-1 base.
|
||||
if(cromimg[1] != "")
|
||||
msu1_base = resolve_file_relative(cromimg[1], files.base_file);
|
||||
msu1_base = resolve_file_relative(cromimg[1], file);
|
||||
else
|
||||
msu1_base = resolve_file_relative(cromimg[0], files.base_file);
|
||||
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)
|
||||
{
|
||||
if(!rtype)
|
||||
throw std::runtime_error("Can't insert cartridge of type NONE!");
|
||||
current_rom_type = NULL;
|
||||
if(!orig_region)
|
||||
if(!orig_region && rtype)
|
||||
orig_region = &rtype->get_preferred_region();
|
||||
if(!region)
|
||||
region = orig_region;
|
||||
if(!orig_region->compatible_with(*region))
|
||||
if(rtype && !orig_region->compatible_with(*region))
|
||||
throw std::runtime_error("Trying to force incompatible region");
|
||||
if(!core_set_region(*region))
|
||||
if(rtype && !core_set_region(*region))
|
||||
throw std::runtime_error("Trying to force unknown region");
|
||||
|
||||
core_romimage images[sizeof(romimg)/sizeof(romimg[0])];
|
||||
|
@ -286,8 +248,11 @@ void loaded_rom::load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_allo
|
|||
images[i].data = (const unsigned char*)romimg[i];
|
||||
images[i].size = (size_t)romimg[i];
|
||||
}
|
||||
if(!rtype->load(images, rtc_sec, rtc_subsec))
|
||||
throw std::runtime_error("Can't load cartridge ROM");
|
||||
if(rtype) {
|
||||
if(!rtype->load(images, rtc_sec, rtc_subsec))
|
||||
throw std::runtime_error("Can't load cartridge ROM");
|
||||
} else
|
||||
core_unload_cartridge();
|
||||
|
||||
region = &core_get_region();
|
||||
core_power();
|
||||
|
@ -301,46 +266,6 @@ void loaded_rom::load(uint64_t rtc_sec, uint64_t rtc_subsec) throw(std::bad_allo
|
|||
refresh_cart_mappings();
|
||||
}
|
||||
|
||||
void loaded_rom::do_patch(const std::vector<std::string>& cmdline) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
int32_t offset = 0;
|
||||
regex_results opt;
|
||||
for(auto i : cmdline) {
|
||||
if(opt = regex("--ips-offset=(.*)", i)) {
|
||||
try {
|
||||
offset = parse_value<int32_t>(opt[1]);
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error("Invalid IPS offset option '" + i + "': " + e.what());
|
||||
}
|
||||
continue;
|
||||
} else if(opt = regex("--ips-([^=]*)=(.+)", i)) {
|
||||
messages << "Patching " << opt[1] << " using '" << opt[2] << "'" << std::endl;
|
||||
std::vector<char> ips;
|
||||
try {
|
||||
ips = read_file_relative(opt[2], "");
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error("Can't read IPS '" + opt[2] + "': " + e.what());
|
||||
}
|
||||
try {
|
||||
int r_id = recognize_commandline_rom(*rtype, opt[1]);
|
||||
if(r_id < 0 || r_id > 2 * sizeof(romimg) / sizeof(romimg[0]))
|
||||
throw std::runtime_error("Invalid subROM '" + opt[1] + "' to patch");
|
||||
if(r_id & 1)
|
||||
romxml[r_id / 2].patch(ips, offset);
|
||||
else
|
||||
romimg[r_id / 2].patch(ips, offset);
|
||||
} catch(std::bad_alloc& e) {
|
||||
OOM_panic();
|
||||
} catch(std::exception& e) {
|
||||
throw std::runtime_error("Can't Patch with IPS '" + opt[2] + "': " + e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<char>> load_sram_commandline(const std::vector<std::string>& cmdline)
|
||||
throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
|
@ -408,60 +333,3 @@ void load_core_state(const std::vector<char>& buf, bool nochecksum) throw(std::r
|
|||
throw std::runtime_error("Savestate corrupt");
|
||||
core_unserialize(&buf[0], buf.size() - 32);;
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
int recognize_commandline_rom(core_type& major, const std::string& romname) throw(std::bad_alloc)
|
||||
{
|
||||
for(unsigned i = 0; i < major.get_image_count(); i++) {
|
||||
std::string iname = major.get_image_info(i).iname;
|
||||
if(romname == iname)
|
||||
return 2 * i + 0;
|
||||
if(romname == iname + "-xml")
|
||||
return 2 * i + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
core_type& recognize_platform(const std::set<std::string>& present) throw(std::bad_alloc, std::runtime_error)
|
||||
{
|
||||
std::list<core_type*> possible = core_type::get_core_types();
|
||||
unsigned total = 0;
|
||||
for(auto i : present) {
|
||||
regex_results r;
|
||||
std::string base = i;
|
||||
if(r = regex("(.*)-xml", base)) {
|
||||
if(!present.count(r[1]))
|
||||
throw std::runtime_error("SubROM XML specified without corresponding subROM");
|
||||
} else
|
||||
total++;
|
||||
}
|
||||
for(auto i : possible) {
|
||||
unsigned pmask = 0;
|
||||
unsigned rmask = 0;
|
||||
unsigned found = 0;
|
||||
for(unsigned j = 0; j < i->get_image_count(); j++) {
|
||||
std::string iname = i->get_image_info(j).iname;
|
||||
if(present.count(iname)) {
|
||||
pmask |= i->get_image_info(j).mandatory;
|
||||
found++;
|
||||
}
|
||||
rmask |= i->get_image_info(j).mandatory;
|
||||
}
|
||||
if(pmask == rmask && found == total)
|
||||
return *i;
|
||||
}
|
||||
throw std::runtime_error("Invalid combination of subROMs");
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include "core/romtype.hpp"
|
||||
#include "library/minmax.hpp"
|
||||
#include "library/string.hpp"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <stdexcept>
|
||||
#include <list>
|
||||
|
||||
|
@ -263,13 +267,32 @@ core_sysregion& core_type::combine_region(core_region& reg)
|
|||
}
|
||||
|
||||
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))
|
||||
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;
|
||||
while(extract_token(ext2, ext, ";") >= 0)
|
||||
extensions.push_back(ext);
|
||||
process_registrations();
|
||||
}
|
||||
|
||||
const std::list<std::string>& core_type::get_extensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
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));
|
||||
|
|
|
@ -76,6 +76,7 @@ namespace
|
|||
std::ofstream ohandle;
|
||||
bool handle_open;
|
||||
std::string current_project;
|
||||
bool lazy_mode;
|
||||
//% is intentionally missing.
|
||||
const char* allowed_filename_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
"^&'@{}[],$?!-#().+~_";
|
||||
|
@ -94,17 +95,29 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
void rrdata::read_base(const std::string& project) throw(std::bad_alloc)
|
||||
void rrdata::read_base(const std::string& project, bool lazy) throw(std::bad_alloc)
|
||||
{
|
||||
if(project == current_project)
|
||||
if(project == current_project && (!lazy_mode || lazy))
|
||||
return;
|
||||
if(lazy) {
|
||||
std::set<rrdata::instance> new_rrset;
|
||||
rrset = new_rrset;
|
||||
current_project = project;
|
||||
lazy_mode = true;
|
||||
if(handle_open)
|
||||
ohandle.close();
|
||||
handle_open = false;
|
||||
return;
|
||||
}
|
||||
std::set<rrdata::instance> new_rrset;
|
||||
if(project == current_project)
|
||||
new_rrset = rrset;
|
||||
std::string filename = get_config_path() + "/" + safe_filename(project) + ".rr";
|
||||
if(handle_open) {
|
||||
ohandle.close();
|
||||
handle_open = false;
|
||||
}
|
||||
ihandle.open(filename.c_str(), std::ios_base::in);
|
||||
ihandle.open(filename.c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
while(ihandle) {
|
||||
unsigned char bytes[RRDATA_BYTES];
|
||||
ihandle.read(reinterpret_cast<char*>(bytes), RRDATA_BYTES);
|
||||
|
@ -113,11 +126,19 @@ void rrdata::read_base(const std::string& project) throw(std::bad_alloc)
|
|||
new_rrset.insert(k);
|
||||
}
|
||||
ihandle.close();
|
||||
ohandle.open(filename.c_str(), std::ios_base::out | std::ios_base::app);
|
||||
ohandle.open(filename.c_str(), std::ios_base::out | std::ios_base::app | std::ios_base::binary);
|
||||
if(ohandle)
|
||||
handle_open = true;
|
||||
if(project == current_project && lazy_mode && !lazy) {
|
||||
//Finish the project creation, write all.
|
||||
for(auto i : rrset) {
|
||||
ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
|
||||
ohandle.flush();
|
||||
}
|
||||
}
|
||||
rrset = new_rrset;
|
||||
current_project = project;
|
||||
lazy_mode = lazy;
|
||||
}
|
||||
|
||||
void rrdata::close() throw()
|
||||
|
|
|
@ -387,7 +387,14 @@ bool lsnes_app::OnInit()
|
|||
msg_window = new wxwin_messages();
|
||||
msg_window->Show();
|
||||
|
||||
open_rom_select_window();
|
||||
do_basic_core_init();
|
||||
loaded_rom* rom = new loaded_rom;
|
||||
moviefile mov;
|
||||
mov.port1 = &porttype_info::port_default(0);
|
||||
mov.port2 = &porttype_info::port_default(1);
|
||||
mov.input.clear(*mov.port1, *mov.port2);
|
||||
mov.start_paused = true;
|
||||
boot_emulator(*rom, mov);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -92,7 +92,8 @@ enum
|
|||
wxID_LOAD_LIBRARY,
|
||||
wxID_SETTINGS,
|
||||
wxID_RELOAD_ROM_IMAGE,
|
||||
wxID_LOAD_ROM_IMAGE
|
||||
wxID_LOAD_ROM_IMAGE,
|
||||
wxID_NEW_MOVIE,
|
||||
};
|
||||
|
||||
|
||||
|
@ -459,12 +460,33 @@ namespace
|
|||
}
|
||||
|
||||
path_setting moviepath_setting("moviepath");
|
||||
path_setting rompath_setting("rompath");
|
||||
|
||||
std::string movie_path()
|
||||
{
|
||||
return setting::get("moviepath");
|
||||
}
|
||||
|
||||
std::string rom_path()
|
||||
{
|
||||
return setting::get("rompath");
|
||||
}
|
||||
|
||||
bool is_lsnes_movie(const std::string& filename)
|
||||
{
|
||||
try {
|
||||
zip_reader r(filename);
|
||||
std::istream& s = r["systemid"];
|
||||
std::string s2;
|
||||
std::getline(s, s2);
|
||||
delete &s;
|
||||
istrip_CR(s2);
|
||||
return (s2 == "lsnes-rr1");
|
||||
} catch(...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class loadfile : public wxFileDropTarget
|
||||
{
|
||||
public:
|
||||
|
@ -472,7 +494,10 @@ namespace
|
|||
{
|
||||
if(filenames.Count() != 1)
|
||||
return false;
|
||||
platform::queue("load " + tostdstring(filenames[0]));
|
||||
if(is_lsnes_movie(tostdstring(filenames[0])))
|
||||
platform::queue("load-smart " + tostdstring(filenames[0]));
|
||||
else
|
||||
platform::queue("reload-rom " + tostdstring(filenames[0]));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -688,6 +713,9 @@ wxwin_mainwindow::wxwin_mainwindow()
|
|||
menu_separator();
|
||||
menu_entry(wxID_ABOUT, wxT("About..."));
|
||||
menu_start(wxT("System"));
|
||||
menu_start_sub(wxT("New"));
|
||||
menu_entry(wxID_NEW_MOVIE, wxT("Movie..."));
|
||||
menu_end_sub();
|
||||
menu_start_sub(wxT("Load"));
|
||||
menu_entry(wxID_LOAD_STATE, wxT("State..."));
|
||||
menu_entry(wxID_LOAD_STATE_RO, wxT("State (readonly)..."));
|
||||
|
@ -1068,10 +1096,13 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
|
|||
wxsetingsdialog_display(this);
|
||||
break;
|
||||
case wxID_LOAD_ROM_IMAGE:
|
||||
platform::queue("reload-rom " + pick_file_member(this, "Select new ROM image", "."));
|
||||
platform::queue("reload-rom " + pick_file_member(this, "Select new ROM image", rom_path()));
|
||||
return;
|
||||
case wxID_RELOAD_ROM_IMAGE:
|
||||
platform::queue("reload-rom");
|
||||
return;
|
||||
case wxID_NEW_MOVIE:
|
||||
show_projectwindow(this);
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "core/moviedata.hpp"
|
||||
#include "core/framerate.hpp"
|
||||
#include "core/settings.hpp"
|
||||
#include "core/window.hpp"
|
||||
#include "library/zip.hpp"
|
||||
|
||||
#include "platform/wxwidgets/platform.hpp"
|
||||
|
@ -159,205 +160,12 @@ namespace
|
|||
private:
|
||||
wxTextCtrl* ctrl;
|
||||
};
|
||||
|
||||
path_setting rompath_setting("rompath");
|
||||
|
||||
std::string rom_path()
|
||||
{
|
||||
//This is pre-boot, so read directly.
|
||||
return rompath_setting;
|
||||
}
|
||||
|
||||
struct rom_slot_callback
|
||||
{
|
||||
virtual void on_file_change() = 0;
|
||||
};
|
||||
|
||||
class rom_slot : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
rom_slot(wxWindow* inWindow, rom_slot_callback* _cb);
|
||||
void show(wxSizer* sizer);
|
||||
void hide(wxSizer* sizer);
|
||||
void change(const std::string& name, bool has_markup);
|
||||
std::string get_filename();
|
||||
std::string get_markup();
|
||||
void on_change(wxCommandEvent& e);
|
||||
void on_filename_b(wxCommandEvent& e);
|
||||
void on_markup_b(wxCommandEvent& e);
|
||||
private:
|
||||
wxPanel* panel;
|
||||
wxBoxSizer* top;
|
||||
wxStaticBox* box;
|
||||
wxButton* filename_pick;
|
||||
wxButton* markup_pick;
|
||||
wxTextCtrl* filename;
|
||||
wxTextCtrl* markup;
|
||||
bool markup_flag;
|
||||
bool enabled;
|
||||
rom_slot_callback* cb;
|
||||
wxStaticBoxSizer* intsizer;
|
||||
};
|
||||
|
||||
rom_slot::rom_slot(wxWindow* in_window, rom_slot_callback* _cb)
|
||||
{
|
||||
wxSizer* tmp;
|
||||
cb = _cb;
|
||||
panel = new wxPanel(in_window);
|
||||
top = new wxBoxSizer(wxVERTICAL);
|
||||
panel->SetSizer(top);
|
||||
box = new wxStaticBox(panel, wxID_ANY, wxT(""));
|
||||
intsizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
intsizer->Add(new wxStaticText(panel, wxID_ANY, wxT("File")));
|
||||
tmp = new wxBoxSizer(wxHORIZONTAL);
|
||||
tmp->Add(filename = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxDefaultPosition,
|
||||
wxSize(400,-1)), 1, wxGROW);
|
||||
filename->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(rom_slot::on_change), NULL, this);
|
||||
filename->SetDropTarget(new textboxloadfilename(filename));
|
||||
tmp->Add(filename_pick = new wxButton(panel, wxID_ANY, wxT("Pick...")));
|
||||
filename_pick->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(rom_slot::on_filename_b),
|
||||
NULL, this);;
|
||||
intsizer->Add(tmp);
|
||||
intsizer->Add(new wxStaticText(panel, wxID_ANY, wxT("Default mappings override file (optional) ")));
|
||||
tmp = new wxBoxSizer(wxHORIZONTAL);
|
||||
tmp->Add(markup = new wxTextCtrl(panel, wxID_ANY, wxT(""), wxDefaultPosition,
|
||||
wxSize(400,-1)), 1, wxGROW);
|
||||
markup->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(rom_slot::on_change), NULL, this);
|
||||
markup->SetDropTarget(new textboxloadfilename(markup));
|
||||
tmp->Add(markup_pick = new wxButton(panel, wxID_ANY, wxT("Pick...")));
|
||||
markup_pick->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(rom_slot::on_markup_b),
|
||||
NULL, this);
|
||||
intsizer->Add(tmp);
|
||||
markup->Enable(markup_flag = false);
|
||||
top->Add(intsizer);
|
||||
hide(NULL);
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
void rom_slot::on_change(wxCommandEvent& e)
|
||||
{
|
||||
if(cb)
|
||||
cb->on_file_change();
|
||||
}
|
||||
|
||||
void rom_slot::show(wxSizer* sizer)
|
||||
{
|
||||
panel->Show();
|
||||
sizer->Add(panel);
|
||||
enabled = true;
|
||||
intsizer->Layout();
|
||||
top->Layout();
|
||||
sizer->Layout();
|
||||
}
|
||||
|
||||
void rom_slot::hide(wxSizer* sizer)
|
||||
{
|
||||
if(sizer)
|
||||
sizer->Detach(panel);
|
||||
enabled = false;
|
||||
panel->Hide();
|
||||
if(sizer)
|
||||
sizer->Layout();
|
||||
}
|
||||
|
||||
void rom_slot::change(const std::string& name, bool has_markup)
|
||||
{
|
||||
box->SetLabel(towxstring(name));
|
||||
markup_flag = has_markup;
|
||||
markup->Enable(has_markup);
|
||||
markup_pick->Enable(has_markup);
|
||||
}
|
||||
|
||||
std::string rom_slot::get_filename()
|
||||
{
|
||||
if(!enabled)
|
||||
return "";
|
||||
return tostdstring(filename->GetValue());
|
||||
}
|
||||
|
||||
std::string rom_slot::get_markup()
|
||||
{
|
||||
if(!enabled || !markup_flag)
|
||||
return "";
|
||||
return tostdstring(markup->GetValue());
|
||||
}
|
||||
|
||||
void rom_slot::on_filename_b(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
std::string fname = pick_file_member(panel, "Choose ROM file", rom_path());
|
||||
filename->SetValue(towxstring(fname));
|
||||
on_change(e);
|
||||
} catch(canceled_exception& e) {
|
||||
}
|
||||
}
|
||||
|
||||
void rom_slot::on_markup_b(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
std::string fname = pick_file_member(panel, "Choose markup file", rom_path());
|
||||
markup->SetValue(towxstring(fname));
|
||||
on_change(e);
|
||||
} catch(canceled_exception& e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class wxwin_romselect : public wxFrame, rom_slot_callback
|
||||
class wxwin_project : public wxDialog
|
||||
{
|
||||
public:
|
||||
wxwin_romselect();
|
||||
~wxwin_romselect();
|
||||
void on_filename_change(wxCommandEvent& e);
|
||||
void on_romtype_change(wxCommandEvent& e);
|
||||
void on_quit(wxCommandEvent& e);
|
||||
void on_open_rom(wxCommandEvent& e);
|
||||
void on_apply_rom(wxCommandEvent& e);
|
||||
void on_openapply_rom(wxCommandEvent& e, bool apply);
|
||||
void on_file_change();
|
||||
loaded_rom* our_rom;
|
||||
private:
|
||||
wxComboBox* romtype_combo;
|
||||
wxComboBox* region_combo;
|
||||
wxBoxSizer* romgrid;
|
||||
rom_slot* slots[ROMSELECT_ROM_COUNT];
|
||||
wxButton* apply_rom;
|
||||
wxButton* open_rom;
|
||||
wxButton* quit_button;
|
||||
std::string current_rtype;
|
||||
void set_rtype(std::string rtype);
|
||||
};
|
||||
|
||||
void open_rom_select_window()
|
||||
{
|
||||
wxwin_romselect* romwin = new wxwin_romselect();
|
||||
romwin->Show();
|
||||
}
|
||||
|
||||
class wxwin_patch : public wxFrame
|
||||
{
|
||||
public:
|
||||
wxwin_patch(loaded_rom& rom);
|
||||
~wxwin_patch();
|
||||
void on_patchfile_change(wxCommandEvent& e);
|
||||
void on_ask_patchfile(wxCommandEvent& e);
|
||||
void on_do_patch(wxCommandEvent& e);
|
||||
void on_quit(wxCommandEvent& e);
|
||||
void on_done(wxCommandEvent& e);
|
||||
loaded_rom* our_rom;
|
||||
private:
|
||||
wxComboBox* patch_what;
|
||||
wxStaticText* checksums[ROMSELECT_ROM_COUNT];
|
||||
wxTextCtrl* patchfile;
|
||||
wxButton* choosefile;
|
||||
wxButton* dopatch;
|
||||
wxTextCtrl* patch_offset;
|
||||
};
|
||||
|
||||
class wxwin_project : public wxFrame
|
||||
{
|
||||
public:
|
||||
wxwin_project(loaded_rom& rom);
|
||||
wxwin_project();
|
||||
~wxwin_project();
|
||||
void on_file_select(wxCommandEvent& e);
|
||||
void on_new_select(wxCommandEvent& e);
|
||||
|
@ -365,19 +173,12 @@ public:
|
|||
void on_ask_filename(wxCommandEvent& e);
|
||||
void on_quit(wxCommandEvent& e);
|
||||
void on_load(wxCommandEvent& e);
|
||||
void on_tab_select(wxNotebookEvent& e);
|
||||
loaded_rom* our_rom;
|
||||
private:
|
||||
bool load_file;
|
||||
struct moviefile make_movie();
|
||||
wxTextCtrl* savefile;
|
||||
wxButton* ask_savefile;
|
||||
wxNotebook* notebook;
|
||||
std::map<std::string, wxTextCtrl*> sram_files;
|
||||
std::map<std::string, wxButton*> sram_choosers;
|
||||
wxComboBox* controller1type;
|
||||
wxComboBox* controller2type;
|
||||
wxCheckBox* start_pause;
|
||||
wxTextCtrl* projectname;
|
||||
wxTextCtrl* prefix;
|
||||
wxTextCtrl* rtc_sec;
|
||||
|
@ -389,349 +190,24 @@ private:
|
|||
};
|
||||
|
||||
|
||||
wxwin_romselect::wxwin_romselect()
|
||||
: wxFrame(NULL, wxID_ANY, wxT("Select ROM"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
|
||||
|
||||
void show_projectwindow(wxWindow* modwin)
|
||||
{
|
||||
std::vector<wxString> rtchoices;
|
||||
std::vector<wxString> rrchoices;
|
||||
size_t systems = populate_system_choices(rtchoices);
|
||||
size_t regions = populate_region_choices(rrchoices);
|
||||
|
||||
Centre();
|
||||
|
||||
//The toplevel sizer contains three sizers:
|
||||
//- The top bar having ROM type / Region selects.
|
||||
//- The middle area having ROM filename boxes.
|
||||
//- The bottom bar having OK/Quit buttons.
|
||||
wxFlexGridSizer* toplevel = new wxFlexGridSizer(3, 1, 0, 0);
|
||||
SetSizer(toplevel);
|
||||
|
||||
//The ROM type / Region selects.
|
||||
wxBoxSizer* selects = new wxBoxSizer(wxHORIZONTAL);
|
||||
selects->Add(new wxStaticText(this, wxID_ANY, wxT("ROM type:")), 0, wxGROW);
|
||||
selects->Add(romtype_combo = new wxComboBox(this, wxID_ANY, rtchoices[0], wxDefaultPosition, wxDefaultSize,
|
||||
systems, &rtchoices[0], wxCB_READONLY), 0, wxGROW);
|
||||
selects->Add(new wxStaticText(this, wxID_ANY, wxT("Region:")), 0, wxGROW);
|
||||
selects->Add(region_combo = new wxComboBox(this, wxID_ANY, rrchoices[0], wxDefaultPosition, wxDefaultSize,
|
||||
regions, &rrchoices[0], wxCB_READONLY), 0, wxGROW);
|
||||
romtype_combo->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_romtype_change), NULL, this);
|
||||
region_combo->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_romtype_change), NULL, this);
|
||||
toplevel->Add(selects, 0, wxGROW);
|
||||
|
||||
//ROM filename selects
|
||||
romgrid = new wxBoxSizer(wxVERTICAL);
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
slots[i] = new rom_slot(this, this);
|
||||
toplevel->Add(romgrid, 1, wxGROW);
|
||||
|
||||
//Button bar.
|
||||
wxBoxSizer* buttons = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttons->Add(apply_rom = new wxButton(this, wxID_ANY, wxT("Apply patches")), 0, wxALIGN_RIGHT);
|
||||
buttons->Add(open_rom = new wxButton(this, wxID_OPEN, wxT("Open ROM")), 0, wxALIGN_RIGHT);
|
||||
buttons->AddStretchSpacer();
|
||||
buttons->Add(quit_button = new wxButton(this, wxID_EXIT, wxT("Quit")), 0, wxALIGN_RIGHT);
|
||||
apply_rom->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_apply_rom), NULL, this);
|
||||
open_rom->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_open_rom), NULL, this);
|
||||
open_rom->Disable();
|
||||
apply_rom->Disable();
|
||||
quit_button->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_romselect::on_quit), NULL, this);
|
||||
toplevel->Add(buttons, 1, wxGROW);
|
||||
|
||||
//Initialize form.
|
||||
set_rtype("");
|
||||
|
||||
//Display it.
|
||||
toplevel->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
||||
wxwin_romselect::~wxwin_romselect()
|
||||
{
|
||||
for(size_t i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
delete slots[i];
|
||||
}
|
||||
|
||||
void wxwin_romselect::set_rtype(std::string rtype)
|
||||
{
|
||||
bool no_rtype = (current_rtype == "");
|
||||
if(rtype == "")
|
||||
rtype = tostdstring(romtype_combo->GetValue());
|
||||
if(rtype == current_rtype)
|
||||
return;
|
||||
region_combo->Clear();
|
||||
for(auto i : romtype_from_string(rtype).get_regions())
|
||||
region_combo->Append(towxstring(i->get_hname()));
|
||||
region_combo->SetSelection(0);
|
||||
if(has_forced_region(rtype))
|
||||
region_combo->Disable();
|
||||
else
|
||||
region_combo->Enable();
|
||||
std::string tmp[ROMSELECT_ROM_COUNT];
|
||||
unsigned c = fill_rom_names(romtype_from_string(rtype), tmp);
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
slots[i]->hide(romgrid);
|
||||
for(unsigned i = 0; i < c; i++) {
|
||||
slots[i]->change(tmp[i], true);
|
||||
slots[i]->show(romgrid);
|
||||
}
|
||||
romgrid->Layout();
|
||||
current_rtype = rtype;
|
||||
Fit();
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_file_change()
|
||||
{
|
||||
bool ok = true;
|
||||
core_type& rtype = romtype_from_string(tostdstring(romtype_combo->GetValue()));
|
||||
unsigned flags = 0;
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
flags |= ((slots[i]->get_filename() != "") ? (1 << i) : 0);
|
||||
open_rom->Enable(check_present_roms(rtype, flags));
|
||||
apply_rom->Enable(check_present_roms(rtype, flags));
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_romtype_change(wxCommandEvent& e)
|
||||
{
|
||||
set_rtype(tostdstring(romtype_combo->GetValue()));
|
||||
on_file_change();
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_quit(wxCommandEvent& e)
|
||||
{
|
||||
Close(true);
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_open_rom(wxCommandEvent& e)
|
||||
{
|
||||
on_openapply_rom(e, false);
|
||||
}
|
||||
|
||||
void wxwin_romselect::on_apply_rom(wxCommandEvent& e)
|
||||
{
|
||||
on_openapply_rom(e, true);
|
||||
}
|
||||
|
||||
|
||||
void wxwin_romselect::on_openapply_rom(wxCommandEvent& e, bool apply)
|
||||
{
|
||||
rom_files rfiles;
|
||||
rfiles.base_file = "";
|
||||
rfiles.rtype = &romtype_from_string(tostdstring(romtype_combo->GetValue()));
|
||||
rfiles.region = ®ion_from_string(*rfiles.rtype, tostdstring(region_combo->GetValue()));
|
||||
for(size_t i = 0; i < ROMSELECT_ROM_COUNT && i < sizeof(rfiles.romimg) / sizeof(rfiles.romimg[0]); i++) {
|
||||
rfiles.romimg[i] = slots[i]->get_filename();
|
||||
rfiles.romxml[i] = slots[i]->get_markup();
|
||||
}
|
||||
try {
|
||||
our_rom = new loaded_rom(rfiles);
|
||||
our_rom_name = "";
|
||||
for(size_t i = 1; i < sizeof(our_rom->romimg) / sizeof(our_rom->romimg[0]); i++)
|
||||
if(our_rom->romimg[i].valid && our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[i].sha256;
|
||||
if(our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[0].sha256;
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(this, "Error loading ROM", e.what(), wxICON_EXCLAMATION);
|
||||
if(!our_rom->rtype) {
|
||||
show_message_ok(modwin, "Can't start new movie", "No ROM loaded", wxICON_EXCLAMATION);
|
||||
return;
|
||||
}
|
||||
if(apply) {
|
||||
wxwin_patch* projwin = new wxwin_patch(*our_rom);
|
||||
projwin->Show();
|
||||
} else {
|
||||
patching_done(*our_rom, this);
|
||||
}
|
||||
Destroy();
|
||||
}
|
||||
//---------------------------------------------------
|
||||
wxwin_patch::wxwin_patch(loaded_rom& rom)
|
||||
: wxFrame(NULL, wxID_ANY, wxT("Patch ROM"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
|
||||
{
|
||||
our_rom = &rom;
|
||||
wxString targets[2 * ROMSELECT_ROM_COUNT];
|
||||
std::string _targets[ROMSELECT_ROM_COUNT];
|
||||
size_t _target_count = fill_rom_names(*rom.rtype, _targets);
|
||||
size_t target_count = 0;
|
||||
for(auto i = 0; i < _target_count; i++) {
|
||||
targets[2 * i] = towxstring(_targets[i]);
|
||||
targets[2 * i + 1] = towxstring(_targets[i] + MARKUP_POSTFIX);
|
||||
target_count += 2;
|
||||
}
|
||||
|
||||
//Toplevel has 5 blocks:
|
||||
//- Checksums for ROMs.
|
||||
//- Patch what select.
|
||||
//- Filename select.
|
||||
//- Patch offset.
|
||||
//- Button bar.
|
||||
Centre();
|
||||
wxFlexGridSizer* toplevel = new wxFlexGridSizer(5, 1, 0, 0);
|
||||
SetSizer(toplevel);
|
||||
|
||||
//Checksums block.
|
||||
wxFlexGridSizer* hashes = new wxFlexGridSizer(target_count, 2, 0, 0);
|
||||
for(unsigned i = 0; i < ROMSELECT_ROM_COUNT; i++)
|
||||
checksums[i] = NULL;
|
||||
for(unsigned i = 0; i < target_count; i++) {
|
||||
std::string hash = get_rom_slot(*our_rom, i).sha256;
|
||||
if(hash == "")
|
||||
hash = "<Not present>";
|
||||
hashes->Add(new wxStaticText(this, wxID_ANY, targets[i]), 0, wxGROW);
|
||||
hashes->Add(checksums[i] = new wxStaticText(this, wxID_ANY, towxstring(hash)), 0, wxGROW);
|
||||
}
|
||||
toplevel->Add(hashes, 0, wxGROW);
|
||||
|
||||
//Target select.
|
||||
wxFlexGridSizer* targetselect = new wxFlexGridSizer(1, 2, 0, 0);
|
||||
targetselect->Add(new wxStaticText(this, wxID_ANY, wxT("Patch what:")), 0, wxGROW);
|
||||
targetselect->Add(patch_what = new wxComboBox(this, wxID_ANY, targets[0], wxDefaultPosition, wxDefaultSize,
|
||||
target_count, targets, wxCB_READONLY), 0, wxGROW);
|
||||
toplevel->Add(targetselect, 0, wxGROW);
|
||||
|
||||
//Patchfile.
|
||||
wxFlexGridSizer* patchsel = new wxFlexGridSizer(1, 3, 0, 0);
|
||||
patchsel->Add(new wxStaticText(this, wxID_ANY, wxT("File:")), 0, wxGROW);
|
||||
patchsel->Add(patchfile = new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(500, -1)),
|
||||
1, wxGROW);
|
||||
patchsel->Add(choosefile = new wxButton(this, wxID_ANY, wxT("Pick")), 0, wxGROW);
|
||||
patchfile->Connect(wxEVT_COMMAND_TEXT_UPDATED,
|
||||
wxCommandEventHandler(wxwin_patch::on_patchfile_change), NULL, this);
|
||||
choosefile->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_ask_patchfile), NULL, this);
|
||||
patchfile->SetDropTarget(new textboxloadfilename(patchfile));
|
||||
toplevel->Add(patchsel, 0, wxGROW);
|
||||
|
||||
//Patch offset.
|
||||
wxFlexGridSizer* offsetselect = new wxFlexGridSizer(1, 2, 0, 0);
|
||||
offsetselect->Add(new wxStaticText(this, wxID_ANY, wxT("Patch offset:")), 0, wxGROW);
|
||||
offsetselect->Add(patch_offset = new wxTextCtrl(this, wxID_ANY, wxT("")), 0, wxGROW);
|
||||
patch_offset->Connect(wxEVT_COMMAND_TEXT_UPDATED,
|
||||
wxCommandEventHandler(wxwin_patch::on_patchfile_change), NULL, this);
|
||||
toplevel->Add(offsetselect, 0, wxGROW);
|
||||
|
||||
//Button bar
|
||||
wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttonbar->AddStretchSpacer();
|
||||
wxButton* thats_enough = new wxButton(this, wxID_ANY, wxT("Enough"));
|
||||
buttonbar->Add(thats_enough, 0, wxGROW);
|
||||
thats_enough->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_done), NULL, this);
|
||||
dopatch = new wxButton(this, wxID_ANY, wxT("Patch"));
|
||||
buttonbar->Add(dopatch, 0, wxGROW);
|
||||
dopatch->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_do_patch), NULL, this);
|
||||
dopatch->Disable();
|
||||
wxButton* quitbutton = new wxButton(this, wxID_EXIT, wxT("Quit"));
|
||||
buttonbar->Add(quitbutton, 0, wxGROW);
|
||||
quitbutton->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_patch::on_quit), NULL, this);
|
||||
toplevel->Add(buttonbar, 0, wxGROW);
|
||||
|
||||
patch_offset->SetValue(wxT("0"));
|
||||
|
||||
hashes->SetSizeHints(this);
|
||||
targetselect->SetSizeHints(this);
|
||||
buttonbar->SetSizeHints(this);
|
||||
toplevel->SetSizeHints(this);
|
||||
Fit();
|
||||
wxwin_project* projwin = new wxwin_project();
|
||||
projwin->ShowModal();
|
||||
projwin->Destroy();
|
||||
}
|
||||
|
||||
void wxwin_patch::on_ask_patchfile(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
std::string fname = pick_file_member(this, "Choose patch file", rom_path());
|
||||
patchfile->SetValue(towxstring(fname));
|
||||
on_patchfile_change(e);
|
||||
} catch(canceled_exception& e) {
|
||||
}
|
||||
}
|
||||
|
||||
wxwin_patch::~wxwin_patch()
|
||||
{
|
||||
}
|
||||
|
||||
void wxwin_patch::on_patchfile_change(wxCommandEvent& e)
|
||||
{
|
||||
bool ok = true;
|
||||
ok = ok && (patchfile->GetValue().Length() != 0);
|
||||
std::string offsetv = tostdstring(patch_offset->GetValue());
|
||||
try {
|
||||
int32_t offset = boost::lexical_cast<int32_t>(offsetv);
|
||||
} catch(...) {
|
||||
ok = false;
|
||||
}
|
||||
if(dopatch)
|
||||
dopatch->Enable(ok);
|
||||
}
|
||||
|
||||
void wxwin_patch::on_do_patch(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
auto patch_contents = read_file_relative(tostdstring(patchfile->GetValue()), "");
|
||||
size_t patch_index = romname_to_index(*our_rom->rtype, patch_what->GetValue());
|
||||
if(patch_index > 2 * ROMSELECT_ROM_COUNT)
|
||||
throw std::runtime_error("Internal error: Patch WHAT?");
|
||||
loaded_slot& s = get_rom_slot(*our_rom, patch_index);
|
||||
std::string offsetv = tostdstring(patch_offset->GetValue());
|
||||
int32_t offset = boost::lexical_cast<int32_t>(offsetv);
|
||||
s.patch(patch_contents, offset);
|
||||
checksums[patch_index]->SetLabel(towxstring(s.sha256));
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(this, "Error patching ROM", e.what(), wxICON_EXCLAMATION);
|
||||
return;
|
||||
}
|
||||
patchfile->SetValue(wxT(""));
|
||||
}
|
||||
|
||||
void wxwin_patch::on_quit(wxCommandEvent& e)
|
||||
{
|
||||
Close(true);
|
||||
}
|
||||
|
||||
void patching_done(struct loaded_rom& rom, wxWindow* modwin)
|
||||
{
|
||||
struct loaded_rom* our_rom = &rom;
|
||||
try {
|
||||
do_basic_core_init();
|
||||
our_rom_name = "";
|
||||
for(size_t i = 1; i < sizeof(our_rom->romimg) / sizeof(our_rom->romimg[0]); i++)
|
||||
if(our_rom->romimg[i].valid && our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[i].sha256;
|
||||
if(our_rom_name == "")
|
||||
our_rom_name = our_rom->romimg[0].sha256;
|
||||
our_rom->load(1000000000, 0);
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(modwin, "Error loading ROM", e.what(), wxICON_EXCLAMATION);
|
||||
return;
|
||||
}
|
||||
messages << "Detected region: " << our_rom->rtype->combine_region(*our_rom->region).get_name() << std::endl;
|
||||
set_nominal_framerate(our_rom->region->approx_framerate());
|
||||
|
||||
messages << "--- Internal memory mappings ---" << std::endl;
|
||||
dump_region_map();
|
||||
messages << "--- End of Startup --- " << std::endl;
|
||||
wxwin_project* projwin = new wxwin_project(*our_rom);
|
||||
projwin->Show();
|
||||
}
|
||||
|
||||
void wxwin_patch::on_done(wxCommandEvent& e)
|
||||
{
|
||||
patching_done(*our_rom, this);
|
||||
Destroy();
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
|
||||
wxwin_project::wxwin_project(loaded_rom& rom)
|
||||
: wxFrame(NULL, wxID_ANY, wxT("Project settings"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxwin_project::wxwin_project()
|
||||
: wxDialog(NULL, wxID_ANY, wxT("Project settings"), wxDefaultPosition, wxSize(-1, -1),
|
||||
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
|
||||
{
|
||||
our_rom = &rom;
|
||||
std::vector<wxString> cchoices;
|
||||
unsigned dfltidx;
|
||||
|
||||
|
@ -743,27 +219,7 @@ wxwin_project::wxwin_project(loaded_rom& rom)
|
|||
//- Button bar.
|
||||
wxBoxSizer* toplevel = new wxBoxSizer(wxVERTICAL);
|
||||
SetSizer(toplevel);
|
||||
notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP);
|
||||
wxPanel* load_panel = new wxPanel(notebook);
|
||||
wxPanel* new_panel = new wxPanel(notebook);
|
||||
|
||||
//The load page.
|
||||
wxSizer* load_sizer = new wxFlexGridSizer(1, 3, 0, 0);
|
||||
wxSizer* load_sizer2 = new wxBoxSizer(wxVERTICAL);
|
||||
load_panel->SetSizer(load_sizer2);
|
||||
load_sizer2->Add(load_sizer, 0, wxGROW);
|
||||
load_sizer->Add(new wxStaticText(load_panel, wxID_ANY, wxT("File to load:")), 0, wxGROW);
|
||||
load_sizer->Add(savefile = new wxTextCtrl(load_panel, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(500, -1)),
|
||||
1, wxGROW);
|
||||
savefile->SetDropTarget(new textboxloadfilename(savefile));
|
||||
|
||||
load_sizer->Add(ask_savefile = new wxButton(load_panel, ASK_FILENAME_BUTTON, wxT("Pick")), 0, wxGROW);
|
||||
load_sizer2->Add(start_pause = new wxCheckBox(load_panel, wxID_ANY, wxT("Start paused")), 0, wxGROW);
|
||||
savefile->Connect(wxEVT_COMMAND_TEXT_UPDATED,
|
||||
wxCommandEventHandler(wxwin_project::on_filename_change), NULL, this);
|
||||
ask_savefile->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(wxwin_project::on_ask_filename), NULL, this);
|
||||
notebook->AddPage(load_panel, wxT("Load save/movie"));
|
||||
wxPanel* new_panel = new wxPanel(this);
|
||||
|
||||
//The new page.
|
||||
//3 Page-level blocks.
|
||||
|
@ -827,10 +283,7 @@ wxwin_project::wxwin_project(loaded_rom& rom)
|
|||
authors->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(wxwin_project::on_filename_change), NULL,
|
||||
this);
|
||||
|
||||
notebook->Connect(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler(wxwin_project::on_tab_select),
|
||||
NULL, this);
|
||||
notebook->AddPage(new_panel, wxT("New movie"));
|
||||
toplevel->Add(notebook, 1, wxGROW);
|
||||
toplevel->Add(new_panel, 1, wxGROW);
|
||||
|
||||
//Button bar.
|
||||
wxBoxSizer* buttonbar = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
@ -843,25 +296,13 @@ wxwin_project::wxwin_project(loaded_rom& rom)
|
|||
wxCommandEventHandler(wxwin_project::on_quit), NULL, this);
|
||||
toplevel->Add(buttonbar, 0, wxGROW);
|
||||
|
||||
bool file_filled = false;
|
||||
{
|
||||
std::ifstream s(get_config_path() + "/" + our_rom_name + ".ls");
|
||||
std::getline(s, last_save);
|
||||
savefile->SetValue(towxstring(last_save));
|
||||
if(last_save != "")
|
||||
file_filled = true;
|
||||
}
|
||||
|
||||
//This gets re-enabled later if needed.
|
||||
load_file = true;
|
||||
load->Disable();
|
||||
notebook->SetSelection(file_filled ? 0 : 1);
|
||||
wxCommandEvent e2;
|
||||
on_filename_change(e2);
|
||||
|
||||
mainblock->SetSizeHints(this);
|
||||
new_sizer->SetSizeHints(this);
|
||||
load_sizer->SetSizeHints(this);
|
||||
toplevel->SetSizeHints(this);
|
||||
Fit();
|
||||
}
|
||||
|
@ -870,32 +311,11 @@ wxwin_project::~wxwin_project()
|
|||
{
|
||||
}
|
||||
|
||||
void wxwin_project::on_tab_select(wxNotebookEvent& e)
|
||||
{
|
||||
int p = e.GetSelection();
|
||||
if(p < 0) {
|
||||
load->Disable();
|
||||
return;
|
||||
} else if(p == 0) {
|
||||
load_file = true;
|
||||
load->SetLabel(wxT("Load"));
|
||||
} else if(p == 1) {
|
||||
load_file = false;
|
||||
load->SetLabel(wxT("Start"));
|
||||
}
|
||||
wxCommandEvent e2;
|
||||
on_filename_change(e2);
|
||||
e.Skip();
|
||||
}
|
||||
|
||||
void wxwin_project::on_ask_filename(wxCommandEvent& e)
|
||||
{
|
||||
int id = e.GetId();
|
||||
try {
|
||||
if(id == ASK_FILENAME_BUTTON) {
|
||||
std::string fname = pick_file(this, "Choose save/movie", ".");
|
||||
savefile->SetValue(towxstring(fname));
|
||||
} else if(id >= ASK_SRAMS_BASE && id <= ASK_SRAMS_LAST) {
|
||||
if(id >= ASK_SRAMS_BASE && id <= ASK_SRAMS_LAST) {
|
||||
std::string fname = pick_file_member(this, "Choose " + sram_names[id - ASK_SRAMS_BASE], ".");
|
||||
sram_files[sram_names[id - ASK_SRAMS_BASE]]->SetValue(towxstring(fname));
|
||||
}
|
||||
|
@ -906,44 +326,35 @@ void wxwin_project::on_ask_filename(wxCommandEvent& e)
|
|||
|
||||
void wxwin_project::on_filename_change(wxCommandEvent& e)
|
||||
{
|
||||
if(load_file) {
|
||||
load->Enable(savefile->GetValue().Length() != 0);
|
||||
} else {
|
||||
try {
|
||||
boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
|
||||
if(boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue())) < 0)
|
||||
throw 42;
|
||||
size_t lines = authors->GetNumberOfLines();
|
||||
for(size_t i = 0; i < lines; i++) {
|
||||
std::string l = tostdstring(authors->GetLineText(i));
|
||||
if(l == "|")
|
||||
throw 43;
|
||||
}
|
||||
load->Enable();
|
||||
} catch(...) {
|
||||
load->Disable();
|
||||
try {
|
||||
boost::lexical_cast<int64_t>(tostdstring(rtc_sec->GetValue()));
|
||||
if(boost::lexical_cast<int64_t>(tostdstring(rtc_subsec->GetValue())) < 0)
|
||||
throw 42;
|
||||
size_t lines = authors->GetNumberOfLines();
|
||||
for(size_t i = 0; i < lines; i++) {
|
||||
std::string l = tostdstring(authors->GetLineText(i));
|
||||
if(l == "|")
|
||||
throw 43;
|
||||
}
|
||||
load->Enable();
|
||||
} catch(...) {
|
||||
load->Disable();
|
||||
}
|
||||
}
|
||||
|
||||
void wxwin_project::on_quit(wxCommandEvent& e)
|
||||
{
|
||||
Close(true);
|
||||
EndModal(0);
|
||||
}
|
||||
|
||||
void wxwin_project::on_load(wxCommandEvent& e)
|
||||
{
|
||||
try {
|
||||
if(load_file) {
|
||||
moviefile& mov = *new moviefile(tostdstring(savefile->GetValue()));
|
||||
mov.start_paused = start_pause->GetValue();
|
||||
boot_emulator(*our_rom, mov);
|
||||
} else {
|
||||
moviefile& mov = *new moviefile(make_movie());
|
||||
mov.start_paused = start_pause->GetValue();
|
||||
boot_emulator(*our_rom, mov);
|
||||
}
|
||||
Destroy();
|
||||
moviefile mov = make_movie();
|
||||
mov.start_paused = false;
|
||||
mov.save(get_config_path() + "/movie.tmp", 0);
|
||||
platform::queue("load-state " + get_config_path() + "/movie.tmp");
|
||||
EndModal(0);
|
||||
} catch(std::exception& e) {
|
||||
show_message_ok(this, "Error loading movie", e.what(), wxICON_EXCLAMATION);
|
||||
return;
|
||||
|
|
|
@ -6,6 +6,19 @@
|
|||
#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;
|
||||
|
|
Loading…
Add table
Reference in a new issue