From 189e7075947ec8fb53d374da22ddca7bd9cda6f0 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Mon, 28 May 2012 09:50:50 +1000 Subject: [PATCH] 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. --- bsnes/emulator/emulator.hpp | 2 +- bsnes/emulator/interface.hpp | 11 ++- bsnes/fc/interface/interface.cpp | 4 +- bsnes/gb/cartridge/cartridge.cpp | 5 +- bsnes/gb/cartridge/cartridge.hpp | 2 +- bsnes/gb/interface/interface.cpp | 6 +- bsnes/gba/interface/interface.cpp | 4 +- bsnes/profile/Sufami Turbo.sfc/manifest.xml | 6 +- bsnes/sfc/cartridge/cartridge.cpp | 94 ++++++++++----------- bsnes/sfc/cartridge/cartridge.hpp | 5 +- bsnes/sfc/cartridge/markup.cpp | 23 +++-- bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp | 10 --- bsnes/sfc/interface/interface.cpp | 29 ++++--- bsnes/sfc/interface/interface.hpp | 11 ++- bsnes/target-ethos/ethos.cpp | 2 +- bsnes/target-ethos/general/browser.cpp | 4 +- bsnes/target-ethos/general/presentation.cpp | 27 ++++-- bsnes/target-ethos/general/presentation.hpp | 4 +- bsnes/target-ethos/input/input.cpp | 86 ++++++++++++++++--- bsnes/target-ethos/input/input.hpp | 8 +- bsnes/target-ethos/interface/interface.cpp | 4 +- bsnes/target-ethos/interface/interface.hpp | 2 +- bsnes/target-ethos/settings/input.cpp | 6 +- bsnes/target-ethos/utility/utility.cpp | 42 +++------ bsnes/target-ethos/utility/utility.hpp | 4 +- 25 files changed, 236 insertions(+), 165 deletions(-) diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index 8348d070..4e55060d 100755 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { 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 License[] = "GPLv3"; } diff --git a/bsnes/emulator/interface.hpp b/bsnes/emulator/interface.hpp index 92c7d382..f0d1ca79 100755 --- a/bsnes/emulator/interface.hpp +++ b/bsnes/emulator/interface.hpp @@ -11,6 +11,10 @@ struct Interface { bool overscan; double aspectRatio; bool resettable; + struct Capability { + bool states; + bool cheats; + } capability; } information; struct Media { @@ -18,7 +22,6 @@ struct Interface { string name; string type; string path; - string extension; }; vector firmware; @@ -30,7 +33,7 @@ struct Interface { string name; struct Input { unsigned id; - unsigned type; //0 = digital, 1 = analog + unsigned type; //0 = digital, 1 = analog (relative), 2 = analog (absolute) string name; unsigned guid; }; @@ -46,7 +49,7 @@ struct Interface { vector port; 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 saveRequest(unsigned, const string&) {} virtual uint32_t videoColor(unsigned, uint16_t, uint16_t, uint16_t) { return 0u; } @@ -58,7 +61,7 @@ struct Interface { } *bind; //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 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); } diff --git a/bsnes/fc/interface/interface.cpp b/bsnes/fc/interface/interface.cpp index a049e051..d15e37e6 100755 --- a/bsnes/fc/interface/interface.cpp +++ b/bsnes/fc/interface/interface.cpp @@ -109,8 +109,10 @@ Interface::Interface() { information.overscan = true; information.aspectRatio = 8.0 / 7.0; 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"}; diff --git a/bsnes/gb/cartridge/cartridge.cpp b/bsnes/gb/cartridge/cartridge.cpp index 3cb92d05..062f975e 100755 --- a/bsnes/gb/cartridge/cartridge.cpp +++ b/bsnes/gb/cartridge/cartridge.cpp @@ -14,7 +14,7 @@ namespace GameBoy { #include "serialization.cpp" 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.mapper = Mapper::Unknown; information.ram = false; @@ -49,7 +49,8 @@ void Cartridge::load(System::Revision revision, const string &manifest, bool pre ramsize = numeral(ram["size"].data); ramdata = allocate(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(ram["name"].exists()) interface->loadRequest(ID::RAM, ram["name"].data); if(ram["name"].exists()) memory.append({ID::RAM, ram["name"].data}); diff --git a/bsnes/gb/cartridge/cartridge.hpp b/bsnes/gb/cartridge/cartridge.hpp index 992f19cd..90640ce3 100755 --- a/bsnes/gb/cartridge/cartridge.hpp +++ b/bsnes/gb/cartridge/cartridge.hpp @@ -51,7 +51,7 @@ struct Cartridge : MMIO, property { MMIO *mapper; bool bootrom_enable; - void load(System::Revision revision, const string &manifest, bool preloaded = false); + void load(System::Revision revision, const string &manifest); void unload(); uint8 rom_read(unsigned addr); diff --git a/bsnes/gb/interface/interface.cpp b/bsnes/gb/interface/interface.cpp index 7667f7b8..507e5dce 100755 --- a/bsnes/gb/interface/interface.cpp +++ b/bsnes/gb/interface/interface.cpp @@ -120,13 +120,15 @@ Interface::Interface() { information.overscan = false; information.aspectRatio = 1.0; information.resettable = false; + information.capability.states = true; + information.capability.cheats = true; firmware.append({ID::GameBoyBootROM, "Game Boy", "sys", "boot.rom"}); firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "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::GameBoyColor, "Game Boy Color", "sys", "program.rom", "gbc"}); + media.append({ID::GameBoy, "Game Boy", "sys", "gb" }); + media.append({ID::GameBoyColor, "Game Boy Color", "sys", "gbc"}); { Device device{0, ID::Device, "Controller"}; diff --git a/bsnes/gba/interface/interface.cpp b/bsnes/gba/interface/interface.cpp index 79c53085..ad9b4871 100755 --- a/bsnes/gba/interface/interface.cpp +++ b/bsnes/gba/interface/interface.cpp @@ -101,10 +101,12 @@ Interface::Interface() { information.overscan = false; information.aspectRatio = 1.0; information.resettable = false; + information.capability.states = true; + information.capability.cheats = false; 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"}; diff --git a/bsnes/profile/Sufami Turbo.sfc/manifest.xml b/bsnes/profile/Sufami Turbo.sfc/manifest.xml index e426b806..7fb246dc 100755 --- a/bsnes/profile/Sufami Turbo.sfc/manifest.xml +++ b/bsnes/profile/Sufami Turbo.sfc/manifest.xml @@ -1,6 +1,6 @@ - + @@ -10,7 +10,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/bsnes/sfc/cartridge/cartridge.cpp b/bsnes/sfc/cartridge/cartridge.cpp index 4e79c734..a9e65f19 100755 --- a/bsnes/sfc/cartridge/cartridge.cpp +++ b/bsnes/sfc/cartridge/cartridge.cpp @@ -5,7 +5,6 @@ namespace SuperFamicom { #include "markup.cpp" #include "serialization.cpp" - Cartridge cartridge; void Cartridge::load(const string &manifest) { @@ -59,63 +58,63 @@ void Cartridge::load(const string &manifest) { loaded = true; } -void Cartridge::load(const string &markup, const stream &stream) { - rom.copy(stream); +void Cartridge::load_super_game_boy(const string &manifest) { + XML::Document document(manifest); + auto &rom = document["cartridge"]["rom"]; + auto &ram = document["cartridge"]["ram"]; - region = Region::NTSC; -//ram_size = 0; + GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, manifest); - has_gb_slot = false; - has_bs_cart = false; - has_bs_slot = false; - 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; + if(rom["name"].exists()) interface->loadRequest(ID::SuperGameBoyROM, rom["name"].data); + if(ram["name"].exists()) interface->loadRequest(ID::SuperGameBoyRAM, ram["name"].data); + if(ram["name"].exists()) memory.append({ID::SuperGameBoyRAM, ram["name"].data}); +} - parse_markup(markup); -//print(markup, "\n\n"); +void Cartridge::load_satellaview(const string &manifest) { + XML::Document document(manifest); + auto &rom = document["cartridge"]["rom"]; - //Super Game Boy - if(cartridge.has_gb_slot()) { - sha256 = nall::sha256(GameBoy::cartridge.romdata, GameBoy::cartridge.romsize); + if(rom["name"].exists()) { + interface->loadRequest(ID::BsxFlashROM, rom["name"].data); + } +} + +void Cartridge::load_sufami_turbo_a(const string &manifest) { + XML::Document document(manifest); + auto &rom = document["cartridge"]["rom"]; + auto &ram = document["cartridge"]["ram"]; + + if(rom["name"].exists()) { + interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].data); } - //Broadcast Satellaview - else if(cartridge.has_bs_cart() && cartridge.has_bs_slot()) { - sha256 = nall::sha256(bsxflash.memory.data(), bsxflash.memory.size()); + if(ram["name"].exists()) { + unsigned size = numeral(ram["size"].data); + sufamiturbo.slotA.ram.map(allocate(size, 0xff), size); + interface->loadRequest(ID::SufamiTurboSlotARAM, ram["name"].data); + memory.append({ID::SufamiTurboSlotARAM, ram["name"].data}); } - //Sufami Turbo - else if(cartridge.has_st_slots()) { - sha256 = nall::sha256(sufamiturbo.slotA.rom.data(), sufamiturbo.slotA.rom.size()); + if(document["cartridge"]["linkable"].data == "true") { + interface->loadRequest(ID::SufamiTurboSlotB, "Sufami Turbo - Slot B", "st"); + } +} + +void Cartridge::load_sufami_turbo_b(const string &manifest) { + XML::Document document(manifest); + auto &rom = document["cartridge"]["rom"]; + auto &ram = document["cartridge"]["ram"]; + + if(rom["name"].exists()) { + interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].data); } - //Super Famicom - else { - sha256 = nall::sha256(rom.data(), rom.size()); + if(ram["name"].exists()) { + unsigned size = numeral(ram["size"].data); + sufamiturbo.slotB.ram.map(allocate(size, 0xff), size); + interface->loadRequest(ID::SufamiTurboSlotBRAM, ram["name"].data); + memory.append({ID::SufamiTurboSlotBRAM, ram["name"].data}); } - -// if(ram_size > 0) { -// ram.map(allocate(ram_size, 0xff), ram_size); -// interface->memory.append({ID::RAM, "save.ram"}); -// } - - rom.write_protect(true); - ram.write_protect(false); - - system.load(); - loaded = true; } void Cartridge::unload() { @@ -131,7 +130,6 @@ void Cartridge::unload() { Cartridge::Cartridge() { loaded = false; - unload(); } Cartridge::~Cartridge() { diff --git a/bsnes/sfc/cartridge/cartridge.hpp b/bsnes/sfc/cartridge/cartridge.hpp index 2a8eb695..c14de4e0 100755 --- a/bsnes/sfc/cartridge/cartridge.hpp +++ b/bsnes/sfc/cartridge/cartridge.hpp @@ -63,7 +63,10 @@ struct Cartridge : property { vector memory; 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 serialize(serializer&); diff --git a/bsnes/sfc/cartridge/markup.cpp b/bsnes/sfc/cartridge/markup.cpp index 03ef7efc..2e00fe1e 100755 --- a/bsnes/sfc/cartridge/markup.cpp +++ b/bsnes/sfc/cartridge/markup.cpp @@ -103,14 +103,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) { if(root.exists() == false) return; has_gb_slot = true; - //Game Boy requires a cartridge to be loaded ... - //load "empty" cartridge, in case loadRequest() does not load one - vector 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"); + interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb"); 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_slot = true; - interface->loadRequest(ID::BsxFlashROM, "BS-X Satellaview", "bs", "program.rom"); + interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs"); if(has_bs_cart) { 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"]) { if(node.name != "map") continue; + if(bsxflash.memory.size() == 0) continue; + Mapping m(bsxflash.memory); parse_markup_map(m, node); mapping.append(m); @@ -159,8 +154,8 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) { if(root.exists() == false) return; has_st_slots = true; - interface->loadRequest(ID::SufamiTurboSlotAROM, "Sufami Turbo - Slot A", "st", "program.rom"); - interface->loadRequest(ID::SufamiTurboSlotBROM, "Sufami Turbo - Slot B", "st", "program.rom"); + //load required slot A (will request slot B if slot A cartridge is linkable) + interface->loadRequest(ID::SufamiTurboSlotA, "Sufami Turbo - Slot A", "st"); for(auto &slot : root) { if(slot.name != "slot") continue; @@ -170,6 +165,8 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) { for(auto &leaf : node) { if(leaf.name != "map") continue; SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom; + if(memory.size() == 0) continue; + Mapping m(memory); parse_markup_map(m, leaf); if(m.size == 0) m.size = memory.size(); @@ -181,9 +178,11 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) { for(auto &leaf : node) { if(leaf.name != "map") continue; SuperFamicom::Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram; + if(memory.size() == 0) continue; + Mapping m(memory); 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); } } diff --git a/bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp b/bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp index 2870799d..ac7236d2 100755 --- a/bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp +++ b/bsnes/sfc/chip/sufamiturbo/sufamiturbo.cpp @@ -7,16 +7,6 @@ namespace SuperFamicom { SufamiTurbo sufamiturbo; void SufamiTurbo::load() { - slotA.ram.map(allocate(128 * 1024, 0xff), 128 * 1024); - slotB.ram.map(allocate(128 * 1024, 0xff), 128 * 1024); - - if(slotA.rom.data() == nullptr) { - slotA.rom.map(allocate(128 * 1024, 0xff), 128 * 1024); - } - - if(slotB.rom.data() == nullptr) { - slotB.rom.map(allocate(128 * 1024, 0xff), 128 * 1024); - } } void SufamiTurbo::unload() { diff --git a/bsnes/sfc/interface/interface.cpp b/bsnes/sfc/interface/interface.cpp index c39d11aa..971a858a 100755 --- a/bsnes/sfc/interface/interface.cpp +++ b/bsnes/sfc/interface/interface.cpp @@ -34,14 +34,18 @@ unsigned Interface::group(unsigned id) { case ID::NecDSPRAM: case ID::BsxPSRAM: return 0; + case ID::SuperGameBoy: case ID::SuperGameBoyROM: case ID::SuperGameBoyRAM: return 1; + case ID::Satellaview: case ID::BsxFlashROM: return 2; + case ID::SufamiTurboSlotA: case ID::SufamiTurboSlotAROM: case ID::SufamiTurboSlotARAM: return 3; + case ID::SufamiTurboSlotB: case ID::SufamiTurboSlotBROM: case ID::SufamiTurboSlotBRAM: return 4; @@ -50,7 +54,11 @@ unsigned Interface::group(unsigned id) { } 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() { @@ -107,12 +115,11 @@ void Interface::load(unsigned id, const stream &stream, const string &manifest) } if(id == ID::SuperGameBoyROM) { - GameBoy::interface->load(GameBoy::ID::ROM, stream); - GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, manifest, true); + stream.read(GameBoy::cartridge.romdata, min(GameBoy::cartridge.romsize, stream.size())); } 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) { @@ -132,11 +139,11 @@ void Interface::load(unsigned id, const stream &stream, const string &manifest) } 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) { - 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.aspectRatio = 8.0 / 7.0; information.resettable = true; + information.capability.states = true; + information.capability.cheats = true; firmware.append({ID::IPLROM, "Super Famicom", "sys", "spc700.rom"}); - media.append({ID::SuperFamicom, "Super Famicom", "sys", "program.rom", "sfc"}); - media.append({ID::SuperFamicom, "Super Game Boy", "sfc", "program.rom", "gb" }); - media.append({ID::SuperFamicom, "BS-X Satellaview", "sfc", "program.rom", "bs" }); - media.append({ID::SuperFamicom, "Sufami Turbo", "sfc", "program.rom", "st" }); + media.append({ID::SuperFamicom, "Super Famicom", "sys", "sfc"}); + media.append({ID::SuperFamicom, "Super Game Boy", "sfc", "gb" }); + media.append({ID::SuperFamicom, "BS-X Satellaview", "sfc", "bs" }); + media.append({ID::SuperFamicom, "Sufami Turbo", "sfc", "st" }); { Device device{0, ID::Port1 | ID::Port2, "Controller"}; diff --git a/bsnes/sfc/interface/interface.hpp b/bsnes/sfc/interface/interface.hpp index e1c0f704..2b6bebcb 100755 --- a/bsnes/sfc/interface/interface.hpp +++ b/bsnes/sfc/interface/interface.hpp @@ -4,10 +4,14 @@ namespace SuperFamicom { struct ID { enum : unsigned { + //cartridges SuperFamicom, - }; + SuperGameBoy, + Satellaview, + SufamiTurboSlotA, + SufamiTurboSlotB, - enum : unsigned { + //memory IPLROM, ROM, @@ -32,9 +36,8 @@ struct ID { SufamiTurboSlotBROM, SufamiTurboSlotARAM, SufamiTurboSlotBRAM, - }; - enum : unsigned { + //controller ports Port1 = 1, Port2 = 2, }; diff --git a/bsnes/target-ethos/ethos.cpp b/bsnes/target-ethos/ethos.cpp index 716ae8ce..555cd550 100755 --- a/bsnes/target-ethos/ethos.cpp +++ b/bsnes/target-ethos/ethos.cpp @@ -27,7 +27,7 @@ void Application::commandLineLoad(string pathname) { for(auto &emulator : this->emulator) { for(auto &media : emulator->media) { if(media.type != "sys") continue; - if(type != media.extension) continue; + if(type != media.path) continue; return utility->loadMedia(emulator, media, pathname); } } diff --git a/bsnes/target-ethos/general/browser.cpp b/bsnes/target-ethos/general/browser.cpp index f14385b4..a385321b 100755 --- a/bsnes/target-ethos/general/browser.cpp +++ b/bsnes/target-ethos/general/browser.cpp @@ -67,7 +67,7 @@ void Browser::bootstrap() { for(auto &media : emulator->media) { bool found = false; for(auto &folder : folderList) { - if(folder.extension == media.extension) { + if(folder.extension == media.path) { found = true; break; } @@ -75,7 +75,7 @@ void Browser::bootstrap() { if(found == true) continue; Folder folder; - folder.extension = media.extension; + folder.extension = media.path; folder.path = application->basepath; folder.selection = 0; folderList.append(folder); diff --git a/bsnes/target-ethos/general/presentation.cpp b/bsnes/target-ethos/general/presentation.cpp index 94632922..cdd421fe 100755 --- a/bsnes/target-ethos/general/presentation.cpp +++ b/bsnes/target-ethos/general/presentation.cpp @@ -28,9 +28,19 @@ void Presentation::synchronize() { synchronizeVideo.setChecked(config->video.synchronize); synchronizeAudio.setChecked(config->audio.synchronize); muteAudio.setChecked(config->audio.mute); - toolsMenu.setVisible(application->active); - synchronizeTime.setVisible(application->active && system().rtc()); - resizeWindow.setVisible(config->video.scaleMode != 2); + + 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); + stateManager.setVisible(system().information.capability.states); + cheatEditor.setVisible(system().information.capability.cheats); + synchronizeTime.setVisible(system().rtc()); + } } 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}); loadStateMenu.setText("Load State"); for(unsigned n = 0; n < 5; n++) loadStateItem[n].setText({"Slot ", 1 + n}); - synchronizeTime.setText("Synchronize Time"); resizeWindow.setText("Resize Window"); - cheatEditor.setText("Cheat Editor"); stateManager.setText("State Manager"); + cheatEditor.setText("Cheat Editor"); + synchronizeTime.setText("Synchronize Time"); append(loadMenu); 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]); toolsMenu.append(loadStateMenu); for(unsigned n = 0; n < 5; n++) loadStateMenu.append(loadStateItem[n]); - toolsMenu.append(synchronizeTime); toolsMenu.append(stateMenuSeparator); - toolsMenu.append(resizeWindow, cheatEditor, stateManager); + toolsMenu.append(resizeWindow, stateManager, cheatEditor, synchronizeTime); append(layout); layout.append(viewport, {0, 0, 720, 480}); @@ -120,10 +129,10 @@ Presentation::Presentation() : active(nullptr) { 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++) loadStateItem[n].onActivate = [=] { utility->loadState(1 + n); }; - synchronizeTime.onActivate = [&] { system().rtcsync(); }; resizeWindow.onActivate = [&] { utility->resize(true); }; - cheatEditor.onActivate = [&] { ::cheatEditor->setVisible(); }; stateManager.onActivate = [&] { ::stateManager->setVisible(); }; + cheatEditor.onActivate = [&] { ::cheatEditor->setVisible(); }; + synchronizeTime.onActivate = [&] { system().rtcsync(); }; synchronize(); } diff --git a/bsnes/target-ethos/general/presentation.hpp b/bsnes/target-ethos/general/presentation.hpp index 597083a3..1a44aa32 100755 --- a/bsnes/target-ethos/general/presentation.hpp +++ b/bsnes/target-ethos/general/presentation.hpp @@ -43,11 +43,11 @@ struct Presentation : Window { Item saveStateItem[5]; Menu loadStateMenu; Item loadStateItem[5]; - Item synchronizeTime; Separator stateMenuSeparator; Item resizeWindow; - Item cheatEditor; Item stateManager; + Item cheatEditor; + Item synchronizeTime; void synchronize(); void setSystemName(const string &name); diff --git a/bsnes/target-ethos/input/input.cpp b/bsnes/target-ethos/input/input.cpp index e731fe2a..365565b5 100755 --- a/bsnes/target-ethos/input/input.cpp +++ b/bsnes/target-ethos/input/input.cpp @@ -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::Mouse; @@ -118,16 +118,9 @@ bool AnalogInput::bind(unsigned scancode, int16_t value) { if(Joypad::isAnyAxis(scancode)) return append(encode); 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; 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() { logic = 1; //AND inputManager->hotkeyMap.append(this); @@ -201,8 +264,9 @@ void InputManager::bootstrap() { AbstractInput *abstract = nullptr; if(input.type == 0) abstract = new DigitalInput; - if(input.type == 1) abstract = new AnalogInput; - if(input.type >= 2) continue; + if(input.type == 1) abstract = new RelativeInput; + 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.replace(" ", ""); diff --git a/bsnes/target-ethos/input/input.hpp b/bsnes/target-ethos/input/input.hpp index 9a982f58..c6f7e2b3 100755 --- a/bsnes/target-ethos/input/input.hpp +++ b/bsnes/target-ethos/input/input.hpp @@ -23,7 +23,13 @@ struct DigitalInput : AbstractInput { 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; bool bind(unsigned scancode, int16_t value); int16_t poll(); diff --git a/bsnes/target-ethos/interface/interface.cpp b/bsnes/target-ethos/interface/interface.cpp index 68368d3e..9b8ecc62 100755 --- a/bsnes/target-ethos/interface/interface.cpp +++ b/bsnes/target-ethos/interface/interface.cpp @@ -1,8 +1,8 @@ #include "../ethos.hpp" Interface *interface = nullptr; -void Interface::loadRequest(unsigned id, const string &name, const string &type, const string &path) { - return utility->loadRequest(id, name, type, path); +void Interface::loadRequest(unsigned id, const string &name, const string &type) { + return utility->loadRequest(id, name, type); } void Interface::loadRequest(unsigned id, const string &path) { diff --git a/bsnes/target-ethos/interface/interface.hpp b/bsnes/target-ethos/interface/interface.hpp index 9fc581c3..8d449c9a 100755 --- a/bsnes/target-ethos/interface/interface.hpp +++ b/bsnes/target-ethos/interface/interface.hpp @@ -1,7 +1,7 @@ struct Interface : Emulator::Interface::Bind { + void loadRequest(unsigned id, const string &name, const string &type); void loadRequest(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); void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height); void audioSample(int16_t lsample, int16_t rsample); diff --git a/bsnes/target-ethos/settings/input.cpp b/bsnes/target-ethos/settings/input.cpp index 3c4bdd04..9ccb155b 100755 --- a/bsnes/target-ethos/settings/input.cpp +++ b/bsnes/target-ethos/settings/input.cpp @@ -72,7 +72,8 @@ void InputSettings::synchronize() { assign[2].setVisible(true); } - if(dynamic_cast(selectedInput)) { + if(dynamic_cast(selectedInput) + || dynamic_cast(selectedInput)) { assign[0].setText("Mouse X-axis"); assign[1].setText("Mouse Y-axis"); assign[0].setVisible(true); @@ -170,7 +171,8 @@ void InputSettings::assignMouseInput(unsigned n) { return inputEvent(mouse(0).button(n), 1, true); } - if(dynamic_cast(activeInput)) { + if(dynamic_cast(activeInput) + || dynamic_cast(activeInput)) { return inputEvent(mouse(0).axis(n), 1, true); } } diff --git a/bsnes/target-ethos/utility/utility.cpp b/bsnes/target-ethos/utility/utility.cpp index caf489f9..6faec475 100755 --- a/bsnes/target-ethos/utility/utility.cpp +++ b/bsnes/target-ethos/utility/utility.cpp @@ -11,7 +11,7 @@ void Utility::setInterface(Emulator::Interface *emulator) { void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media) { string pathname; 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(!file::exists({pathname, "manifest.xml"})) return; 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 -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); if(pathname.empty()) return; this->path(system().group(id)) = pathname; @@ -43,8 +43,7 @@ void Utility::loadRequest(unsigned id, const string &name, const string &type, c string manifest; manifest.readfile({pathname, "manifest.xml"}); - mmapstream stream({pathname, path}); - system().load(id, stream, manifest); + system().load(id, manifest); } //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); } -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) { if(application->active == nullptr) return; system().connect(port, device); @@ -110,7 +86,8 @@ void Utility::load() { title.rtrim<1>(" + "); presentation->setTitle(title); - loadMemory(); + cheatEditor->load({pathname[0], "cheats.xml"}); + stateManager->load({pathname[0], "bsnes/states.bsa"}, 1); system().paletteUpdate(); synchronizeDSP(); @@ -124,7 +101,9 @@ void Utility::unload() { if(application->active == nullptr) return; if(tracerEnable) tracerToggle(); - saveMemory(); + cheatEditor->save({pathname[0], "cheats.xml"}); + stateManager->save({pathname[0], "bsnes/states.bsa"}, 1); + system().unload(); path.reset(); pathname.reset(); @@ -135,8 +114,9 @@ void Utility::unload() { video.clear(); audio.clear(); presentation->setTitle({Emulator::Name, " v", Emulator::Version}); - cheatEditor->synchronize(); - stateManager->synchronize(); + cheatDatabase->setVisible(false); + cheatEditor->setVisible(false); + stateManager->setVisible(false); } void Utility::saveState(unsigned slot) { diff --git a/bsnes/target-ethos/utility/utility.hpp b/bsnes/target-ethos/utility/utility.hpp index f8f17708..dc5f3a11 100755 --- a/bsnes/target-ethos/utility/utility.hpp +++ b/bsnes/target-ethos/utility/utility.hpp @@ -4,11 +4,9 @@ struct Utility { void loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media); 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 saveRequest(unsigned id, const string &path); - void loadMemory(); - void saveMemory(); void connect(unsigned port, unsigned device); void power();