Revamp ROM loading

This commit is contained in:
Ilari Liusvaara 2012-08-24 20:24:18 +03:00
parent d1210efe03
commit e83e4eb4e1
17 changed files with 450 additions and 1050 deletions

View file

@ -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.
*

View file

@ -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

View file

@ -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;
};

View file

@ -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.
*/

View file

@ -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);

View file

@ -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;

View file

@ -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) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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]);

View file

@ -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");
}

View file

@ -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, &region));

View file

@ -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()

View file

@ -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;
}

View file

@ -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;
};
}

View file

@ -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 = &region_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;

View file

@ -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;