mirror of https://github.com/bsnes-emu/bsnes.git
Update to v082r17 release.
byuu says: Adds BS-X/Slotted/SufamiTurbo/SGB cartridge loading. Calling it Satellaview as I'm more partial to that at the moment. FileBrowser now remembers your folders per filter type like before, and will keep your place in the list if you don't switch away. I wanted there to be ONE slot loader, so the loader will show a grayed out secondary slot on non-ST loading, but it's more consistent to only have one window instead of two for geometry placement. Removed help menu. Will try and work it in somewhere unobtrusive later on I suppose. Added timed messages and the usual "no cart loaded / paused" messages and such.
This commit is contained in:
parent
5c2d16828c
commit
69ed35db99
|
@ -23,6 +23,7 @@ namespace nall {
|
||||||
enum class time : unsigned { create, modify, access };
|
enum class time : unsigned { create, modify, access };
|
||||||
|
|
||||||
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
|
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
|
||||||
|
data = 0;
|
||||||
file fp;
|
file fp;
|
||||||
if(fp.open(filename, mode::read) == false) return false;
|
if(fp.open(filename, mode::read) == false) return false;
|
||||||
size = fp.size();
|
size = fp.size();
|
||||||
|
|
|
@ -103,6 +103,9 @@ namespace nall {
|
||||||
template<unsigned Limit = 0> inline lstring& qsplit(const char*, const char*);
|
template<unsigned Limit = 0> inline lstring& qsplit(const char*, const char*);
|
||||||
template<unsigned Limit = 0> inline lstring& iqsplit(const char*, const char*);
|
template<unsigned Limit = 0> inline lstring& iqsplit(const char*, const char*);
|
||||||
|
|
||||||
|
inline bool operator==(const lstring&) const;
|
||||||
|
inline bool operator!=(const lstring&) const;
|
||||||
|
|
||||||
lstring();
|
lstring();
|
||||||
lstring(std::initializer_list<string>);
|
lstring(std::initializer_list<string>);
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,19 @@ optional<unsigned> lstring::find(const char *key) const {
|
||||||
return { false, 0 };
|
return { false, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool lstring::operator==(const lstring &source) const {
|
||||||
|
if(this == &source) return true;
|
||||||
|
if(size() != source.size()) return false;
|
||||||
|
for(unsigned n = 0; n < size(); n++) {
|
||||||
|
if(operator[](n) != source[n]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lstring::operator!=(const lstring &source) const {
|
||||||
|
return !operator==(source);
|
||||||
|
}
|
||||||
|
|
||||||
inline lstring::lstring() {
|
inline lstring::lstring() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
namespace NES {
|
namespace NES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bnes";
|
static const char Name[] = "bnes";
|
||||||
static const char Version[] = "000.12";
|
static const char Version[] = "000.13";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,6 +290,10 @@ void Window::setWidgetFont(const string &font) {
|
||||||
return p.setWidgetFont(font);
|
return p.setWidgetFont(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string Window::statusText() {
|
||||||
|
return state.statusText;
|
||||||
|
}
|
||||||
|
|
||||||
void Window::synchronizeLayout() {
|
void Window::synchronizeLayout() {
|
||||||
setGeometry(geometry());
|
setGeometry(geometry());
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,6 +153,7 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
|
||||||
void setTitle(const nall::string &text);
|
void setTitle(const nall::string &text);
|
||||||
void setVisible(bool visible = true);
|
void setVisible(bool visible = true);
|
||||||
void setWidgetFont(const nall::string &font);
|
void setWidgetFont(const nall::string &font);
|
||||||
|
nall::string statusText();
|
||||||
void synchronizeLayout();
|
void synchronizeLayout();
|
||||||
|
|
||||||
Window();
|
Window();
|
||||||
|
|
|
@ -27,9 +27,38 @@ bool Interface::cartridgeLoaded() {
|
||||||
return cartridge.loaded();
|
return cartridge.loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::loadCartridge(const string &xml, const uint8_t *data, unsigned size) {
|
void Interface::loadCartridge(const CartridgeData &base) {
|
||||||
cartridge.rom.copy(data, size);
|
cartridge.rom.copy(base.data, base.size);
|
||||||
cartridge.load(Cartridge::Mode::Normal, { xml });
|
cartridge.load(Cartridge::Mode::Normal, { base.xml });
|
||||||
|
system.power();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot) {
|
||||||
|
cartridge.rom.copy(base.data, base.size);
|
||||||
|
if(slot.data) bsxflash.memory.copy(slot.data, slot.size);
|
||||||
|
cartridge.load(Cartridge::Mode::BsxSlotted, { base.xml, slot.xml });
|
||||||
|
system.power();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot) {
|
||||||
|
cartridge.rom.copy(base.data, base.size);
|
||||||
|
if(slot.data) bsxflash.memory.copy(slot.data, slot.size);
|
||||||
|
cartridge.load(Cartridge::Mode::Bsx, { base.xml, slot.xml });
|
||||||
|
system.power();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::loadSufamiTurboCartridge(const CartridgeData &base, const CartridgeData &slotA, const CartridgeData &slotB) {
|
||||||
|
cartridge.rom.copy(base.data, base.size);
|
||||||
|
if(slotA.data) sufamiturbo.slotA.rom.copy(slotA.data, slotA.size);
|
||||||
|
if(slotB.data) sufamiturbo.slotB.rom.copy(slotB.data, slotB.size);
|
||||||
|
cartridge.load(Cartridge::Mode::SufamiTurbo, { base.xml, slotA.xml, slotB.xml });
|
||||||
|
system.power();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot) {
|
||||||
|
cartridge.rom.copy(base.data, base.size);
|
||||||
|
GameBoy::cartridge.load(slot.xml, slot.data, slot.size);
|
||||||
|
cartridge.load(Cartridge::Mode::SuperGameBoy, { base.xml, "" });
|
||||||
system.power();
|
system.power();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +88,10 @@ bool Interface::unserialize(serializer &s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::setCheats(const lstring &list) {
|
void Interface::setCheats(const lstring &list) {
|
||||||
|
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) {
|
||||||
|
return icd2.setCheats(list);
|
||||||
|
}
|
||||||
|
|
||||||
cheat.reset();
|
cheat.reset();
|
||||||
foreach(code, list) {
|
foreach(code, list) {
|
||||||
lstring codelist;
|
lstring codelist;
|
||||||
|
|
|
@ -8,8 +8,18 @@ public:
|
||||||
|
|
||||||
virtual void connect(bool port, Input::Device device);
|
virtual void connect(bool port, Input::Device device);
|
||||||
|
|
||||||
|
struct CartridgeData {
|
||||||
|
string xml;
|
||||||
|
const uint8_t *data;
|
||||||
|
unsigned size;
|
||||||
|
};
|
||||||
|
|
||||||
virtual bool cartridgeLoaded();
|
virtual bool cartridgeLoaded();
|
||||||
virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size);
|
virtual void loadCartridge(const CartridgeData &base);
|
||||||
|
virtual void loadSatellaviewSlottedCartridge(const CartridgeData &base, const CartridgeData &slot);
|
||||||
|
virtual void loadSatellaviewCartridge(const CartridgeData &base, const CartridgeData &slot);
|
||||||
|
virtual void loadSufamiTurboCartridge(const CartridgeData &base, const CartridgeData &slotA, const CartridgeData &slotB);
|
||||||
|
virtual void loadSuperGameBoyCartridge(const CartridgeData &base, const CartridgeData &slot);
|
||||||
virtual void unloadCartridge();
|
virtual void unloadCartridge();
|
||||||
|
|
||||||
virtual void power();
|
virtual void power();
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "082.16";
|
static const char Version[] = "082.17";
|
||||||
static const unsigned SerializerVersion = 22;
|
static const unsigned SerializerVersion = 22;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,10 @@ using namespace ruby;
|
||||||
|
|
||||||
struct Application {
|
struct Application {
|
||||||
bool quit;
|
bool quit;
|
||||||
|
bool pause;
|
||||||
bool autopause;
|
bool autopause;
|
||||||
|
|
||||||
string realpath;
|
string basepath;
|
||||||
string userpath;
|
string userpath;
|
||||||
|
|
||||||
string title;
|
string title;
|
||||||
|
|
|
@ -14,7 +14,9 @@ Config::Config() {
|
||||||
attach(input.driver = "", "Input::Driver");
|
attach(input.driver = "", "Input::Driver");
|
||||||
attach(input.focusPolicy = 1, "Input::FocusPolicy");
|
attach(input.focusPolicy = 1, "Input::FocusPolicy");
|
||||||
|
|
||||||
attach(path.last = application->realpath, "Path::Recent");
|
attach(path.bios.satellaview = "", "Path::BIOS::Satellaview");
|
||||||
|
attach(path.bios.sufamiTurbo = "", "Path::BIOS::SufamiTurbo");
|
||||||
|
attach(path.bios.superGameBoy = "", "Path::BIOS::SuperGameBoy");
|
||||||
|
|
||||||
attach(nes.controllerPort1Device = 1, "NES::Controller::Port1");
|
attach(nes.controllerPort1Device = 1, "NES::Controller::Port1");
|
||||||
attach(nes.controllerPort2Device = 0, "NES::Controller::Port2");
|
attach(nes.controllerPort2Device = 0, "NES::Controller::Port2");
|
||||||
|
|
|
@ -18,7 +18,11 @@ struct Config : public configuration {
|
||||||
} input;
|
} input;
|
||||||
|
|
||||||
struct Path {
|
struct Path {
|
||||||
string last;
|
struct BIOS {
|
||||||
|
string satellaview;
|
||||||
|
string sufamiTurbo;
|
||||||
|
string superGameBoy;
|
||||||
|
} bios;
|
||||||
} path;
|
} path;
|
||||||
|
|
||||||
struct NES {
|
struct NES {
|
||||||
|
|
|
@ -27,13 +27,13 @@ FileBrowser::FileBrowser() {
|
||||||
};
|
};
|
||||||
|
|
||||||
pathBrowse.onTick = [&] {
|
pathBrowse.onTick = [&] {
|
||||||
string path = OS::folderSelect(*this, activePath);
|
string path = OS::folderSelect(*this, mode->path);
|
||||||
if(path != "") setPath(path);
|
if(path != "") setPath(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
pathUp.onTick = [&] {
|
pathUp.onTick = [&] {
|
||||||
if(activePath == "/") return;
|
if(mode->path == "/") return;
|
||||||
string path = activePath;
|
string path = mode->path;
|
||||||
path.rtrim<1>("/");
|
path.rtrim<1>("/");
|
||||||
path = dir(path);
|
path = dir(path);
|
||||||
setPath(path);
|
setPath(path);
|
||||||
|
@ -41,18 +41,36 @@ FileBrowser::FileBrowser() {
|
||||||
|
|
||||||
fileList.onActivate = openButton.onTick = { &FileBrowser::fileListActivate, this };
|
fileList.onActivate = openButton.onTick = { &FileBrowser::fileListActivate, this };
|
||||||
|
|
||||||
setPath(config->path.last);
|
filterModes[Mode::Default ] = { "Default", "", { "*" } };
|
||||||
|
filterModes[Mode::NES ] = { "NES", "", { "*.nes" } };
|
||||||
|
filterModes[Mode::SNES ] = { "SNES", "", { "*.sfc" } };
|
||||||
|
filterModes[Mode::GameBoy ] = { "GameBoy", "", { "*.gb", "*.gbc" } };
|
||||||
|
filterModes[Mode::Satellaview] = { "Satellaview", "", { "*.bs" } };
|
||||||
|
filterModes[Mode::SufamiTurbo] = { "SufamiTurbo", "", { "*.st" } };
|
||||||
|
mode = &filterModes[Mode::Default];
|
||||||
|
|
||||||
|
foreach(mode, filterModes) config.attach(mode.path, mode.name);
|
||||||
|
config.load(string{ application->userpath, "paths.cfg" });
|
||||||
|
config.save(string{ application->userpath, "paths.cfg" });
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileBrowser::open(const string &title, const lstring &filterList, function<void (string)> callback) {
|
FileBrowser::~FileBrowser() {
|
||||||
this->callback = callback;
|
config.save(string{ application->userpath, "paths.cfg" });
|
||||||
this->filterList = filterList;
|
}
|
||||||
|
|
||||||
|
void FileBrowser::open(const string &title, unsigned requestedMode, function<void (string)> requestedCallback) {
|
||||||
|
callback = requestedCallback;
|
||||||
|
if(mode == &filterModes[requestedMode]) {
|
||||||
|
setVisible();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mode = &filterModes[requestedMode];
|
||||||
|
|
||||||
setTitle(title);
|
setTitle(title);
|
||||||
setPath(activePath);
|
setPath(mode->path);
|
||||||
|
|
||||||
string filterText = "Files of type: ";
|
string filterText = "Files of type: ";
|
||||||
foreach(filter, filterList) filterText.append(filter, ", ");
|
foreach(filter, mode->filter) filterText.append(filter, ", ");
|
||||||
filterText.trim<1>(", ");
|
filterText.trim<1>(", ");
|
||||||
filterLabel.setText(filterText);
|
filterLabel.setText(filterText);
|
||||||
|
|
||||||
|
@ -60,9 +78,9 @@ void FileBrowser::open(const string &title, const lstring &filterList, function<
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileBrowser::setPath(const string &path) {
|
void FileBrowser::setPath(const string &path) {
|
||||||
config->path.last = path;
|
mode->path = path;
|
||||||
activePath = path;
|
if(mode->path == "") mode->path = application->basepath;
|
||||||
pathEdit.setText(activePath);
|
pathEdit.setText(mode->path);
|
||||||
|
|
||||||
fileList.reset();
|
fileList.reset();
|
||||||
fileNameList.reset();
|
fileNameList.reset();
|
||||||
|
@ -71,8 +89,11 @@ void FileBrowser::setPath(const string &path) {
|
||||||
foreach(fileName, contentsList) {
|
foreach(fileName, contentsList) {
|
||||||
if(fileName.endswith("/")) {
|
if(fileName.endswith("/")) {
|
||||||
fileNameList.append(fileName);
|
fileNameList.append(fileName);
|
||||||
} else foreach(filter, filterList) {
|
} else foreach(filter, mode->filter) {
|
||||||
if(fileName.wildcard(filter)) fileNameList.append(fileName);
|
if(fileName.wildcard(filter)) {
|
||||||
|
fileNameList.append(fileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,8 +105,39 @@ void FileBrowser::setPath(const string &path) {
|
||||||
void FileBrowser::fileListActivate() {
|
void FileBrowser::fileListActivate() {
|
||||||
unsigned selection = fileList.selection();
|
unsigned selection = fileList.selection();
|
||||||
string fileName = fileNameList[selection];
|
string fileName = fileNameList[selection];
|
||||||
if(fileName.endswith("/")) return setPath({ activePath, fileName });
|
if(fileName.endswith("/")) {
|
||||||
|
if(loadFolder({ mode->path, fileName })) return;
|
||||||
|
return setPath({ mode->path, fileName });
|
||||||
|
}
|
||||||
|
loadFile({ mode->path, fileName });
|
||||||
|
}
|
||||||
|
|
||||||
if(callback) callback({ activePath, fileName });
|
bool FileBrowser::loadFolder(const string &requestedPath) {
|
||||||
|
bool accept = false;
|
||||||
|
string path = requestedPath;
|
||||||
|
path.rtrim<1>("/");
|
||||||
|
foreach(filter, mode->filter) {
|
||||||
|
if(path.wildcard(filter)) accept = true;
|
||||||
|
}
|
||||||
|
if(accept == false) return false;
|
||||||
|
|
||||||
|
lstring contentsList = directory::contents(requestedPath);
|
||||||
|
lstring fileNameList;
|
||||||
|
foreach(fileName, contentsList) {
|
||||||
|
foreach(filter, mode->filter) {
|
||||||
|
if(fileName.wildcard(filter)) {
|
||||||
|
fileNameList.append(fileName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fileNameList.size() != 1) return false;
|
||||||
|
loadFile({ requestedPath, fileNameList[0] });
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileBrowser::loadFile(const string &filename) {
|
||||||
|
if(callback) callback(filename);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,28 @@ struct FileBrowser : Window {
|
||||||
Label filterLabel;
|
Label filterLabel;
|
||||||
Button openButton;
|
Button openButton;
|
||||||
|
|
||||||
void open(const string &title, const lstring &filterList, function<void (string)> callback);
|
struct Mode { enum : unsigned { Default, NES, SNES, GameBoy, Satellaview, SufamiTurbo }; };
|
||||||
|
void open(const string &title, unsigned mode, function<void (string)> callback);
|
||||||
|
|
||||||
FileBrowser();
|
FileBrowser();
|
||||||
|
~FileBrowser();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
string activePath;
|
configuration config;
|
||||||
lstring filterList;
|
struct FilterMode {
|
||||||
|
string name;
|
||||||
|
string path;
|
||||||
|
lstring filter;
|
||||||
|
} *mode;
|
||||||
|
linear_vector<FilterMode> filterModes;
|
||||||
|
|
||||||
lstring fileNameList;
|
lstring fileNameList;
|
||||||
function<void (string)> callback;
|
function<void (string)> callback;
|
||||||
|
|
||||||
void setPath(const string &path);
|
void setPath(const string &path);
|
||||||
void fileListActivate();
|
void fileListActivate();
|
||||||
|
bool loadFolder(const string &path);
|
||||||
|
void loadFile(const string &filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern FileBrowser *fileBrowser;
|
extern FileBrowser *fileBrowser;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
#include "../base.hpp"
|
#include "../base.hpp"
|
||||||
#include "main-window.cpp"
|
#include "main-window.cpp"
|
||||||
#include "file-browser.cpp"
|
#include "file-browser.cpp"
|
||||||
|
#include "slot-loader.cpp"
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
#include "main-window.hpp"
|
#include "main-window.hpp"
|
||||||
#include "file-browser.hpp"
|
#include "file-browser.hpp"
|
||||||
|
#include "slot-loader.hpp"
|
||||||
|
|
|
@ -10,6 +10,10 @@ MainWindow::MainWindow() {
|
||||||
cartridgeLoadSNES.setText("Load SNES Cartridge ...");
|
cartridgeLoadSNES.setText("Load SNES Cartridge ...");
|
||||||
cartridgeLoadNES.setText("Load NES Cartridge ...");
|
cartridgeLoadNES.setText("Load NES Cartridge ...");
|
||||||
cartridgeLoadGameBoy.setText("Load Game Boy Cartridge ...");
|
cartridgeLoadGameBoy.setText("Load Game Boy Cartridge ...");
|
||||||
|
cartridgeLoadSatellaviewSlotted.setText("Load Satellaview-Slotted Cartridge ...");
|
||||||
|
cartridgeLoadSatellaview.setText("Load Satellaview Cartridge ...");
|
||||||
|
cartridgeLoadSufamiTurbo.setText("Load Sufami Turbo Cartridge ...");
|
||||||
|
cartridgeLoadSuperGameBoy.setText("Load Super Game Boy Cartridge ...");
|
||||||
|
|
||||||
nesMenu.setText("NES");
|
nesMenu.setText("NES");
|
||||||
nesPower.setText("Power Cycle");
|
nesPower.setText("Power Cycle");
|
||||||
|
@ -86,13 +90,15 @@ MainWindow::MainWindow() {
|
||||||
toolsStateManager.setText("State Manager ...");
|
toolsStateManager.setText("State Manager ...");
|
||||||
toolsTest.setText("Test");
|
toolsTest.setText("Test");
|
||||||
|
|
||||||
helpMenu.setText("Help");
|
|
||||||
helpAbout.setText("About ...");
|
|
||||||
|
|
||||||
append(cartridgeMenu);
|
append(cartridgeMenu);
|
||||||
cartridgeMenu.append(cartridgeLoadNES);
|
cartridgeMenu.append(cartridgeLoadNES);
|
||||||
cartridgeMenu.append(cartridgeLoadSNES);
|
cartridgeMenu.append(cartridgeLoadSNES);
|
||||||
cartridgeMenu.append(cartridgeLoadGameBoy);
|
cartridgeMenu.append(cartridgeLoadGameBoy);
|
||||||
|
cartridgeMenu.append(cartridgeSeparator);
|
||||||
|
cartridgeMenu.append(cartridgeLoadSatellaviewSlotted);
|
||||||
|
cartridgeMenu.append(cartridgeLoadSatellaview);
|
||||||
|
cartridgeMenu.append(cartridgeLoadSufamiTurbo);
|
||||||
|
cartridgeMenu.append(cartridgeLoadSuperGameBoy);
|
||||||
|
|
||||||
append(nesMenu);
|
append(nesMenu);
|
||||||
nesMenu.append(nesPower);
|
nesMenu.append(nesPower);
|
||||||
|
@ -167,9 +173,6 @@ MainWindow::MainWindow() {
|
||||||
toolsMenu.append(toolsSeparator3);
|
toolsMenu.append(toolsSeparator3);
|
||||||
toolsMenu.append(toolsTest);
|
toolsMenu.append(toolsTest);
|
||||||
|
|
||||||
append(helpMenu);
|
|
||||||
helpMenu.append(helpAbout);
|
|
||||||
|
|
||||||
setMenuVisible();
|
setMenuVisible();
|
||||||
|
|
||||||
setStatusText("No cartridge loaded");
|
setStatusText("No cartridge loaded");
|
||||||
|
@ -182,23 +185,28 @@ MainWindow::MainWindow() {
|
||||||
onSize = [&] { utility->resizeMainWindow(); };
|
onSize = [&] { utility->resizeMainWindow(); };
|
||||||
|
|
||||||
cartridgeLoadNES.onTick = [&] {
|
cartridgeLoadNES.onTick = [&] {
|
||||||
fileBrowser->open("Load NES Cartridge", { "*.nes" }, [](string filename) {
|
fileBrowser->open("Load Cartridge - NES", FileBrowser::Mode::NES, [](string filename) {
|
||||||
interface->loadCartridge(filename);
|
interface->nes.loadCartridge(filename);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
cartridgeLoadSNES.onTick = [&] {
|
cartridgeLoadSNES.onTick = [&] {
|
||||||
fileBrowser->open("Load SNES Cartridge", { "*.sfc" }, [](string filename) {
|
fileBrowser->open("Load Cartridge - SNES", FileBrowser::Mode::SNES, [](string filename) {
|
||||||
interface->loadCartridge(filename);
|
interface->snes.loadCartridge(filename);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
cartridgeLoadGameBoy.onTick = [&] {
|
cartridgeLoadGameBoy.onTick = [&] {
|
||||||
fileBrowser->open("Load Game Boy Cartridge", { "*.gb", "*.gbc" }, [](string filename) {
|
fileBrowser->open("Load Cartridge - Game Boy", FileBrowser::Mode::GameBoy, [](string filename) {
|
||||||
interface->loadCartridge(filename);
|
interface->gameBoy.loadCartridge(filename);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cartridgeLoadSatellaviewSlotted.onTick = [&] { slotLoader->loadSatellaviewSlotted(); };
|
||||||
|
cartridgeLoadSatellaview.onTick = [&] { slotLoader->loadSatellaview(); };
|
||||||
|
cartridgeLoadSufamiTurbo.onTick = [&] { slotLoader->loadSufamiTurbo(); };
|
||||||
|
cartridgeLoadSuperGameBoy.onTick = [&] { slotLoader->loadSuperGameBoy(); };
|
||||||
|
|
||||||
nesPower.onTick = { &Interface::power, interface };
|
nesPower.onTick = { &Interface::power, interface };
|
||||||
nesReset.onTick = { &Interface::reset, interface };
|
nesReset.onTick = { &Interface::reset, interface };
|
||||||
|
|
||||||
|
@ -276,19 +284,11 @@ MainWindow::MainWindow() {
|
||||||
NES::cpu.trace = toolsTest.checked();
|
NES::cpu.trace = toolsTest.checked();
|
||||||
};
|
};
|
||||||
|
|
||||||
helpAbout.onTick = [&] {
|
|
||||||
MessageWindow::information(*this, {
|
|
||||||
application->title, "\n\n",
|
|
||||||
"Author: byuu\n",
|
|
||||||
"Website: http://byuu.org/"
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
synchronize();
|
synchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::synchronize() {
|
void MainWindow::synchronize() {
|
||||||
if(interface->loaded()) {
|
if(interface->cartridgeLoaded()) {
|
||||||
toolsStateSave.setEnabled(true);
|
toolsStateSave.setEnabled(true);
|
||||||
toolsStateLoad.setEnabled(true);
|
toolsStateLoad.setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -6,6 +6,11 @@ struct MainWindow : Window {
|
||||||
Item cartridgeLoadSNES;
|
Item cartridgeLoadSNES;
|
||||||
Item cartridgeLoadNES;
|
Item cartridgeLoadNES;
|
||||||
Item cartridgeLoadGameBoy;
|
Item cartridgeLoadGameBoy;
|
||||||
|
Separator cartridgeSeparator;
|
||||||
|
Item cartridgeLoadSatellaviewSlotted;
|
||||||
|
Item cartridgeLoadSatellaview;
|
||||||
|
Item cartridgeLoadSufamiTurbo;
|
||||||
|
Item cartridgeLoadSuperGameBoy;
|
||||||
|
|
||||||
Menu nesMenu;
|
Menu nesMenu;
|
||||||
Item nesPower;
|
Item nesPower;
|
||||||
|
@ -67,9 +72,6 @@ struct MainWindow : Window {
|
||||||
Separator toolsSeparator3;
|
Separator toolsSeparator3;
|
||||||
CheckItem toolsTest;
|
CheckItem toolsTest;
|
||||||
|
|
||||||
Menu helpMenu;
|
|
||||||
Item helpAbout;
|
|
||||||
|
|
||||||
void synchronize();
|
void synchronize();
|
||||||
MainWindow();
|
MainWindow();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
SlotLoader *slotLoader = 0;
|
||||||
|
|
||||||
|
SlotLoaderPath::SlotLoaderPath() {
|
||||||
|
browse.setText("Browse ...");
|
||||||
|
append(label, 40, 0, 5);
|
||||||
|
append(path, ~0, 0, 5);
|
||||||
|
append(browse, 80, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SlotLoader::SlotLoader() {
|
||||||
|
layout.setMargin(5);
|
||||||
|
base.label.setText("Base:");
|
||||||
|
slot[0].label.setText("Slot:");
|
||||||
|
slot[1].label.setText("Slot:");
|
||||||
|
loadButton.setText("Load");
|
||||||
|
|
||||||
|
append(layout);
|
||||||
|
layout.append(base, ~0, 0, 5);
|
||||||
|
layout.append(slot[0], ~0, 0, 5);
|
||||||
|
layout.append(slot[1], ~0, 0, 5);
|
||||||
|
layout.append(controlLayout, ~0, 0);
|
||||||
|
controlLayout.append(spacer, ~0, 0);
|
||||||
|
controlLayout.append(loadButton, 80, 0);
|
||||||
|
|
||||||
|
setGeometry({ 128, 128, 500, layout.minimumGeometry().height });
|
||||||
|
windowManager->append(this, "SlotLoader");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlotLoader::synchronize() {
|
||||||
|
loadButton.setEnabled(base.path.text() != "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlotLoader::loadSatellaviewSlotted() {
|
||||||
|
setTitle("Load Cartridge - Satellaview-Slotted");
|
||||||
|
|
||||||
|
base.path.setText("");
|
||||||
|
|
||||||
|
slot[0].path.setText("");
|
||||||
|
slot[0].path.setEnabled(true);
|
||||||
|
slot[0].browse.setEnabled(true);
|
||||||
|
|
||||||
|
slot[1].path.setText("");
|
||||||
|
slot[1].path.setEnabled(false);
|
||||||
|
slot[1].browse.setEnabled(false);
|
||||||
|
|
||||||
|
base.browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load Cartridge - SNES", FileBrowser::Mode::SNES, [&](const string &filename) {
|
||||||
|
base.path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
slot[0].browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load Cartridge - Satellaview", FileBrowser::Mode::Satellaview, [&](const string &filename) {
|
||||||
|
slot[0].path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadButton.onTick = [&] {
|
||||||
|
this->setVisible(false);
|
||||||
|
interface->snes.loadSatellaviewSlottedCartridge(base.path.text(), slot[0].path.text());
|
||||||
|
};
|
||||||
|
|
||||||
|
synchronize();
|
||||||
|
setVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlotLoader::loadSatellaview() {
|
||||||
|
setTitle("Load Cartridge - Satellaview");
|
||||||
|
|
||||||
|
base.path.setText(config->path.bios.satellaview);
|
||||||
|
|
||||||
|
slot[0].path.setText("");
|
||||||
|
slot[0].path.setEnabled(true);
|
||||||
|
slot[0].browse.setEnabled(true);
|
||||||
|
|
||||||
|
slot[1].path.setText("");
|
||||||
|
slot[1].path.setEnabled(false);
|
||||||
|
slot[1].browse.setEnabled(false);
|
||||||
|
|
||||||
|
base.browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load BIOS - Satellaview", FileBrowser::Mode::SNES, [&](const string &filename) {
|
||||||
|
config->path.bios.satellaview = filename;
|
||||||
|
base.path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
slot[0].browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load Cartridge - Satellaview", FileBrowser::Mode::Satellaview, [&](const string &filename) {
|
||||||
|
slot[0].path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadButton.onTick = [&] {
|
||||||
|
this->setVisible(false);
|
||||||
|
interface->snes.loadSatellaviewCartridge(base.path.text(), slot[0].path.text());
|
||||||
|
};
|
||||||
|
|
||||||
|
synchronize();
|
||||||
|
setVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlotLoader::loadSufamiTurbo() {
|
||||||
|
setTitle("Load Cartridge - Sufami Turbo");
|
||||||
|
|
||||||
|
base.path.setText(config->path.bios.sufamiTurbo);
|
||||||
|
|
||||||
|
slot[0].path.setText("");
|
||||||
|
slot[0].path.setEnabled(true);
|
||||||
|
slot[0].browse.setEnabled(true);
|
||||||
|
|
||||||
|
slot[1].path.setText("");
|
||||||
|
slot[1].path.setEnabled(true);
|
||||||
|
slot[1].browse.setEnabled(true);
|
||||||
|
|
||||||
|
base.browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load BIOS - Sufami Turbo", FileBrowser::Mode::SNES, [&](const string &filename) {
|
||||||
|
config->path.bios.sufamiTurbo = filename;
|
||||||
|
base.path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
slot[0].browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load Cartridge - Sufami Turbo", FileBrowser::Mode::SufamiTurbo, [&](const string &filename) {
|
||||||
|
slot[0].path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
slot[1].browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load Cartridge - Sufami Turbo", FileBrowser::Mode::SufamiTurbo, [&](const string &filename) {
|
||||||
|
slot[1].path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadButton.onTick = [&] {
|
||||||
|
this->setVisible(false);
|
||||||
|
interface->snes.loadSufamiTurboCartridge(base.path.text(), slot[0].path.text(), slot[1].path.text());
|
||||||
|
};
|
||||||
|
|
||||||
|
synchronize();
|
||||||
|
setVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SlotLoader::loadSuperGameBoy() {
|
||||||
|
setTitle("Load Cartridge - Super Game Boy");
|
||||||
|
|
||||||
|
base.path.setText(config->path.bios.superGameBoy);
|
||||||
|
|
||||||
|
slot[0].path.setText("");
|
||||||
|
slot[0].path.setEnabled(true);
|
||||||
|
slot[0].browse.setEnabled(true);
|
||||||
|
|
||||||
|
slot[1].path.setText("");
|
||||||
|
slot[1].path.setEnabled(false);
|
||||||
|
slot[1].browse.setEnabled(false);
|
||||||
|
|
||||||
|
base.browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load BIOS - Super Game Boy", FileBrowser::Mode::SNES, [&](const string &filename) {
|
||||||
|
config->path.bios.superGameBoy = filename;
|
||||||
|
base.path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
slot[0].browse.onTick = [&] {
|
||||||
|
fileBrowser->open("Load Cartridge - Game Boy", FileBrowser::Mode::GameBoy, [&](const string &filename) {
|
||||||
|
slot[0].path.setText(filename);
|
||||||
|
synchronize();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadButton.onTick = [&] {
|
||||||
|
this->setVisible(false);
|
||||||
|
interface->snes.loadSuperGameBoyCartridge(base.path.text(), slot[0].path.text());
|
||||||
|
};
|
||||||
|
|
||||||
|
synchronize();
|
||||||
|
setVisible();
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
struct SlotLoaderPath : HorizontalLayout {
|
||||||
|
Label label;
|
||||||
|
LineEdit path;
|
||||||
|
Button browse;
|
||||||
|
|
||||||
|
string name;
|
||||||
|
lstring filter;
|
||||||
|
|
||||||
|
SlotLoaderPath();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SlotLoader : Window {
|
||||||
|
VerticalLayout layout;
|
||||||
|
SlotLoaderPath base;
|
||||||
|
SlotLoaderPath slot[2];
|
||||||
|
HorizontalLayout controlLayout;
|
||||||
|
Widget spacer;
|
||||||
|
Button loadButton;
|
||||||
|
|
||||||
|
void synchronize();
|
||||||
|
void loadSatellaviewSlotted();
|
||||||
|
void loadSatellaview();
|
||||||
|
void loadSufamiTurbo();
|
||||||
|
void loadSuperGameBoy();
|
||||||
|
|
||||||
|
SlotLoader();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SlotLoader *slotLoader;
|
|
@ -3,6 +3,10 @@ void HotkeyGeneral::inputEvent(int16_t scancode, int16_t value) {
|
||||||
utility->toggleFullScreen();
|
utility->toggleFullScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(scancode == pause.scancode && value) {
|
||||||
|
application->pause = !application->pause;
|
||||||
|
}
|
||||||
|
|
||||||
if(scancode == turboMode.scancode) {
|
if(scancode == turboMode.scancode) {
|
||||||
static bool Vsync, Async;
|
static bool Vsync, Async;
|
||||||
if(value) {
|
if(value) {
|
||||||
|
@ -20,13 +24,16 @@ void HotkeyGeneral::inputEvent(int16_t scancode, int16_t value) {
|
||||||
HotkeyGeneral::HotkeyGeneral() {
|
HotkeyGeneral::HotkeyGeneral() {
|
||||||
name = "General";
|
name = "General";
|
||||||
|
|
||||||
toggleFullScreen.name = "Toggle Fullscreen";
|
toggleFullScreen.name = "Toggle fullscreen";
|
||||||
turboMode.name = "Turbo Mode";
|
pause.name = "Pause emulation";
|
||||||
|
turboMode.name = "Turbo mode";
|
||||||
|
|
||||||
toggleFullScreen.mapping = "KB0::F11";
|
toggleFullScreen.mapping = "KB0::F11";
|
||||||
|
pause.mapping = "KB0::P";
|
||||||
turboMode.mapping = "KB0::Tilde";
|
turboMode.mapping = "KB0::Tilde";
|
||||||
|
|
||||||
append(toggleFullScreen);
|
append(toggleFullScreen);
|
||||||
|
append(pause);
|
||||||
append(turboMode);
|
append(turboMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
struct HotkeyGeneral : TertiaryInput {
|
struct HotkeyGeneral : TertiaryInput {
|
||||||
DigitalInput toggleFullScreen;
|
DigitalInput toggleFullScreen;
|
||||||
|
DigitalInput pause;
|
||||||
DigitalInput turboMode;
|
DigitalInput turboMode;
|
||||||
|
|
||||||
void inputEvent(int16_t scancode, int16_t value);
|
void inputEvent(int16_t scancode, int16_t value);
|
||||||
|
|
|
@ -3,11 +3,14 @@ bool InterfaceGameBoy::loadCartridge(const string &filename) {
|
||||||
unsigned size;
|
unsigned size;
|
||||||
if(file::read(filename, data, size) == false) return false;
|
if(file::read(filename, data, size) == false) return false;
|
||||||
|
|
||||||
|
interface->unloadCartridge();
|
||||||
interface->baseName = nall::basename(filename);
|
interface->baseName = nall::basename(filename);
|
||||||
|
|
||||||
GameBoyCartridge info(data, size);
|
GameBoyCartridge info(data, size);
|
||||||
GameBoy::Interface::loadCartridge(info.xml, data, size);
|
GameBoy::Interface::loadCartridge(info.xml, data, size);
|
||||||
|
|
||||||
delete[] data;
|
delete[] data;
|
||||||
|
|
||||||
|
interface->loadCartridge(::Interface::Mode::GameBoy);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ void Interface::setController(unsigned port, unsigned device) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interface::loaded() {
|
bool Interface::cartridgeLoaded() {
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
case Mode::NES: return nes.cartridgeLoaded();
|
case Mode::NES: return nes.cartridgeLoaded();
|
||||||
case Mode::SNES: return snes.cartridgeLoaded();
|
case Mode::SNES: return snes.cartridgeLoaded();
|
||||||
|
@ -34,32 +34,28 @@ bool Interface::loaded() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Interface::loadCartridge(Mode mode) {
|
||||||
|
utility->setMode(this->mode = mode);
|
||||||
|
bindControllers();
|
||||||
|
cheatEditor->load({ baseName, ".cht" });
|
||||||
|
stateManager->load({ baseName, ".bsa" }, 0u);
|
||||||
|
utility->showMessage({ "Loaded ", notdir(baseName) });
|
||||||
|
}
|
||||||
|
|
||||||
bool Interface::loadCartridge(const string &filename) {
|
bool Interface::loadCartridge(const string &filename) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
setCheatCodes();
|
if(filename.endswith(".nes")) result = nes.loadCartridge(filename);
|
||||||
unloadCartridge();
|
if(filename.endswith(".sfc")) result = snes.loadCartridge(filename);
|
||||||
if(filename.endswith(".nes")) result = loadCartridgeNES(filename);
|
if(filename.endswith(".gb" )) result = gameBoy.loadCartridge(filename);
|
||||||
if(filename.endswith(".sfc")) result = loadCartridgeSNES(filename);
|
if(filename.endswith(".gbc")) result = gameBoy.loadCartridge(filename);
|
||||||
if(filename.endswith(".gb" )) result = loadCartridgeGameBoy(filename);
|
|
||||||
if(filename.endswith(".gbc")) result = loadCartridgeGameBoy(filename);
|
|
||||||
if(result == true) {
|
|
||||||
bindControllers();
|
|
||||||
cheatEditor->load({ baseName, ".cht" });
|
|
||||||
stateManager->load({ baseName, ".bsa" }, 0u);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interface::loadCartridgeNES(const string &filename) {
|
|
||||||
if(nes.loadCartridge(filename) == false) return false;
|
|
||||||
utility->setMode(mode = Mode::NES);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interface::unloadCartridge() {
|
void Interface::unloadCartridge() {
|
||||||
if(loaded() == false) return;
|
if(cartridgeLoaded() == false) return;
|
||||||
cheatEditor->save({ baseName, ".cht" });
|
cheatEditor->save({ baseName, ".cht" });
|
||||||
stateManager->save({ baseName, ".bsa" }, 0u);
|
stateManager->save({ baseName, ".bsa" }, 0u);
|
||||||
|
setCheatCodes();
|
||||||
|
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
case Mode::NES: nes.unloadCartridge(); break;
|
case Mode::NES: nes.unloadCartridge(); break;
|
||||||
|
@ -70,33 +66,6 @@ void Interface::unloadCartridge() {
|
||||||
utility->setMode(mode = Mode::None);
|
utility->setMode(mode = Mode::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::unloadCartridgeNES() {
|
|
||||||
nes.unloadCartridge();
|
|
||||||
utility->setMode(mode = Mode::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Interface::loadCartridgeSNES(const string &filename) {
|
|
||||||
if(snes.loadCartridge(filename) == false) return false;
|
|
||||||
utility->setMode(mode = Mode::SNES);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interface::unloadCartridgeSNES() {
|
|
||||||
snes.unloadCartridge();
|
|
||||||
utility->setMode(mode = Mode::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Interface::loadCartridgeGameBoy(const string &filename) {
|
|
||||||
if(gameBoy.loadCartridge(filename) == false) return false;
|
|
||||||
utility->setMode(mode = Mode::GameBoy);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interface::unloadCartridgeGameBoy() {
|
|
||||||
gameBoy.unloadCartridge();
|
|
||||||
utility->setMode(mode = Mode::None);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Interface::power() {
|
void Interface::power() {
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
case Mode::NES: return nes.power();
|
case Mode::NES: return nes.power();
|
||||||
|
@ -138,19 +107,23 @@ bool Interface::unserialize(serializer &s) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interface::saveState(const string &filename) {
|
bool Interface::saveState(const string &filename) {
|
||||||
|
bool result = false;
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
case Mode::SNES: return snes.saveState(filename);
|
case Mode::SNES: result = snes.saveState(filename); break;
|
||||||
case Mode::GameBoy: return gameBoy.saveState(filename);
|
case Mode::GameBoy: result = gameBoy.saveState(filename); break;
|
||||||
}
|
}
|
||||||
return false;
|
utility->showMessage(result == true ? "Saved state" : "Failed to save state");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Interface::loadState(const string &filename) {
|
bool Interface::loadState(const string &filename) {
|
||||||
|
bool result = false;
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
case Mode::SNES: return snes.loadState(filename);
|
case Mode::SNES: result = snes.loadState(filename); break;
|
||||||
case Mode::GameBoy: return gameBoy.loadState(filename);
|
case Mode::GameBoy: result = gameBoy.loadState(filename); break;
|
||||||
}
|
}
|
||||||
return false;
|
utility->showMessage(result == true ? "Loaded state" : "Failed to load state");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::setCheatCodes(const lstring &list) {
|
void Interface::setCheatCodes(const lstring &list) {
|
||||||
|
@ -178,7 +151,7 @@ void Interface::videoRefresh() {
|
||||||
time(¤t);
|
time(¤t);
|
||||||
if(current != previous) {
|
if(current != previous) {
|
||||||
previous = current;
|
previous = current;
|
||||||
mainWindow->setStatusText({ "FPS: ", frameCounter });
|
utility->setStatusText({ "FPS: ", frameCounter });
|
||||||
frameCounter = 0;
|
frameCounter = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,10 @@ struct Interface : property<Interface> {
|
||||||
void bindControllers();
|
void bindControllers();
|
||||||
void setController(unsigned port, unsigned device);
|
void setController(unsigned port, unsigned device);
|
||||||
|
|
||||||
bool loaded();
|
bool cartridgeLoaded();
|
||||||
|
void loadCartridge(Mode mode);
|
||||||
bool loadCartridge(const string &filename);
|
bool loadCartridge(const string &filename); //auto-detect system-type based on file extension
|
||||||
bool loadCartridgeNES(const string &filename);
|
|
||||||
bool loadCartridgeSNES(const string &filename);
|
|
||||||
bool loadCartridgeGameBoy(const string &filename);
|
|
||||||
|
|
||||||
void unloadCartridge();
|
void unloadCartridge();
|
||||||
void unloadCartridgeNES();
|
|
||||||
void unloadCartridgeSNES();
|
|
||||||
void unloadCartridgeGameBoy();
|
|
||||||
|
|
||||||
void power();
|
void power();
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -38,7 +31,6 @@ struct Interface : property<Interface> {
|
||||||
|
|
||||||
string baseName; // = "/path/to/cartridge" (no extension)
|
string baseName; // = "/path/to/cartridge" (no extension)
|
||||||
|
|
||||||
private:
|
|
||||||
InterfaceNES nes;
|
InterfaceNES nes;
|
||||||
InterfaceSNES snes;
|
InterfaceSNES snes;
|
||||||
InterfaceGameBoy gameBoy;
|
InterfaceGameBoy gameBoy;
|
||||||
|
|
|
@ -17,10 +17,13 @@ bool InterfaceNES::loadCartridge(const string &filename) {
|
||||||
filemap fp;
|
filemap fp;
|
||||||
if(fp.open(filename, filemap::mode::read) == false) return false;
|
if(fp.open(filename, filemap::mode::read) == false) return false;
|
||||||
|
|
||||||
|
interface->unloadCartridge();
|
||||||
interface->baseName = nall::basename(filename);
|
interface->baseName = nall::basename(filename);
|
||||||
NES::Interface::loadCartridge("", fp.data(), fp.size());
|
|
||||||
|
|
||||||
|
NES::Interface::loadCartridge("", fp.data(), fp.size());
|
||||||
fp.close();
|
fp.close();
|
||||||
|
|
||||||
|
interface->loadCartridge(::Interface::Mode::NES);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,95 @@ bool InterfaceSNES::loadCartridge(const string &filename) {
|
||||||
unsigned size;
|
unsigned size;
|
||||||
if(file::read(filename, data, size) == false) return false;
|
if(file::read(filename, data, size) == false) return false;
|
||||||
|
|
||||||
|
interface->unloadCartridge();
|
||||||
interface->baseName = nall::basename(filename);
|
interface->baseName = nall::basename(filename);
|
||||||
string xml = SNESCartridge(data, size).xmlMemoryMap;
|
|
||||||
SNES::Interface::loadCartridge(xml, data, size);
|
|
||||||
|
|
||||||
|
string xml = SNESCartridge(data, size).xmlMemoryMap;
|
||||||
|
SNES::Interface::loadCartridge({ xml, data, size });
|
||||||
delete[] data;
|
delete[] data;
|
||||||
|
|
||||||
|
interface->loadCartridge(::Interface::Mode::SNES);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InterfaceSNES::loadSatellaviewSlottedCartridge(const string &basename, const string &slotname) {
|
||||||
|
uint8_t *data[2];
|
||||||
|
unsigned size[2];
|
||||||
|
if(file::read(basename, data[0], size[0]) == false) return false;
|
||||||
|
file::read(slotname, data[1], size[1]);
|
||||||
|
|
||||||
|
interface->unloadCartridge();
|
||||||
|
interface->baseName = nall::basename(basename);
|
||||||
|
if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname)));
|
||||||
|
|
||||||
|
string xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
|
||||||
|
SNES::Interface::loadSatellaviewSlottedCartridge({ xml, data[0], size[0] }, { "", data[1], size[1] });
|
||||||
|
delete[] data[0];
|
||||||
|
if(data[1]) delete[] data[1];
|
||||||
|
|
||||||
|
interface->loadCartridge(::Interface::Mode::SNES);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InterfaceSNES::loadSatellaviewCartridge(const string &basename, const string &slotname) {
|
||||||
|
uint8_t *data[2];
|
||||||
|
unsigned size[2];
|
||||||
|
if(file::read(basename, data[0], size[0]) == false) return false;
|
||||||
|
file::read(slotname, data[1], size[1]);
|
||||||
|
|
||||||
|
interface->unloadCartridge();
|
||||||
|
interface->baseName = nall::basename(basename);
|
||||||
|
if(data[1]) interface->baseName.append("+", nall::basename(notdir(slotname)));
|
||||||
|
|
||||||
|
string xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
|
||||||
|
SNES::Interface::loadSatellaviewCartridge({ xml, data[0], size[0] }, { "", data[1], size[1] });
|
||||||
|
delete[] data[0];
|
||||||
|
if(data[1]) delete[] data[1];
|
||||||
|
|
||||||
|
interface->loadCartridge(::Interface::Mode::SNES);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InterfaceSNES::loadSufamiTurboCartridge(const string &basename, const string &slotAname, const string &slotBname) {
|
||||||
|
uint8_t *data[3];
|
||||||
|
unsigned size[3];
|
||||||
|
if(file::read(basename, data[0], size[0]) == false) return false;
|
||||||
|
file::read(slotAname, data[1], size[1]);
|
||||||
|
file::read(slotBname, data[2], size[2]);
|
||||||
|
|
||||||
|
interface->unloadCartridge();
|
||||||
|
interface->baseName = nall::basename(basename);
|
||||||
|
if(data[1] && data[2]) interface->baseName = { nall::basename(slotAname), "+", nall::basename(notdir(slotBname)) };
|
||||||
|
else if(data[1]) interface->baseName = nall::basename(slotAname);
|
||||||
|
else if(data[2]) interface->baseName = nall::basename(slotBname);
|
||||||
|
|
||||||
|
string xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
|
||||||
|
SNES::Interface::loadSufamiTurboCartridge({ xml, data[0], size[0] }, { "", data[1], size[1] }, { "", data[2], size[2] });
|
||||||
|
delete[] data[0];
|
||||||
|
if(data[1]) delete[] data[1];
|
||||||
|
if(data[2]) delete[] data[2];
|
||||||
|
|
||||||
|
interface->loadCartridge(::Interface::Mode::SNES);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InterfaceSNES::loadSuperGameBoyCartridge(const string &basename, const string &slotname) {
|
||||||
|
uint8_t *data[2];
|
||||||
|
unsigned size[2];
|
||||||
|
if(file::read(basename, data[0], size[0]) == false) return false;
|
||||||
|
file::read(slotname, data[1], size[1]);
|
||||||
|
|
||||||
|
interface->unloadCartridge();
|
||||||
|
interface->baseName = nall::basename(basename);
|
||||||
|
if(data[1]) interface->baseName = nall::basename(slotname);
|
||||||
|
|
||||||
|
string xml = SNESCartridge(data[0], size[0]).xmlMemoryMap;
|
||||||
|
string gbXml = GameBoyCartridge(data[1], size[1]).xml;
|
||||||
|
SNES::Interface::loadSuperGameBoyCartridge({ xml, data[0], size[0] }, { gbXml, data[1], size[1] });
|
||||||
|
delete[] data[0];
|
||||||
|
if(data[1]) delete[] data[1];
|
||||||
|
|
||||||
|
interface->loadCartridge(::Interface::Mode::SNES);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,10 @@ struct InterfaceSNES : SNES::Interface {
|
||||||
void setController(bool port, unsigned device);
|
void setController(bool port, unsigned device);
|
||||||
|
|
||||||
bool loadCartridge(const string &filename);
|
bool loadCartridge(const string &filename);
|
||||||
|
bool loadSatellaviewSlottedCartridge(const string &basename, const string &slotname);
|
||||||
|
bool loadSatellaviewCartridge(const string &basename, const string &slotname);
|
||||||
|
bool loadSufamiTurboCartridge(const string &basename, const string &slotAname, const string &slotBname);
|
||||||
|
bool loadSuperGameBoyCartridge(const string &basename, const string &slotname);
|
||||||
void unloadCartridge();
|
void unloadCartridge();
|
||||||
|
|
||||||
bool saveState(const string &filename);
|
bool saveState(const string &filename);
|
||||||
|
|
|
@ -7,8 +7,9 @@ void Application::run() {
|
||||||
inputManager->scan();
|
inputManager->scan();
|
||||||
|
|
||||||
autopause = (mainWindow->focused() == false && config->input.focusPolicy == 2);
|
autopause = (mainWindow->focused() == false && config->input.focusPolicy == 2);
|
||||||
|
utility->updateStatus();
|
||||||
|
|
||||||
if(interface->loaded() == false || autopause) {
|
if(interface->cartridgeLoaded() == false || pause || autopause) {
|
||||||
audio.clear();
|
audio.clear();
|
||||||
usleep(20 * 1000);
|
usleep(20 * 1000);
|
||||||
return;
|
return;
|
||||||
|
@ -17,12 +18,15 @@ void Application::run() {
|
||||||
interface->run();
|
interface->run();
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::Application(int argc, char **argv) : quit(false) {
|
Application::Application(int argc, char **argv) {
|
||||||
application = this;
|
application = this;
|
||||||
|
quit = false;
|
||||||
|
pause = false;
|
||||||
|
autopause = false;
|
||||||
{
|
{
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
auto unused = ::realpath(argv[0], path);
|
auto unused = ::realpath(argv[0], path);
|
||||||
realpath = path;
|
basepath = path;
|
||||||
unused = ::userpath(path);
|
unused = ::userpath(path);
|
||||||
userpath = path;
|
userpath = path;
|
||||||
#if defined(PLATFORM_WIN)
|
#if defined(PLATFORM_WIN)
|
||||||
|
@ -52,6 +56,7 @@ Application::Application(int argc, char **argv) : quit(false) {
|
||||||
windowManager = new WindowManager;
|
windowManager = new WindowManager;
|
||||||
mainWindow = new MainWindow;
|
mainWindow = new MainWindow;
|
||||||
fileBrowser = new FileBrowser;
|
fileBrowser = new FileBrowser;
|
||||||
|
slotLoader = new SlotLoader;
|
||||||
settingsWindow = new SettingsWindow;
|
settingsWindow = new SettingsWindow;
|
||||||
cheatEditor = new CheatEditor;
|
cheatEditor = new CheatEditor;
|
||||||
stateManager = new StateManager;
|
stateManager = new StateManager;
|
||||||
|
@ -99,6 +104,7 @@ Application::~Application() {
|
||||||
delete stateManager;
|
delete stateManager;
|
||||||
delete cheatEditor;
|
delete cheatEditor;
|
||||||
delete settingsWindow;
|
delete settingsWindow;
|
||||||
|
delete slotLoader;
|
||||||
delete fileBrowser;
|
delete fileBrowser;
|
||||||
delete mainWindow;
|
delete mainWindow;
|
||||||
delete windowManager;
|
delete windowManager;
|
||||||
|
|
|
@ -43,7 +43,7 @@ CheatEditor::CheatEditor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheatEditor::synchronize() {
|
void CheatEditor::synchronize() {
|
||||||
layout.setEnabled(interface->loaded());
|
layout.setEnabled(interface->cartridgeLoaded());
|
||||||
|
|
||||||
if(cheatList.selected()) {
|
if(cheatList.selected()) {
|
||||||
unsigned n = cheatList.selection();
|
unsigned n = cheatList.selection();
|
||||||
|
|
|
@ -38,7 +38,7 @@ StateManager::StateManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateManager::synchronize() {
|
void StateManager::synchronize() {
|
||||||
layout.setEnabled(interface->loaded());
|
layout.setEnabled(interface->cartridgeLoaded());
|
||||||
|
|
||||||
descEdit.setText("");
|
descEdit.setText("");
|
||||||
descEdit.setEnabled(false);
|
descEdit.setEnabled(false);
|
||||||
|
|
|
@ -71,14 +71,10 @@ void Utility::resizeMainWindow(bool shrink) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Utility::shrinkMainWindow() {
|
|
||||||
}
|
|
||||||
|
|
||||||
void Utility::toggleFullScreen() {
|
void Utility::toggleFullScreen() {
|
||||||
static bool fullScreen = false;
|
|
||||||
static Geometry geometry;
|
static Geometry geometry;
|
||||||
|
|
||||||
if(fullScreen == false) {
|
if(mainWindow->fullScreen() == false) {
|
||||||
geometry = mainWindow->geometry();
|
geometry = mainWindow->geometry();
|
||||||
mainWindow->setMenuVisible(false);
|
mainWindow->setMenuVisible(false);
|
||||||
mainWindow->setStatusVisible(false);
|
mainWindow->setStatusVisible(false);
|
||||||
|
@ -92,7 +88,6 @@ void Utility::toggleFullScreen() {
|
||||||
mainWindow->setGeometry(geometry);
|
mainWindow->setGeometry(geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
fullScreen ^= 1;
|
|
||||||
resizeMainWindow();
|
resizeMainWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,3 +96,33 @@ void Utility::bindVideoShader() {
|
||||||
data.readfile(config->video.shader);
|
data.readfile(config->video.shader);
|
||||||
video.set(Video::Shader, (const char*)data);
|
video.set(Video::Shader, (const char*)data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Utility::updateStatus() {
|
||||||
|
time_t currentTime = time(0);
|
||||||
|
string text;
|
||||||
|
if((currentTime - statusTime) <= 2) {
|
||||||
|
text = statusMessage;
|
||||||
|
} else if(interface->cartridgeLoaded() == false) {
|
||||||
|
text = "No cartridge loaded";
|
||||||
|
} else if(application->pause || application->autopause) {
|
||||||
|
text = "Paused";
|
||||||
|
} else {
|
||||||
|
text = statusText;
|
||||||
|
}
|
||||||
|
if(text != mainWindow->statusText()) {
|
||||||
|
mainWindow->setStatusText(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utility::setStatusText(const string &text) {
|
||||||
|
statusText = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utility::showMessage(const string &message) {
|
||||||
|
statusTime = time(0);
|
||||||
|
statusMessage = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utility::Utility() {
|
||||||
|
statusTime = 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,19 @@
|
||||||
struct Utility {
|
struct Utility {
|
||||||
void setMode(Interface::Mode mode);
|
void setMode(Interface::Mode mode);
|
||||||
void resizeMainWindow(bool shrink = false);
|
void resizeMainWindow(bool shrink = false);
|
||||||
void shrinkMainWindow();
|
|
||||||
void toggleFullScreen();
|
void toggleFullScreen();
|
||||||
void bindVideoShader();
|
void bindVideoShader();
|
||||||
|
|
||||||
|
void updateStatus();
|
||||||
|
void setStatusText(const string &text);
|
||||||
|
void showMessage(const string &text);
|
||||||
|
|
||||||
|
Utility();
|
||||||
|
|
||||||
|
private:
|
||||||
|
time_t statusTime;
|
||||||
|
string statusText;
|
||||||
|
string statusMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Utility *utility;
|
extern Utility *utility;
|
||||||
|
|
Loading…
Reference in New Issue