mirror of https://github.com/bsnes-emu/bsnes.git
Update to v089r08 release.
byuu says: Changelog: - Super Game Boy, BS-X Satellaview and Sufami Turbo cartridges all load manifests that specify their file names, and they all work - Sufami Turbo can now properly handle carts without RAM, or empty slots entirely - Emulator::Interface structures no longer specify any file names, ever - exposed "capability.(cheats,states)" now. So far, this just means the GBA doesn't show the cheat editor, since it doesn't support cheat codes yet - as such, state manager and cheat editor windows auto-hide (may be a tiny bit inconvenient, but it makes not having to sync them or deal with input when no cart is loaded easier) - added "AbsoluteInput" type, which returns mouse coordinates from -32767,-32767 (top left) to +32767,+32767 (bottom right) or -32768,-32768 (offscreen) AbsoluteInput is just something I'm toying with. Idea is to support eg Super Scope or Justifier, or possibly some future Famicom controllers that are absolute-indexed. The coordinates are scaled, so the bigger your window, the more precise they are. But obviously you can't get more precise than the emulated system, so 1x scale will behave the same anyway. I haven't hooked it up yet, need to mess with the idea of custom cursors via phoenix for that first. Also not sure if it will feel smoother or not ... if you resize the window, your mouse will seem to move slower. Still, not having to capture the mouse for SS/JS may be nicer yet. But we'll see ... just experimenting for now.
This commit is contained in:
parent
9a8a54c75e
commit
189e707594
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "089.07";
|
static const char Version[] = "089.08";
|
||||||
static const char Author[] = "byuu";
|
static const char Author[] = "byuu";
|
||||||
static const char License[] = "GPLv3";
|
static const char License[] = "GPLv3";
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,10 @@ struct Interface {
|
||||||
bool overscan;
|
bool overscan;
|
||||||
double aspectRatio;
|
double aspectRatio;
|
||||||
bool resettable;
|
bool resettable;
|
||||||
|
struct Capability {
|
||||||
|
bool states;
|
||||||
|
bool cheats;
|
||||||
|
} capability;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
struct Media {
|
struct Media {
|
||||||
|
@ -18,7 +22,6 @@ struct Interface {
|
||||||
string name;
|
string name;
|
||||||
string type;
|
string type;
|
||||||
string path;
|
string path;
|
||||||
string extension;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
vector<Media> firmware;
|
vector<Media> firmware;
|
||||||
|
@ -30,7 +33,7 @@ struct Interface {
|
||||||
string name;
|
string name;
|
||||||
struct Input {
|
struct Input {
|
||||||
unsigned id;
|
unsigned id;
|
||||||
unsigned type; //0 = digital, 1 = analog
|
unsigned type; //0 = digital, 1 = analog (relative), 2 = analog (absolute)
|
||||||
string name;
|
string name;
|
||||||
unsigned guid;
|
unsigned guid;
|
||||||
};
|
};
|
||||||
|
@ -46,7 +49,7 @@ struct Interface {
|
||||||
vector<Port> port;
|
vector<Port> port;
|
||||||
|
|
||||||
struct Bind {
|
struct Bind {
|
||||||
virtual void loadRequest(unsigned, const string&, const string&, const string&) {}
|
virtual void loadRequest(unsigned, const string&, const string&) {}
|
||||||
virtual void loadRequest(unsigned, const string&) {}
|
virtual void loadRequest(unsigned, const string&) {}
|
||||||
virtual void saveRequest(unsigned, const string&) {}
|
virtual void saveRequest(unsigned, const string&) {}
|
||||||
virtual uint32_t videoColor(unsigned, uint16_t, uint16_t, uint16_t) { return 0u; }
|
virtual uint32_t videoColor(unsigned, uint16_t, uint16_t, uint16_t) { return 0u; }
|
||||||
|
@ -58,7 +61,7 @@ struct Interface {
|
||||||
} *bind;
|
} *bind;
|
||||||
|
|
||||||
//callback bindings (provided by user interface)
|
//callback bindings (provided by user interface)
|
||||||
void loadRequest(unsigned id, const string &name, const string &type, const string &path) { return bind->loadRequest(id, name, type, path); }
|
void loadRequest(unsigned id, const string &name, const string &type) { return bind->loadRequest(id, name, type); }
|
||||||
void loadRequest(unsigned id, const string &path) { return bind->loadRequest(id, path); }
|
void loadRequest(unsigned id, const string &path) { return bind->loadRequest(id, path); }
|
||||||
void saveRequest(unsigned id, const string &path) { return bind->saveRequest(id, path); }
|
void saveRequest(unsigned id, const string &path) { return bind->saveRequest(id, path); }
|
||||||
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue) { return bind->videoColor(source, red, green, blue); }
|
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue) { return bind->videoColor(source, red, green, blue); }
|
||||||
|
|
|
@ -109,8 +109,10 @@ Interface::Interface() {
|
||||||
information.overscan = true;
|
information.overscan = true;
|
||||||
information.aspectRatio = 8.0 / 7.0;
|
information.aspectRatio = 8.0 / 7.0;
|
||||||
information.resettable = true;
|
information.resettable = true;
|
||||||
|
information.capability.states = true;
|
||||||
|
information.capability.cheats = true;
|
||||||
|
|
||||||
media.append({ID::Famicom, "Famicom", "sys", "program.rom", "fc"});
|
media.append({ID::Famicom, "Famicom", "sys", "fc"});
|
||||||
|
|
||||||
{
|
{
|
||||||
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace GameBoy {
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
void Cartridge::load(System::Revision revision, const string &manifest, bool preloaded) {
|
void Cartridge::load(System::Revision revision, const string &manifest) {
|
||||||
information.markup = manifest;
|
information.markup = manifest;
|
||||||
information.mapper = Mapper::Unknown;
|
information.mapper = Mapper::Unknown;
|
||||||
information.ram = false;
|
information.ram = false;
|
||||||
|
@ -49,7 +49,8 @@ void Cartridge::load(System::Revision revision, const string &manifest, bool pre
|
||||||
ramsize = numeral(ram["size"].data);
|
ramsize = numeral(ram["size"].data);
|
||||||
ramdata = allocate<uint8>(ramsize, 0xff);
|
ramdata = allocate<uint8>(ramsize, 0xff);
|
||||||
|
|
||||||
if(preloaded == false) {
|
//Super Game Boy core loads memory from Super Famicom core
|
||||||
|
if(revision != System::Revision::SuperGameBoy) {
|
||||||
if(rom["name"].exists()) interface->loadRequest(ID::ROM, rom["name"].data);
|
if(rom["name"].exists()) interface->loadRequest(ID::ROM, rom["name"].data);
|
||||||
if(ram["name"].exists()) interface->loadRequest(ID::RAM, ram["name"].data);
|
if(ram["name"].exists()) interface->loadRequest(ID::RAM, ram["name"].data);
|
||||||
if(ram["name"].exists()) memory.append({ID::RAM, ram["name"].data});
|
if(ram["name"].exists()) memory.append({ID::RAM, ram["name"].data});
|
||||||
|
|
|
@ -51,7 +51,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||||
MMIO *mapper;
|
MMIO *mapper;
|
||||||
bool bootrom_enable;
|
bool bootrom_enable;
|
||||||
|
|
||||||
void load(System::Revision revision, const string &manifest, bool preloaded = false);
|
void load(System::Revision revision, const string &manifest);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
uint8 rom_read(unsigned addr);
|
uint8 rom_read(unsigned addr);
|
||||||
|
|
|
@ -120,13 +120,15 @@ Interface::Interface() {
|
||||||
information.overscan = false;
|
information.overscan = false;
|
||||||
information.aspectRatio = 1.0;
|
information.aspectRatio = 1.0;
|
||||||
information.resettable = false;
|
information.resettable = false;
|
||||||
|
information.capability.states = true;
|
||||||
|
information.capability.cheats = true;
|
||||||
|
|
||||||
firmware.append({ID::GameBoyBootROM, "Game Boy", "sys", "boot.rom"});
|
firmware.append({ID::GameBoyBootROM, "Game Boy", "sys", "boot.rom"});
|
||||||
firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "boot.rom"});
|
firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "boot.rom"});
|
||||||
firmware.append({ID::GameBoyColorBootROM, "Game Boy Color", "sys", "boot.rom"});
|
firmware.append({ID::GameBoyColorBootROM, "Game Boy Color", "sys", "boot.rom"});
|
||||||
|
|
||||||
media.append({ID::GameBoy, "Game Boy", "sys", "program.rom", "gb" });
|
media.append({ID::GameBoy, "Game Boy", "sys", "gb" });
|
||||||
media.append({ID::GameBoyColor, "Game Boy Color", "sys", "program.rom", "gbc"});
|
media.append({ID::GameBoyColor, "Game Boy Color", "sys", "gbc"});
|
||||||
|
|
||||||
{
|
{
|
||||||
Device device{0, ID::Device, "Controller"};
|
Device device{0, ID::Device, "Controller"};
|
||||||
|
|
|
@ -101,10 +101,12 @@ Interface::Interface() {
|
||||||
information.overscan = false;
|
information.overscan = false;
|
||||||
information.aspectRatio = 1.0;
|
information.aspectRatio = 1.0;
|
||||||
information.resettable = false;
|
information.resettable = false;
|
||||||
|
information.capability.states = true;
|
||||||
|
information.capability.cheats = false;
|
||||||
|
|
||||||
firmware.append({ID::BIOS, "Game Boy Advance", "sys", "bios.rom"});
|
firmware.append({ID::BIOS, "Game Boy Advance", "sys", "bios.rom"});
|
||||||
|
|
||||||
media.append({ID::GameBoyAdvance, "Game Boy Advance", "sys", "program.rom", "gba"});
|
media.append({ID::GameBoyAdvance, "Game Boy Advance", "sys", "gba"});
|
||||||
|
|
||||||
{
|
{
|
||||||
Device device{0, ID::Device, "Controller"};
|
Device device{0, ID::Device, "Controller"};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<cartridge region="NTSC">
|
<cartridge region="NTSC">
|
||||||
<rom>
|
<rom name="program.rom" size="0x40000">
|
||||||
<map mode="linear" address="00-1f:8000-ffff"/>
|
<map mode="linear" address="00-1f:8000-ffff"/>
|
||||||
<map mode="linear" address="80-9f:8000-ffff"/>
|
<map mode="linear" address="80-9f:8000-ffff"/>
|
||||||
</rom>
|
</rom>
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
<map mode="linear" address="20-3f:8000-ffff"/>
|
<map mode="linear" address="20-3f:8000-ffff"/>
|
||||||
<map mode="linear" address="a0-bf:8000-ffff"/>
|
<map mode="linear" address="a0-bf:8000-ffff"/>
|
||||||
</rom>
|
</rom>
|
||||||
<ram size="131072">
|
<ram>
|
||||||
<map mode="linear" address="60-63:8000-ffff"/>
|
<map mode="linear" address="60-63:8000-ffff"/>
|
||||||
<map mode="linear" address="e0-e3:8000-ffff"/>
|
<map mode="linear" address="e0-e3:8000-ffff"/>
|
||||||
</ram>
|
</ram>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<map mode="linear" address="40-5f:8000-ffff"/>
|
<map mode="linear" address="40-5f:8000-ffff"/>
|
||||||
<map mode="linear" address="c0-df:8000-ffff"/>
|
<map mode="linear" address="c0-df:8000-ffff"/>
|
||||||
</rom>
|
</rom>
|
||||||
<ram size="131072">
|
<ram>
|
||||||
<map mode="linear" address="70-73:8000-ffff"/>
|
<map mode="linear" address="70-73:8000-ffff"/>
|
||||||
<map mode="linear" address="f0-f3:8000-ffff"/>
|
<map mode="linear" address="f0-f3:8000-ffff"/>
|
||||||
</ram>
|
</ram>
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace SuperFamicom {
|
||||||
|
|
||||||
#include "markup.cpp"
|
#include "markup.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
void Cartridge::load(const string &manifest) {
|
void Cartridge::load(const string &manifest) {
|
||||||
|
@ -59,63 +58,63 @@ void Cartridge::load(const string &manifest) {
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::load(const string &markup, const stream &stream) {
|
void Cartridge::load_super_game_boy(const string &manifest) {
|
||||||
rom.copy(stream);
|
XML::Document document(manifest);
|
||||||
|
auto &rom = document["cartridge"]["rom"];
|
||||||
|
auto &ram = document["cartridge"]["ram"];
|
||||||
|
|
||||||
region = Region::NTSC;
|
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, manifest);
|
||||||
//ram_size = 0;
|
|
||||||
|
|
||||||
has_gb_slot = false;
|
if(rom["name"].exists()) interface->loadRequest(ID::SuperGameBoyROM, rom["name"].data);
|
||||||
has_bs_cart = false;
|
if(ram["name"].exists()) interface->loadRequest(ID::SuperGameBoyRAM, ram["name"].data);
|
||||||
has_bs_slot = false;
|
if(ram["name"].exists()) memory.append({ID::SuperGameBoyRAM, ram["name"].data});
|
||||||
has_st_slots = false;
|
|
||||||
has_nss_dip = false;
|
|
||||||
has_sa1 = false;
|
|
||||||
has_superfx = false;
|
|
||||||
has_armdsp = false;
|
|
||||||
has_hitachidsp = false;
|
|
||||||
has_necdsp = false;
|
|
||||||
has_epsonrtc = false;
|
|
||||||
has_sharprtc = false;
|
|
||||||
has_spc7110 = false;
|
|
||||||
has_sdd1 = false;
|
|
||||||
has_obc1 = false;
|
|
||||||
has_msu1 = false;
|
|
||||||
has_link = false;
|
|
||||||
|
|
||||||
parse_markup(markup);
|
|
||||||
//print(markup, "\n\n");
|
|
||||||
|
|
||||||
//Super Game Boy
|
|
||||||
if(cartridge.has_gb_slot()) {
|
|
||||||
sha256 = nall::sha256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Broadcast Satellaview
|
void Cartridge::load_satellaview(const string &manifest) {
|
||||||
else if(cartridge.has_bs_cart() && cartridge.has_bs_slot()) {
|
XML::Document document(manifest);
|
||||||
sha256 = nall::sha256(bsxflash.memory.data(), bsxflash.memory.size());
|
auto &rom = document["cartridge"]["rom"];
|
||||||
|
|
||||||
|
if(rom["name"].exists()) {
|
||||||
|
interface->loadRequest(ID::BsxFlashROM, rom["name"].data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sufami Turbo
|
void Cartridge::load_sufami_turbo_a(const string &manifest) {
|
||||||
else if(cartridge.has_st_slots()) {
|
XML::Document document(manifest);
|
||||||
sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size());
|
auto &rom = document["cartridge"]["rom"];
|
||||||
|
auto &ram = document["cartridge"]["ram"];
|
||||||
|
|
||||||
|
if(rom["name"].exists()) {
|
||||||
|
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].data);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Super Famicom
|
if(ram["name"].exists()) {
|
||||||
else {
|
unsigned size = numeral(ram["size"].data);
|
||||||
sha256 = nall::sha256(rom.data(), rom.size());
|
sufamiturbo.slotA.ram.map(allocate<uint8>(size, 0xff), size);
|
||||||
|
interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].data);
|
||||||
|
memory.append({ID::SufamiTurboSlotARAM, ram["name"].data});
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(ram_size > 0) {
|
if(document["cartridge"]["linkable"].data == "true") {
|
||||||
// ram.map(allocate<uint8>(ram_size, 0xff), ram_size);
|
interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st");
|
||||||
// interface->memory.append({ID::RAM, "save.ram"});
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
rom.write_protect(true);
|
void Cartridge::load_sufami_turbo_b(const string &manifest) {
|
||||||
ram.write_protect(false);
|
XML::Document document(manifest);
|
||||||
|
auto &rom = document["cartridge"]["rom"];
|
||||||
|
auto &ram = document["cartridge"]["ram"];
|
||||||
|
|
||||||
system.load();
|
if(rom["name"].exists()) {
|
||||||
loaded = true;
|
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ram["name"].exists()) {
|
||||||
|
unsigned size = numeral(ram["size"].data);
|
||||||
|
sufamiturbo.slotB.ram.map(allocate<uint8>(size, 0xff), size);
|
||||||
|
interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].data);
|
||||||
|
memory.append({ID::SufamiTurboSlotBRAM, ram["name"].data});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::unload() {
|
void Cartridge::unload() {
|
||||||
|
@ -131,7 +130,6 @@ void Cartridge::unload() {
|
||||||
|
|
||||||
Cartridge::Cartridge() {
|
Cartridge::Cartridge() {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
unload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cartridge::~Cartridge() {
|
Cartridge::~Cartridge() {
|
||||||
|
|
|
@ -63,7 +63,10 @@ struct Cartridge : property<Cartridge> {
|
||||||
vector<Memory> memory;
|
vector<Memory> memory;
|
||||||
|
|
||||||
void load(const string &manifest);
|
void load(const string &manifest);
|
||||||
void load(const string &markup, const stream &stream);
|
void load_super_game_boy(const string &manifest);
|
||||||
|
void load_satellaview(const string &manifest);
|
||||||
|
void load_sufami_turbo_a(const string &manifest);
|
||||||
|
void load_sufami_turbo_b(const string &manifest);
|
||||||
void unload();
|
void unload();
|
||||||
|
|
||||||
void serialize(serializer&);
|
void serialize(serializer&);
|
||||||
|
|
|
@ -103,14 +103,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
|
||||||
if(root.exists() == false) return;
|
if(root.exists() == false) return;
|
||||||
has_gb_slot = true;
|
has_gb_slot = true;
|
||||||
|
|
||||||
//Game Boy requires a cartridge to be loaded ...
|
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb");
|
||||||
//load "empty" cartridge, in case loadRequest() does not load one
|
|
||||||
vector<uint8> stream;
|
|
||||||
stream.resize(32768);
|
|
||||||
for(auto &byte : stream) byte = 0xff;
|
|
||||||
interface->load(ID::SuperGameBoyROM, vectorstream{stream}, "");
|
|
||||||
|
|
||||||
interface->loadRequest(ID::SuperGameBoyROM, "Game Boy", "gb", "program.rom");
|
|
||||||
|
|
||||||
icd2.revision = max(1, numeral(root["revision"].data));
|
icd2.revision = max(1, numeral(root["revision"].data));
|
||||||
|
|
||||||
|
@ -127,7 +120,7 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
|
||||||
has_bs_cart = root["mmio"].exists();
|
has_bs_cart = root["mmio"].exists();
|
||||||
has_bs_slot = true;
|
has_bs_slot = true;
|
||||||
|
|
||||||
interface->loadRequest(ID::BsxFlashROM, "BS-X Satellaview", "bs", "program.rom");
|
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
|
||||||
|
|
||||||
if(has_bs_cart) {
|
if(has_bs_cart) {
|
||||||
parse_markup_memory(bsxcartridge.psram, root["psram"], ID::BsxPSRAM, true);
|
parse_markup_memory(bsxcartridge.psram, root["psram"], ID::BsxPSRAM, true);
|
||||||
|
@ -135,6 +128,8 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
|
||||||
|
|
||||||
for(auto &node : root["slot"]) {
|
for(auto &node : root["slot"]) {
|
||||||
if(node.name != "map") continue;
|
if(node.name != "map") continue;
|
||||||
|
if(bsxflash.memory.size() == 0) continue;
|
||||||
|
|
||||||
Mapping m(bsxflash.memory);
|
Mapping m(bsxflash.memory);
|
||||||
parse_markup_map(m, node);
|
parse_markup_map(m, node);
|
||||||
mapping.append(m);
|
mapping.append(m);
|
||||||
|
@ -159,8 +154,8 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
|
||||||
if(root.exists() == false) return;
|
if(root.exists() == false) return;
|
||||||
has_st_slots = true;
|
has_st_slots = true;
|
||||||
|
|
||||||
interface->loadRequest(ID::SufamiTurboSlotAROM, "Sufami Turbo - Slot A", "st", "program.rom");
|
//load required slot A (will request slot B if slot A cartridge is linkable)
|
||||||
interface->loadRequest(ID::SufamiTurboSlotBROM, "Sufami Turbo - Slot B", "st", "program.rom");
|
interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st");
|
||||||
|
|
||||||
for(auto &slot : root) {
|
for(auto &slot : root) {
|
||||||
if(slot.name != "slot") continue;
|
if(slot.name != "slot") continue;
|
||||||
|
@ -170,6 +165,8 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
|
||||||
for(auto &leaf : node) {
|
for(auto &leaf : node) {
|
||||||
if(leaf.name != "map") continue;
|
if(leaf.name != "map") continue;
|
||||||
SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
|
SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
|
||||||
|
if(memory.size() == 0) continue;
|
||||||
|
|
||||||
Mapping m(memory);
|
Mapping m(memory);
|
||||||
parse_markup_map(m, leaf);
|
parse_markup_map(m, leaf);
|
||||||
if(m.size == 0) m.size = memory.size();
|
if(m.size == 0) m.size = memory.size();
|
||||||
|
@ -181,9 +178,11 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
|
||||||
for(auto &leaf : node) {
|
for(auto &leaf : node) {
|
||||||
if(leaf.name != "map") continue;
|
if(leaf.name != "map") continue;
|
||||||
SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
|
SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
|
||||||
|
if(memory.size() == 0) continue;
|
||||||
|
|
||||||
Mapping m(memory);
|
Mapping m(memory);
|
||||||
parse_markup_map(m, leaf);
|
parse_markup_map(m, leaf);
|
||||||
if(m.size == 0) m.size = ram_size;
|
if(m.size == 0) m.size = memory.size();
|
||||||
if(m.size) mapping.append(m);
|
if(m.size) mapping.append(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,6 @@ namespace SuperFamicom {
|
||||||
SufamiTurbo sufamiturbo;
|
SufamiTurbo sufamiturbo;
|
||||||
|
|
||||||
void SufamiTurbo::load() {
|
void SufamiTurbo::load() {
|
||||||
slotA.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
|
||||||
slotB.ram.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
|
||||||
|
|
||||||
if(slotA.rom.data() == nullptr) {
|
|
||||||
slotA.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(slotB.rom.data() == nullptr) {
|
|
||||||
slotB.rom.map(allocate<uint8>(128 * 1024, 0xff), 128 * 1024);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SufamiTurbo::unload() {
|
void SufamiTurbo::unload() {
|
||||||
|
|
|
@ -34,14 +34,18 @@ unsigned Interface::group(unsigned id) {
|
||||||
case ID::NecDSPRAM:
|
case ID::NecDSPRAM:
|
||||||
case ID::BsxPSRAM:
|
case ID::BsxPSRAM:
|
||||||
return 0;
|
return 0;
|
||||||
|
case ID::SuperGameBoy:
|
||||||
case ID::SuperGameBoyROM:
|
case ID::SuperGameBoyROM:
|
||||||
case ID::SuperGameBoyRAM:
|
case ID::SuperGameBoyRAM:
|
||||||
return 1;
|
return 1;
|
||||||
|
case ID::Satellaview:
|
||||||
case ID::BsxFlashROM:
|
case ID::BsxFlashROM:
|
||||||
return 2;
|
return 2;
|
||||||
|
case ID::SufamiTurboSlotA:
|
||||||
case ID::SufamiTurboSlotAROM:
|
case ID::SufamiTurboSlotAROM:
|
||||||
case ID::SufamiTurboSlotARAM:
|
case ID::SufamiTurboSlotARAM:
|
||||||
return 3;
|
return 3;
|
||||||
|
case ID::SufamiTurboSlotB:
|
||||||
case ID::SufamiTurboSlotBROM:
|
case ID::SufamiTurboSlotBROM:
|
||||||
case ID::SufamiTurboSlotBRAM:
|
case ID::SufamiTurboSlotBRAM:
|
||||||
return 4;
|
return 4;
|
||||||
|
@ -50,7 +54,11 @@ unsigned Interface::group(unsigned id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::load(unsigned id, const string &manifest) {
|
void Interface::load(unsigned id, const string &manifest) {
|
||||||
cartridge.load(manifest);
|
if(id == ID::SuperFamicom) cartridge.load(manifest);
|
||||||
|
if(id == ID::SuperGameBoy) cartridge.load_super_game_boy(manifest);
|
||||||
|
if(id == ID::Satellaview) cartridge.load_satellaview(manifest);
|
||||||
|
if(id == ID::SufamiTurboSlotA) cartridge.load_sufami_turbo_a(manifest);
|
||||||
|
if(id == ID::SufamiTurboSlotB) cartridge.load_sufami_turbo_b(manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::save() {
|
void Interface::save() {
|
||||||
|
@ -107,12 +115,11 @@ void Interface::load(unsigned id, const stream &stream, const string &manifest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::SuperGameBoyROM) {
|
if(id == ID::SuperGameBoyROM) {
|
||||||
GameBoy::interface->load(GameBoy::ID::ROM, stream);
|
stream.read(GameBoy::cartridge.romdata, min(GameBoy::cartridge.romsize, stream.size()));
|
||||||
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, manifest, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::SuperGameBoyRAM) {
|
if(id == ID::SuperGameBoyRAM) {
|
||||||
stream.read(GameBoy::cartridge.ramdata, GameBoy::cartridge.ramsize);
|
stream.read(GameBoy::cartridge.ramdata, min(GameBoy::cartridge.ramsize, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::BsxFlashROM) {
|
if(id == ID::BsxFlashROM) {
|
||||||
|
@ -132,11 +139,11 @@ void Interface::load(unsigned id, const stream &stream, const string &manifest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::SufamiTurboSlotARAM) {
|
if(id == ID::SufamiTurboSlotARAM) {
|
||||||
sufamiturbo.slotA.ram.copy(stream);
|
stream.read(sufamiturbo.slotA.ram.data(), min(sufamiturbo.slotA.ram.size(), stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::SufamiTurboSlotBRAM) {
|
if(id == ID::SufamiTurboSlotBRAM) {
|
||||||
sufamiturbo.slotB.ram.copy(stream);
|
stream.read(sufamiturbo.slotB.ram.data(), min(sufamiturbo.slotB.ram.size(), stream.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,13 +291,15 @@ Interface::Interface() {
|
||||||
information.overscan = true;
|
information.overscan = true;
|
||||||
information.aspectRatio = 8.0 / 7.0;
|
information.aspectRatio = 8.0 / 7.0;
|
||||||
information.resettable = true;
|
information.resettable = true;
|
||||||
|
information.capability.states = true;
|
||||||
|
information.capability.cheats = true;
|
||||||
|
|
||||||
firmware.append({ID::IPLROM, "Super Famicom", "sys", "spc700.rom"});
|
firmware.append({ID::IPLROM, "Super Famicom", "sys", "spc700.rom"});
|
||||||
|
|
||||||
media.append({ID::SuperFamicom, "Super Famicom", "sys", "program.rom", "sfc"});
|
media.append({ID::SuperFamicom, "Super Famicom", "sys", "sfc"});
|
||||||
media.append({ID::SuperFamicom, "Super Game Boy", "sfc", "program.rom", "gb" });
|
media.append({ID::SuperFamicom, "Super Game Boy", "sfc", "gb" });
|
||||||
media.append({ID::SuperFamicom, "BS-X Satellaview", "sfc", "program.rom", "bs" });
|
media.append({ID::SuperFamicom, "BS-X Satellaview", "sfc", "bs" });
|
||||||
media.append({ID::SuperFamicom, "Sufami Turbo", "sfc", "program.rom", "st" });
|
media.append({ID::SuperFamicom, "Sufami Turbo", "sfc", "st" });
|
||||||
|
|
||||||
{
|
{
|
||||||
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||||
|
|
|
@ -4,10 +4,14 @@ namespace SuperFamicom {
|
||||||
|
|
||||||
struct ID {
|
struct ID {
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
|
//cartridges
|
||||||
SuperFamicom,
|
SuperFamicom,
|
||||||
};
|
SuperGameBoy,
|
||||||
|
Satellaview,
|
||||||
|
SufamiTurboSlotA,
|
||||||
|
SufamiTurboSlotB,
|
||||||
|
|
||||||
enum : unsigned {
|
//memory
|
||||||
IPLROM,
|
IPLROM,
|
||||||
|
|
||||||
ROM,
|
ROM,
|
||||||
|
@ -32,9 +36,8 @@ struct ID {
|
||||||
SufamiTurboSlotBROM,
|
SufamiTurboSlotBROM,
|
||||||
SufamiTurboSlotARAM,
|
SufamiTurboSlotARAM,
|
||||||
SufamiTurboSlotBRAM,
|
SufamiTurboSlotBRAM,
|
||||||
};
|
|
||||||
|
|
||||||
enum : unsigned {
|
//controller ports
|
||||||
Port1 = 1,
|
Port1 = 1,
|
||||||
Port2 = 2,
|
Port2 = 2,
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,7 +27,7 @@ void Application::commandLineLoad(string pathname) {
|
||||||
for(auto &emulator : this->emulator) {
|
for(auto &emulator : this->emulator) {
|
||||||
for(auto &media : emulator->media) {
|
for(auto &media : emulator->media) {
|
||||||
if(media.type != "sys") continue;
|
if(media.type != "sys") continue;
|
||||||
if(type != media.extension) continue;
|
if(type != media.path) continue;
|
||||||
return utility->loadMedia(emulator, media, pathname);
|
return utility->loadMedia(emulator, media, pathname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ void Browser::bootstrap() {
|
||||||
for(auto &media : emulator->media) {
|
for(auto &media : emulator->media) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for(auto &folder : folderList) {
|
for(auto &folder : folderList) {
|
||||||
if(folder.extension == media.extension) {
|
if(folder.extension == media.path) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ void Browser::bootstrap() {
|
||||||
if(found == true) continue;
|
if(found == true) continue;
|
||||||
|
|
||||||
Folder folder;
|
Folder folder;
|
||||||
folder.extension = media.extension;
|
folder.extension = media.path;
|
||||||
folder.path = application->basepath;
|
folder.path = application->basepath;
|
||||||
folder.selection = 0;
|
folder.selection = 0;
|
||||||
folderList.append(folder);
|
folderList.append(folder);
|
||||||
|
|
|
@ -28,9 +28,19 @@ void Presentation::synchronize() {
|
||||||
synchronizeVideo.setChecked(config->video.synchronize);
|
synchronizeVideo.setChecked(config->video.synchronize);
|
||||||
synchronizeAudio.setChecked(config->audio.synchronize);
|
synchronizeAudio.setChecked(config->audio.synchronize);
|
||||||
muteAudio.setChecked(config->audio.mute);
|
muteAudio.setChecked(config->audio.mute);
|
||||||
toolsMenu.setVisible(application->active);
|
|
||||||
synchronizeTime.setVisible(application->active && system().rtc());
|
if(application->active == nullptr) {
|
||||||
|
toolsMenu.setVisible(false);
|
||||||
|
} else {
|
||||||
|
toolsMenu.setVisible(true);
|
||||||
|
saveStateMenu.setVisible(system().information.capability.states);
|
||||||
|
loadStateMenu.setVisible(system().information.capability.states);
|
||||||
|
stateMenuSeparator.setVisible(system().information.capability.states);
|
||||||
resizeWindow.setVisible(config->video.scaleMode != 2);
|
resizeWindow.setVisible(config->video.scaleMode != 2);
|
||||||
|
stateManager.setVisible(system().information.capability.states);
|
||||||
|
cheatEditor.setVisible(system().information.capability.cheats);
|
||||||
|
synchronizeTime.setVisible(system().rtc());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Presentation::setSystemName(const string &name) {
|
void Presentation::setSystemName(const string &name) {
|
||||||
|
@ -69,10 +79,10 @@ Presentation::Presentation() : active(nullptr) {
|
||||||
for(unsigned n = 0; n < 5; n++) saveStateItem[n].setText({"Slot ", 1 + n});
|
for(unsigned n = 0; n < 5; n++) saveStateItem[n].setText({"Slot ", 1 + n});
|
||||||
loadStateMenu.setText("Load State");
|
loadStateMenu.setText("Load State");
|
||||||
for(unsigned n = 0; n < 5; n++) loadStateItem[n].setText({"Slot ", 1 + n});
|
for(unsigned n = 0; n < 5; n++) loadStateItem[n].setText({"Slot ", 1 + n});
|
||||||
synchronizeTime.setText("Synchronize Time");
|
|
||||||
resizeWindow.setText("Resize Window");
|
resizeWindow.setText("Resize Window");
|
||||||
cheatEditor.setText("Cheat Editor");
|
|
||||||
stateManager.setText("State Manager");
|
stateManager.setText("State Manager");
|
||||||
|
cheatEditor.setText("Cheat Editor");
|
||||||
|
synchronizeTime.setText("Synchronize Time");
|
||||||
|
|
||||||
append(loadMenu);
|
append(loadMenu);
|
||||||
for(auto &item : loadListSystem) loadMenu.append(*item);
|
for(auto &item : loadListSystem) loadMenu.append(*item);
|
||||||
|
@ -97,9 +107,8 @@ Presentation::Presentation() : active(nullptr) {
|
||||||
for(unsigned n = 0; n < 5; n++) saveStateMenu.append(saveStateItem[n]);
|
for(unsigned n = 0; n < 5; n++) saveStateMenu.append(saveStateItem[n]);
|
||||||
toolsMenu.append(loadStateMenu);
|
toolsMenu.append(loadStateMenu);
|
||||||
for(unsigned n = 0; n < 5; n++) loadStateMenu.append(loadStateItem[n]);
|
for(unsigned n = 0; n < 5; n++) loadStateMenu.append(loadStateItem[n]);
|
||||||
toolsMenu.append(synchronizeTime);
|
|
||||||
toolsMenu.append(stateMenuSeparator);
|
toolsMenu.append(stateMenuSeparator);
|
||||||
toolsMenu.append(resizeWindow, cheatEditor, stateManager);
|
toolsMenu.append(resizeWindow, stateManager, cheatEditor, synchronizeTime);
|
||||||
|
|
||||||
append(layout);
|
append(layout);
|
||||||
layout.append(viewport, {0, 0, 720, 480});
|
layout.append(viewport, {0, 0, 720, 480});
|
||||||
|
@ -120,10 +129,10 @@ Presentation::Presentation() : active(nullptr) {
|
||||||
configurationSettings.onActivate = [&] { settings->setVisible(); settings->panelList.setFocused(); };
|
configurationSettings.onActivate = [&] { settings->setVisible(); settings->panelList.setFocused(); };
|
||||||
for(unsigned n = 0; n < 5; n++) saveStateItem[n].onActivate = [=] { utility->saveState(1 + n); };
|
for(unsigned n = 0; n < 5; n++) saveStateItem[n].onActivate = [=] { utility->saveState(1 + n); };
|
||||||
for(unsigned n = 0; n < 5; n++) loadStateItem[n].onActivate = [=] { utility->loadState(1 + n); };
|
for(unsigned n = 0; n < 5; n++) loadStateItem[n].onActivate = [=] { utility->loadState(1 + n); };
|
||||||
synchronizeTime.onActivate = [&] { system().rtcsync(); };
|
|
||||||
resizeWindow.onActivate = [&] { utility->resize(true); };
|
resizeWindow.onActivate = [&] { utility->resize(true); };
|
||||||
cheatEditor.onActivate = [&] { ::cheatEditor->setVisible(); };
|
|
||||||
stateManager.onActivate = [&] { ::stateManager->setVisible(); };
|
stateManager.onActivate = [&] { ::stateManager->setVisible(); };
|
||||||
|
cheatEditor.onActivate = [&] { ::cheatEditor->setVisible(); };
|
||||||
|
synchronizeTime.onActivate = [&] { system().rtcsync(); };
|
||||||
|
|
||||||
synchronize();
|
synchronize();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,11 +43,11 @@ struct Presentation : Window {
|
||||||
Item saveStateItem[5];
|
Item saveStateItem[5];
|
||||||
Menu loadStateMenu;
|
Menu loadStateMenu;
|
||||||
Item loadStateItem[5];
|
Item loadStateItem[5];
|
||||||
Item synchronizeTime;
|
|
||||||
Separator stateMenuSeparator;
|
Separator stateMenuSeparator;
|
||||||
Item resizeWindow;
|
Item resizeWindow;
|
||||||
Item cheatEditor;
|
|
||||||
Item stateManager;
|
Item stateManager;
|
||||||
|
Item cheatEditor;
|
||||||
|
Item synchronizeTime;
|
||||||
|
|
||||||
void synchronize();
|
void synchronize();
|
||||||
void setSystemName(const string &name);
|
void setSystemName(const string &name);
|
||||||
|
|
|
@ -102,7 +102,7 @@ int16_t DigitalInput::poll() {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
bool AnalogInput::bind(unsigned scancode, int16_t value) {
|
bool RelativeInput::bind(unsigned scancode, int16_t value) {
|
||||||
using nall::Keyboard;
|
using nall::Keyboard;
|
||||||
using nall::Mouse;
|
using nall::Mouse;
|
||||||
|
|
||||||
|
@ -118,16 +118,9 @@ bool AnalogInput::bind(unsigned scancode, int16_t value) {
|
||||||
if(Joypad::isAnyAxis(scancode)) return append(encode);
|
if(Joypad::isAnyAxis(scancode)) return append(encode);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
append:
|
|
||||||
if(mapping.position(encode)) return false; //mapping already bound
|
|
||||||
if(mapping.empty() || mapping == "None") mapping = encode; //remove "None"
|
|
||||||
else mapping.append(",", encode); //add to existing mapping list
|
|
||||||
AbstractInput::bind();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t AnalogInput::poll() {
|
int16_t RelativeInput::poll() {
|
||||||
int16_t result = 0;
|
int16_t result = 0;
|
||||||
|
|
||||||
for(auto &item : inputList) {
|
for(auto &item : inputList) {
|
||||||
|
@ -144,6 +137,76 @@ int16_t AnalogInput::poll() {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
bool AbsoluteInput::bind(unsigned scancode, int16_t value) {
|
||||||
|
using nall::Keyboard;
|
||||||
|
using nall::Mouse;
|
||||||
|
|
||||||
|
if(scancode == Scancode::None || scancode == keyboard(0)[Keyboard::Escape]) {
|
||||||
|
inputList.reset();
|
||||||
|
mapping = "None";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
string encode = Scancode::encode(scancode);
|
||||||
|
|
||||||
|
if(Mouse::isAnyAxis(scancode)) {
|
||||||
|
//only one input can be assigned for absolute positioning
|
||||||
|
inputList.reset();
|
||||||
|
mapping = encode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t AbsoluteInput::poll() {
|
||||||
|
int16_t result = -32768; //offscreen value
|
||||||
|
|
||||||
|
using nall::Mouse;
|
||||||
|
|
||||||
|
Position position = phoenix::Mouse::position();
|
||||||
|
Geometry geometry = presentation->geometry();
|
||||||
|
|
||||||
|
if(position.x < geometry.x
|
||||||
|
|| position.y < geometry.y
|
||||||
|
|| position.x >= geometry.x + geometry.width
|
||||||
|
|| position.y >= geometry.y + geometry.height) {
|
||||||
|
//cursor is offscreen
|
||||||
|
position.x = -32768;
|
||||||
|
position.y = -32768;
|
||||||
|
} else {
|
||||||
|
//convert from screen to viewport coordinates
|
||||||
|
double x = position.x - geometry.x;
|
||||||
|
double y = position.y - geometry.y;
|
||||||
|
|
||||||
|
//scale coordinate range to -0.5 to +0.5 (0.0 = center)
|
||||||
|
x = x * 1.0 / geometry.width - 0.5;
|
||||||
|
y = y * 1.0 / geometry.height - 0.5;
|
||||||
|
|
||||||
|
//scale coordinates to -32767 to +32767
|
||||||
|
signed px = (signed)(x * 65535.0);
|
||||||
|
signed py = (signed)(y * 65535.0);
|
||||||
|
|
||||||
|
//clamp to valid range
|
||||||
|
position.x = max(-32767, min(+32767, px));
|
||||||
|
position.y = max(-32767, min(+32767, py));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &item : inputList) {
|
||||||
|
if(item.scancode == mouse(0)[Mouse::Xaxis]) {
|
||||||
|
result = position.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(item.scancode == mouse(0)[Mouse::Yaxis]) {
|
||||||
|
result = position.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
HotkeyInput::HotkeyInput() {
|
HotkeyInput::HotkeyInput() {
|
||||||
logic = 1; //AND
|
logic = 1; //AND
|
||||||
inputManager->hotkeyMap.append(this);
|
inputManager->hotkeyMap.append(this);
|
||||||
|
@ -201,8 +264,9 @@ void InputManager::bootstrap() {
|
||||||
|
|
||||||
AbstractInput *abstract = nullptr;
|
AbstractInput *abstract = nullptr;
|
||||||
if(input.type == 0) abstract = new DigitalInput;
|
if(input.type == 0) abstract = new DigitalInput;
|
||||||
if(input.type == 1) abstract = new AnalogInput;
|
if(input.type == 1) abstract = new RelativeInput;
|
||||||
if(input.type >= 2) continue;
|
if(input.type == 2) abstract = new AbsoluteInput;
|
||||||
|
if(input.type >= 3) continue;
|
||||||
|
|
||||||
abstract->name = {emulator->information.name, "::", port.name, "::", device.name, "::", input.name};
|
abstract->name = {emulator->information.name, "::", port.name, "::", device.name, "::", input.name};
|
||||||
abstract->name.replace(" ", "");
|
abstract->name.replace(" ", "");
|
||||||
|
|
|
@ -23,7 +23,13 @@ struct DigitalInput : AbstractInput {
|
||||||
int16_t poll();
|
int16_t poll();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AnalogInput : AbstractInput {
|
struct RelativeInput : AbstractInput {
|
||||||
|
using AbstractInput::bind;
|
||||||
|
bool bind(unsigned scancode, int16_t value);
|
||||||
|
int16_t poll();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AbsoluteInput : AbstractInput {
|
||||||
using AbstractInput::bind;
|
using AbstractInput::bind;
|
||||||
bool bind(unsigned scancode, int16_t value);
|
bool bind(unsigned scancode, int16_t value);
|
||||||
int16_t poll();
|
int16_t poll();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "../ethos.hpp"
|
#include "../ethos.hpp"
|
||||||
Interface *interface = nullptr;
|
Interface *interface = nullptr;
|
||||||
|
|
||||||
void Interface::loadRequest(unsigned id, const string &name, const string &type, const string &path) {
|
void Interface::loadRequest(unsigned id, const string &name, const string &type) {
|
||||||
return utility->loadRequest(id, name, type, path);
|
return utility->loadRequest(id, name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::loadRequest(unsigned id, const string &path) {
|
void Interface::loadRequest(unsigned id, const string &path) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
struct Interface : Emulator::Interface::Bind {
|
struct Interface : Emulator::Interface::Bind {
|
||||||
|
void loadRequest(unsigned id, const string &name, const string &type);
|
||||||
void loadRequest(unsigned id, const string &path);
|
void loadRequest(unsigned id, const string &path);
|
||||||
void saveRequest(unsigned id, const string &path);
|
void saveRequest(unsigned id, const string &path);
|
||||||
void loadRequest(unsigned id, const string &name, const string &type, const string &path);
|
|
||||||
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue);
|
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue);
|
||||||
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height);
|
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height);
|
||||||
void audioSample(int16_t lsample, int16_t rsample);
|
void audioSample(int16_t lsample, int16_t rsample);
|
||||||
|
|
|
@ -72,7 +72,8 @@ void InputSettings::synchronize() {
|
||||||
assign[2].setVisible(true);
|
assign[2].setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dynamic_cast<AnalogInput*>(selectedInput)) {
|
if(dynamic_cast<RelativeInput*>(selectedInput)
|
||||||
|
|| dynamic_cast<AbsoluteInput*>(selectedInput)) {
|
||||||
assign[0].setText("Mouse X-axis");
|
assign[0].setText("Mouse X-axis");
|
||||||
assign[1].setText("Mouse Y-axis");
|
assign[1].setText("Mouse Y-axis");
|
||||||
assign[0].setVisible(true);
|
assign[0].setVisible(true);
|
||||||
|
@ -170,7 +171,8 @@ void InputSettings::assignMouseInput(unsigned n) {
|
||||||
return inputEvent(mouse(0).button(n), 1, true);
|
return inputEvent(mouse(0).button(n), 1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dynamic_cast<AnalogInput*>(activeInput)) {
|
if(dynamic_cast<RelativeInput*>(activeInput)
|
||||||
|
|| dynamic_cast<AbsoluteInput*>(activeInput)) {
|
||||||
return inputEvent(mouse(0).axis(n), 1, true);
|
return inputEvent(mouse(0).axis(n), 1, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ void Utility::setInterface(Emulator::Interface *emulator) {
|
||||||
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media) {
|
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media) {
|
||||||
string pathname;
|
string pathname;
|
||||||
if(media.type != "sys") pathname = application->path({media.name, ".", media.type, "/"});
|
if(media.type != "sys") pathname = application->path({media.name, ".", media.type, "/"});
|
||||||
if(!directory::exists(pathname)) pathname = browser->select({"Load ", media.name}, media.extension);
|
if(!directory::exists(pathname)) pathname = browser->select({"Load ", media.name}, media.path);
|
||||||
if(!directory::exists(pathname)) return;
|
if(!directory::exists(pathname)) return;
|
||||||
if(!file::exists({pathname, "manifest.xml"})) return;
|
if(!file::exists({pathname, "manifest.xml"})) return;
|
||||||
loadMedia(emulator, media, pathname);
|
loadMedia(emulator, media, pathname);
|
||||||
|
@ -35,7 +35,7 @@ void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Medi
|
||||||
}
|
}
|
||||||
|
|
||||||
//request from emulation core to load non-volatile media folder
|
//request from emulation core to load non-volatile media folder
|
||||||
void Utility::loadRequest(unsigned id, const string &name, const string &type, const string &path) {
|
void Utility::loadRequest(unsigned id, const string &name, const string &type) {
|
||||||
string pathname = browser->select({"Load ", name}, type);
|
string pathname = browser->select({"Load ", name}, type);
|
||||||
if(pathname.empty()) return;
|
if(pathname.empty()) return;
|
||||||
this->path(system().group(id)) = pathname;
|
this->path(system().group(id)) = pathname;
|
||||||
|
@ -43,8 +43,7 @@ void Utility::loadRequest(unsigned id, const string &name, const string &type, c
|
||||||
|
|
||||||
string manifest;
|
string manifest;
|
||||||
manifest.readfile({pathname, "manifest.xml"});
|
manifest.readfile({pathname, "manifest.xml"});
|
||||||
mmapstream stream({pathname, path});
|
system().load(id, manifest);
|
||||||
system().load(id, stream, manifest);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//request from emulation core to load non-volatile media file
|
//request from emulation core to load non-volatile media file
|
||||||
|
@ -62,29 +61,6 @@ void Utility::saveRequest(unsigned id, const string &path) {
|
||||||
return system().save(id, stream);
|
return system().save(id, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utility::loadMemory() {
|
|
||||||
// for(auto &memory : system().memory) {
|
|
||||||
// string pathname = path(system().group(memory.id));
|
|
||||||
// if(file::exists({pathname, memory.name}) == false) continue;
|
|
||||||
// filestream fs({pathname, memory.name});
|
|
||||||
// system().load(memory.id, fs);
|
|
||||||
// }
|
|
||||||
|
|
||||||
cheatEditor->load({pathname[0], "cheats.xml"});
|
|
||||||
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Utility::saveMemory() {
|
|
||||||
// for(auto &memory : system().memory) {
|
|
||||||
// string pathname = path(system().group(memory.id));
|
|
||||||
// filestream fs({pathname, memory.name}, file::mode::write);
|
|
||||||
// system().save(memory.id, fs);
|
|
||||||
// }
|
|
||||||
|
|
||||||
cheatEditor->save({pathname[0], "cheats.xml"});
|
|
||||||
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Utility::connect(unsigned port, unsigned device) {
|
void Utility::connect(unsigned port, unsigned device) {
|
||||||
if(application->active == nullptr) return;
|
if(application->active == nullptr) return;
|
||||||
system().connect(port, device);
|
system().connect(port, device);
|
||||||
|
@ -110,7 +86,8 @@ void Utility::load() {
|
||||||
title.rtrim<1>(" + ");
|
title.rtrim<1>(" + ");
|
||||||
presentation->setTitle(title);
|
presentation->setTitle(title);
|
||||||
|
|
||||||
loadMemory();
|
cheatEditor->load({pathname[0], "cheats.xml"});
|
||||||
|
stateManager->load({pathname[0], "bsnes/states.bsa"}, 1);
|
||||||
|
|
||||||
system().paletteUpdate();
|
system().paletteUpdate();
|
||||||
synchronizeDSP();
|
synchronizeDSP();
|
||||||
|
@ -124,7 +101,9 @@ void Utility::unload() {
|
||||||
if(application->active == nullptr) return;
|
if(application->active == nullptr) return;
|
||||||
if(tracerEnable) tracerToggle();
|
if(tracerEnable) tracerToggle();
|
||||||
|
|
||||||
saveMemory();
|
cheatEditor->save({pathname[0], "cheats.xml"});
|
||||||
|
stateManager->save({pathname[0], "bsnes/states.bsa"}, 1);
|
||||||
|
|
||||||
system().unload();
|
system().unload();
|
||||||
path.reset();
|
path.reset();
|
||||||
pathname.reset();
|
pathname.reset();
|
||||||
|
@ -135,8 +114,9 @@ void Utility::unload() {
|
||||||
video.clear();
|
video.clear();
|
||||||
audio.clear();
|
audio.clear();
|
||||||
presentation->setTitle({Emulator::Name, " v", Emulator::Version});
|
presentation->setTitle({Emulator::Name, " v", Emulator::Version});
|
||||||
cheatEditor->synchronize();
|
cheatDatabase->setVisible(false);
|
||||||
stateManager->synchronize();
|
cheatEditor->setVisible(false);
|
||||||
|
stateManager->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utility::saveState(unsigned slot) {
|
void Utility::saveState(unsigned slot) {
|
||||||
|
|
|
@ -4,11 +4,9 @@ struct Utility {
|
||||||
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media);
|
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media);
|
||||||
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media, const string &pathname);
|
void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media, const string &pathname);
|
||||||
|
|
||||||
void loadRequest(unsigned id, const string &name, const string &type, const string &path);
|
void loadRequest(unsigned id, const string &name, const string &type);
|
||||||
void loadRequest(unsigned id, const string &path);
|
void loadRequest(unsigned id, const string &path);
|
||||||
void saveRequest(unsigned id, const string &path);
|
void saveRequest(unsigned id, const string &path);
|
||||||
void loadMemory();
|
|
||||||
void saveMemory();
|
|
||||||
|
|
||||||
void connect(unsigned port, unsigned device);
|
void connect(unsigned port, unsigned device);
|
||||||
void power();
|
void power();
|
||||||
|
|
Loading…
Reference in New Issue