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:
Tim Allen 2011-09-19 22:34:18 +10:00
parent 5c2d16828c
commit 69ed35db99
33 changed files with 594 additions and 134 deletions

View File

@ -23,6 +23,7 @@ namespace nall {
enum class time : unsigned { create, modify, access };
static bool read(const string &filename, uint8_t *&data, unsigned &size) {
data = 0;
file fp;
if(fp.open(filename, mode::read) == false) return false;
size = fp.size();

View File

@ -103,6 +103,9 @@ namespace nall {
template<unsigned Limit = 0> inline lstring& qsplit(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(std::initializer_list<string>);

View File

@ -135,6 +135,19 @@ optional<unsigned> lstring::find(const char *key) const {
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() {
}

View File

@ -4,7 +4,7 @@
namespace NES {
namespace Info {
static const char Name[] = "bnes";
static const char Version[] = "000.12";
static const char Version[] = "000.13";
}
}

View File

@ -290,6 +290,10 @@ void Window::setWidgetFont(const string &font) {
return p.setWidgetFont(font);
}
string Window::statusText() {
return state.statusText;
}
void Window::synchronizeLayout() {
setGeometry(geometry());
}

View File

@ -153,6 +153,7 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
void setTitle(const nall::string &text);
void setVisible(bool visible = true);
void setWidgetFont(const nall::string &font);
nall::string statusText();
void synchronizeLayout();
Window();

View File

@ -27,9 +27,38 @@ bool Interface::cartridgeLoaded() {
return cartridge.loaded();
}
void Interface::loadCartridge(const string &xml, const uint8_t *data, unsigned size) {
cartridge.rom.copy(data, size);
cartridge.load(Cartridge::Mode::Normal, { xml });
void Interface::loadCartridge(const CartridgeData &base) {
cartridge.rom.copy(base.data, base.size);
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();
}
@ -59,6 +88,10 @@ bool Interface::unserialize(serializer &s) {
}
void Interface::setCheats(const lstring &list) {
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) {
return icd2.setCheats(list);
}
cheat.reset();
foreach(code, list) {
lstring codelist;

View File

@ -8,8 +8,18 @@ public:
virtual void connect(bool port, Input::Device device);
struct CartridgeData {
string xml;
const uint8_t *data;
unsigned size;
};
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 power();

View File

@ -4,7 +4,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "082.16";
static const char Version[] = "082.17";
static const unsigned SerializerVersion = 22;
}
}

View File

@ -30,9 +30,10 @@ using namespace ruby;
struct Application {
bool quit;
bool pause;
bool autopause;
string realpath;
string basepath;
string userpath;
string title;

View File

@ -14,7 +14,9 @@ Config::Config() {
attach(input.driver = "", "Input::Driver");
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.controllerPort2Device = 0, "NES::Controller::Port2");

View File

@ -18,7 +18,11 @@ struct Config : public configuration {
} input;
struct Path {
string last;
struct BIOS {
string satellaview;
string sufamiTurbo;
string superGameBoy;
} bios;
} path;
struct NES {

View File

@ -27,13 +27,13 @@ FileBrowser::FileBrowser() {
};
pathBrowse.onTick = [&] {
string path = OS::folderSelect(*this, activePath);
string path = OS::folderSelect(*this, mode->path);
if(path != "") setPath(path);
};
pathUp.onTick = [&] {
if(activePath == "/") return;
string path = activePath;
if(mode->path == "/") return;
string path = mode->path;
path.rtrim<1>("/");
path = dir(path);
setPath(path);
@ -41,18 +41,36 @@ FileBrowser::FileBrowser() {
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) {
this->callback = callback;
this->filterList = filterList;
FileBrowser::~FileBrowser() {
config.save(string{ application->userpath, "paths.cfg" });
}
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);
setPath(activePath);
setPath(mode->path);
string filterText = "Files of type: ";
foreach(filter, filterList) filterText.append(filter, ", ");
foreach(filter, mode->filter) filterText.append(filter, ", ");
filterText.trim<1>(", ");
filterLabel.setText(filterText);
@ -60,9 +78,9 @@ void FileBrowser::open(const string &title, const lstring &filterList, function<
}
void FileBrowser::setPath(const string &path) {
config->path.last = path;
activePath = path;
pathEdit.setText(activePath);
mode->path = path;
if(mode->path == "") mode->path = application->basepath;
pathEdit.setText(mode->path);
fileList.reset();
fileNameList.reset();
@ -71,8 +89,11 @@ void FileBrowser::setPath(const string &path) {
foreach(fileName, contentsList) {
if(fileName.endswith("/")) {
fileNameList.append(fileName);
} else foreach(filter, filterList) {
if(fileName.wildcard(filter)) fileNameList.append(fileName);
} else foreach(filter, mode->filter) {
if(fileName.wildcard(filter)) {
fileNameList.append(fileName);
break;
}
}
}
@ -84,8 +105,39 @@ void FileBrowser::setPath(const string &path) {
void FileBrowser::fileListActivate() {
unsigned selection = fileList.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);
}

View File

@ -9,18 +9,28 @@ struct FileBrowser : Window {
Label filterLabel;
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();
private:
string activePath;
lstring filterList;
configuration config;
struct FilterMode {
string name;
string path;
lstring filter;
} *mode;
linear_vector<FilterMode> filterModes;
lstring fileNameList;
function<void (string)> callback;
void setPath(const string &path);
void fileListActivate();
bool loadFolder(const string &path);
void loadFile(const string &filename);
};
extern FileBrowser *fileBrowser;

View File

@ -1,3 +1,4 @@
#include "../base.hpp"
#include "main-window.cpp"
#include "file-browser.cpp"
#include "slot-loader.cpp"

View File

@ -1,2 +1,3 @@
#include "main-window.hpp"
#include "file-browser.hpp"
#include "slot-loader.hpp"

View File

@ -10,6 +10,10 @@ MainWindow::MainWindow() {
cartridgeLoadSNES.setText("Load SNES Cartridge ...");
cartridgeLoadNES.setText("Load NES 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");
nesPower.setText("Power Cycle");
@ -86,13 +90,15 @@ MainWindow::MainWindow() {
toolsStateManager.setText("State Manager ...");
toolsTest.setText("Test");
helpMenu.setText("Help");
helpAbout.setText("About ...");
append(cartridgeMenu);
cartridgeMenu.append(cartridgeLoadNES);
cartridgeMenu.append(cartridgeLoadSNES);
cartridgeMenu.append(cartridgeLoadGameBoy);
cartridgeMenu.append(cartridgeSeparator);
cartridgeMenu.append(cartridgeLoadSatellaviewSlotted);
cartridgeMenu.append(cartridgeLoadSatellaview);
cartridgeMenu.append(cartridgeLoadSufamiTurbo);
cartridgeMenu.append(cartridgeLoadSuperGameBoy);
append(nesMenu);
nesMenu.append(nesPower);
@ -167,9 +173,6 @@ MainWindow::MainWindow() {
toolsMenu.append(toolsSeparator3);
toolsMenu.append(toolsTest);
append(helpMenu);
helpMenu.append(helpAbout);
setMenuVisible();
setStatusText("No cartridge loaded");
@ -182,23 +185,28 @@ MainWindow::MainWindow() {
onSize = [&] { utility->resizeMainWindow(); };
cartridgeLoadNES.onTick = [&] {
fileBrowser->open("Load NES Cartridge", { "*.nes" }, [](string filename) {
interface->loadCartridge(filename);
fileBrowser->open("Load Cartridge - NES", FileBrowser::Mode::NES, [](string filename) {
interface->nes.loadCartridge(filename);
});
};
cartridgeLoadSNES.onTick = [&] {
fileBrowser->open("Load SNES Cartridge", { "*.sfc" }, [](string filename) {
interface->loadCartridge(filename);
fileBrowser->open("Load Cartridge - SNES", FileBrowser::Mode::SNES, [](string filename) {
interface->snes.loadCartridge(filename);
});
};
cartridgeLoadGameBoy.onTick = [&] {
fileBrowser->open("Load Game Boy Cartridge", { "*.gb", "*.gbc" }, [](string filename) {
interface->loadCartridge(filename);
fileBrowser->open("Load Cartridge - Game Boy", FileBrowser::Mode::GameBoy, [](string 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 };
nesReset.onTick = { &Interface::reset, interface };
@ -276,19 +284,11 @@ MainWindow::MainWindow() {
NES::cpu.trace = toolsTest.checked();
};
helpAbout.onTick = [&] {
MessageWindow::information(*this, {
application->title, "\n\n",
"Author: byuu\n",
"Website: http://byuu.org/"
});
};
synchronize();
}
void MainWindow::synchronize() {
if(interface->loaded()) {
if(interface->cartridgeLoaded()) {
toolsStateSave.setEnabled(true);
toolsStateLoad.setEnabled(true);
} else {

View File

@ -6,6 +6,11 @@ struct MainWindow : Window {
Item cartridgeLoadSNES;
Item cartridgeLoadNES;
Item cartridgeLoadGameBoy;
Separator cartridgeSeparator;
Item cartridgeLoadSatellaviewSlotted;
Item cartridgeLoadSatellaview;
Item cartridgeLoadSufamiTurbo;
Item cartridgeLoadSuperGameBoy;
Menu nesMenu;
Item nesPower;
@ -67,9 +72,6 @@ struct MainWindow : Window {
Separator toolsSeparator3;
CheckItem toolsTest;
Menu helpMenu;
Item helpAbout;
void synchronize();
MainWindow();

185
bsnes/ui/general/slot-loader.cpp Executable file
View File

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

View File

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

View File

@ -3,6 +3,10 @@ void HotkeyGeneral::inputEvent(int16_t scancode, int16_t value) {
utility->toggleFullScreen();
}
if(scancode == pause.scancode && value) {
application->pause = !application->pause;
}
if(scancode == turboMode.scancode) {
static bool Vsync, Async;
if(value) {
@ -20,13 +24,16 @@ void HotkeyGeneral::inputEvent(int16_t scancode, int16_t value) {
HotkeyGeneral::HotkeyGeneral() {
name = "General";
toggleFullScreen.name = "Toggle Fullscreen";
turboMode.name = "Turbo Mode";
toggleFullScreen.name = "Toggle fullscreen";
pause.name = "Pause emulation";
turboMode.name = "Turbo mode";
toggleFullScreen.mapping = "KB0::F11";
pause.mapping = "KB0::P";
turboMode.mapping = "KB0::Tilde";
append(toggleFullScreen);
append(pause);
append(turboMode);
}

View File

@ -1,5 +1,6 @@
struct HotkeyGeneral : TertiaryInput {
DigitalInput toggleFullScreen;
DigitalInput pause;
DigitalInput turboMode;
void inputEvent(int16_t scancode, int16_t value);

View File

@ -3,11 +3,14 @@ bool InterfaceGameBoy::loadCartridge(const string &filename) {
unsigned size;
if(file::read(filename, data, size) == false) return false;
interface->unloadCartridge();
interface->baseName = nall::basename(filename);
GameBoyCartridge info(data, size);
GameBoy::Interface::loadCartridge(info.xml, data, size);
delete[] data;
interface->loadCartridge(::Interface::Mode::GameBoy);
return true;
}

View File

@ -25,7 +25,7 @@ void Interface::setController(unsigned port, unsigned device) {
}
}
bool Interface::loaded() {
bool Interface::cartridgeLoaded() {
switch(mode()) {
case Mode::NES: return nes.cartridgeLoaded();
case Mode::SNES: return snes.cartridgeLoaded();
@ -34,32 +34,28 @@ bool Interface::loaded() {
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 result = false;
setCheatCodes();
unloadCartridge();
if(filename.endswith(".nes")) result = loadCartridgeNES(filename);
if(filename.endswith(".sfc")) result = loadCartridgeSNES(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);
}
if(filename.endswith(".nes")) result = nes.loadCartridge(filename);
if(filename.endswith(".sfc")) result = snes.loadCartridge(filename);
if(filename.endswith(".gb" )) result = gameBoy.loadCartridge(filename);
if(filename.endswith(".gbc")) result = gameBoy.loadCartridge(filename);
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() {
if(loaded() == false) return;
if(cartridgeLoaded() == false) return;
cheatEditor->save({ baseName, ".cht" });
stateManager->save({ baseName, ".bsa" }, 0u);
setCheatCodes();
switch(mode()) {
case Mode::NES: nes.unloadCartridge(); break;
@ -70,33 +66,6 @@ void Interface::unloadCartridge() {
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() {
switch(mode()) {
case Mode::NES: return nes.power();
@ -138,19 +107,23 @@ bool Interface::unserialize(serializer &s) {
}
bool Interface::saveState(const string &filename) {
bool result = false;
switch(mode()) {
case Mode::SNES: return snes.saveState(filename);
case Mode::GameBoy: return gameBoy.saveState(filename);
case Mode::SNES: result = snes.saveState(filename); break;
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 result = false;
switch(mode()) {
case Mode::SNES: return snes.loadState(filename);
case Mode::GameBoy: return gameBoy.loadState(filename);
case Mode::SNES: result = snes.loadState(filename); break;
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) {
@ -178,7 +151,7 @@ void Interface::videoRefresh() {
time(&current);
if(current != previous) {
previous = current;
mainWindow->setStatusText({ "FPS: ", frameCounter });
utility->setStatusText({ "FPS: ", frameCounter });
frameCounter = 0;
}
}

View File

@ -9,17 +9,10 @@ struct Interface : property<Interface> {
void bindControllers();
void setController(unsigned port, unsigned device);
bool loaded();
bool loadCartridge(const string &filename);
bool loadCartridgeNES(const string &filename);
bool loadCartridgeSNES(const string &filename);
bool loadCartridgeGameBoy(const string &filename);
bool cartridgeLoaded();
void loadCartridge(Mode mode);
bool loadCartridge(const string &filename); //auto-detect system-type based on file extension
void unloadCartridge();
void unloadCartridgeNES();
void unloadCartridgeSNES();
void unloadCartridgeGameBoy();
void power();
void reset();
@ -38,7 +31,6 @@ struct Interface : property<Interface> {
string baseName; // = "/path/to/cartridge" (no extension)
private:
InterfaceNES nes;
InterfaceSNES snes;
InterfaceGameBoy gameBoy;

View File

@ -17,10 +17,13 @@ bool InterfaceNES::loadCartridge(const string &filename) {
filemap fp;
if(fp.open(filename, filemap::mode::read) == false) return false;
interface->unloadCartridge();
interface->baseName = nall::basename(filename);
NES::Interface::loadCartridge("", fp.data(), fp.size());
NES::Interface::loadCartridge("", fp.data(), fp.size());
fp.close();
interface->loadCartridge(::Interface::Mode::NES);
return true;
}

View File

@ -26,11 +26,95 @@ bool InterfaceSNES::loadCartridge(const string &filename) {
unsigned size;
if(file::read(filename, data, size) == false) return false;
interface->unloadCartridge();
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;
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;
}

View File

@ -2,6 +2,10 @@ struct InterfaceSNES : SNES::Interface {
void setController(bool port, unsigned device);
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();
bool saveState(const string &filename);

View File

@ -7,8 +7,9 @@ void Application::run() {
inputManager->scan();
autopause = (mainWindow->focused() == false && config->input.focusPolicy == 2);
utility->updateStatus();
if(interface->loaded() == false || autopause) {
if(interface->cartridgeLoaded() == false || pause || autopause) {
audio.clear();
usleep(20 * 1000);
return;
@ -17,12 +18,15 @@ void Application::run() {
interface->run();
}
Application::Application(int argc, char **argv) : quit(false) {
Application::Application(int argc, char **argv) {
application = this;
quit = false;
pause = false;
autopause = false;
{
char path[PATH_MAX];
auto unused = ::realpath(argv[0], path);
realpath = path;
basepath = path;
unused = ::userpath(path);
userpath = path;
#if defined(PLATFORM_WIN)
@ -52,6 +56,7 @@ Application::Application(int argc, char **argv) : quit(false) {
windowManager = new WindowManager;
mainWindow = new MainWindow;
fileBrowser = new FileBrowser;
slotLoader = new SlotLoader;
settingsWindow = new SettingsWindow;
cheatEditor = new CheatEditor;
stateManager = new StateManager;
@ -99,6 +104,7 @@ Application::~Application() {
delete stateManager;
delete cheatEditor;
delete settingsWindow;
delete slotLoader;
delete fileBrowser;
delete mainWindow;
delete windowManager;

View File

@ -43,7 +43,7 @@ CheatEditor::CheatEditor() {
}
void CheatEditor::synchronize() {
layout.setEnabled(interface->loaded());
layout.setEnabled(interface->cartridgeLoaded());
if(cheatList.selected()) {
unsigned n = cheatList.selection();

View File

@ -38,7 +38,7 @@ StateManager::StateManager() {
}
void StateManager::synchronize() {
layout.setEnabled(interface->loaded());
layout.setEnabled(interface->cartridgeLoaded());
descEdit.setText("");
descEdit.setEnabled(false);

View File

@ -71,14 +71,10 @@ void Utility::resizeMainWindow(bool shrink) {
}
}
void Utility::shrinkMainWindow() {
}
void Utility::toggleFullScreen() {
static bool fullScreen = false;
static Geometry geometry;
if(fullScreen == false) {
if(mainWindow->fullScreen() == false) {
geometry = mainWindow->geometry();
mainWindow->setMenuVisible(false);
mainWindow->setStatusVisible(false);
@ -92,7 +88,6 @@ void Utility::toggleFullScreen() {
mainWindow->setGeometry(geometry);
}
fullScreen ^= 1;
resizeMainWindow();
}
@ -101,3 +96,33 @@ void Utility::bindVideoShader() {
data.readfile(config->video.shader);
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;
}

View File

@ -1,9 +1,19 @@
struct Utility {
void setMode(Interface::Mode mode);
void resizeMainWindow(bool shrink = false);
void shrinkMainWindow();
void toggleFullScreen();
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;