Update to v070r02 release.

byuu says:

- added NTSC/PAL TV output mode selection
- added loading support for BSX Slotted, BSX, Sufami Turbo and Super
  Game Boy games
This commit is contained in:
Tim Allen 2010-09-28 21:25:29 +10:00
parent da5263bfc3
commit 73fdbf893f
18 changed files with 381 additions and 36 deletions

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "070.01";
static const char Version[] = "070.02";
static const unsigned SerializerVersion = 13;
}
}

View File

@ -38,23 +38,29 @@ extern Application application;
struct Style {
enum : unsigned {
#if defined(PHOENIX_WINDOWS)
ButtonHeight = 25,
CheckBoxHeight = 15,
ComboBoxHeight = 22,
EditBoxHeight = 22,
LabelHeight = 15,
SliderHeight = 25,
TextBoxHeight = 22,
#elif defined(PHOENIX_GTK)
ButtonHeight = 25,
CheckBoxHeight = 15,
ComboBoxHeight = 22,
EditBoxHeight = 22,
LabelHeight = 15,
SliderHeight = 22,
TextBoxHeight = 22,
#elif defined(PHOENIX_QT)
ButtonHeight = 25,
CheckBoxHeight = 15,
ComboBoxHeight = 22,
EditBoxHeight = 22,
LabelHeight = 15,
SliderHeight = 22,
TextBoxHeight = 22,
#endif
};
};

View File

@ -1,10 +1,10 @@
#include "../base.hpp"
Cartridge cartridge;
bool Cartridge::loadNormal(const char *filename) {
bool Cartridge::loadNormal(const char *basename) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, filename) == false) return false;
baseName = nall::basename(filename);
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
baseName = nall::basename(basename);
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, lstring() << baseXML);
loadMemory(SNES::memory::cartram, baseName, ".srm");
loadMemory(SNES::memory::cartrtc, baseName, ".rtc");
@ -12,10 +12,71 @@ bool Cartridge::loadNormal(const char *filename) {
return true;
}
bool Cartridge::loadBsxSlotted(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::bsxflash, slotAXML, slotname);
baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, lstring() << baseXML << slotAXML);
loadMemory(SNES::memory::cartram, baseName, ".srm");
loadMemory(SNES::memory::cartrtc, baseName, ".rtc");
utility.cartridgeLoaded();
return true;
}
bool Cartridge::loadBsx(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::bsxflash, slotAXML, slotname);
baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, lstring() << baseXML << slotAXML);
loadMemory(SNES::memory::bsxram, baseName, ".srm");
loadMemory(SNES::memory::bsxpram, baseName, ".psr");
utility.cartridgeLoaded();
return true;
}
bool Cartridge::loadSufamiTurbo(const char *basename, const char *slotAname, const char *slotBname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::stArom, slotAXML, slotAname);
loadCartridge(SNES::memory::stBrom, slotBXML, slotBname);
baseName = nall::basename(basename);
slotAName = nall::basename(slotAname);
slotBName = nall::basename(slotBname);
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, lstring() << baseXML << slotAXML << slotBXML);
loadMemory(SNES::memory::stAram, slotAName, ".srm");
loadMemory(SNES::memory::stBram, slotBName, ".srm");
utility.cartridgeLoaded();
return true;
}
bool Cartridge::loadSuperGameBoy(const char *basename, const char *slotname) {
unload();
if(loadCartridge(SNES::memory::cartrom, baseXML, basename) == false) return false;
loadCartridge(SNES::memory::gbrom, slotAXML, slotname);
baseName = nall::basename(basename);
slotAName = nall::basename(slotname);
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, lstring() << baseXML << slotAXML);
loadMemory(SNES::memory::gbram, slotAName, ".sav");
loadMemory(SNES::memory::gbrtc, slotAName, ".rtc");
utility.cartridgeLoaded();
return true;
}
void Cartridge::unload() {
if(SNES::cartridge.loaded() == false) return;
saveMemory(SNES::memory::cartram, baseName, ".srm");
saveMemory(SNES::memory::cartrtc, baseName, ".rtc");
saveMemory(SNES::memory::bsxram, baseName, ".srm");
saveMemory(SNES::memory::bsxpram, baseName, ".psr");
saveMemory(SNES::memory::stAram, slotAName, ".srm");
saveMemory(SNES::memory::stBram, slotBName, ".srm");
saveMemory(SNES::memory::gbram, slotAName, ".sav");
saveMemory(SNES::memory::gbrtc, slotAName, ".rtc");
baseName = slotAName = slotBName = "";
utility.cartridgeUnloaded();
}

View File

@ -1,5 +1,9 @@
struct Cartridge {
bool loadNormal(const char *filename);
bool loadNormal(const char *basename);
bool loadBsxSlotted(const char *basename, const char *slotname);
bool loadBsx(const char *basename, const char *slotname);
bool loadSufamiTurbo(const char *basename, const char *slotAname, const char *slotBname);
bool loadSuperGameBoy(const char *basename, const char *slotname);
void unload();
string baseName, slotAName, slotBName;

View File

@ -11,9 +11,13 @@ void Configuration::save() {
void Configuration::create() {
attach(path.current = "", "path.current");
attach(path.satellaviewBios = "", "path.satellaviewBios");
attach(path.sufamiTurboBios = "", "path.sufamiTurboBios");
attach(path.superGameBoyBios = "", "path.superGameBoyBios");
attach(video.driver = "", "video.driver");
attach(video.synchronize = false, "video.synchronize");
attach(video.region = 0, "video.region");
attach(video.smooth = true, "video.smooth");
attach(video.scale = 2, "video.scale");
attach(video.aspectRatioCorrection = true, "video.aspectRatioCorrection");

View File

@ -3,11 +3,15 @@ struct Configuration : public configuration {
string base;
string user;
string current;
string satellaviewBios;
string sufamiTurboBios;
string superGameBoyBios;
} path;
struct Video {
string driver;
bool synchronize;
bool region;
bool smooth;
unsigned scale;
bool aspectRatioCorrection;

View File

@ -5,9 +5,8 @@ void FileBrowser::create() {
Window::create(0, 0, 256, 256, "Load Cartridge");
setDefaultFont(application.proportionalFont);
unsigned x = 5, y = 5;
unsigned x = 5, y = 5, height = Style::TextBoxHeight;
unsigned height = Style::EditBoxHeight;
pathBox.create(*this, x, y, 630 - height - height - 10, height);
browseButton.create(*this, x + 630 - height - height - 5, y, height, height, "...");
upButton.create(*this, x + 630 - height, y, height, height, ".."); y += height + 5;
@ -22,18 +21,42 @@ void FileBrowser::create() {
contentsBox.onActivate = { &FileBrowser::fileActivate, this };
}
void FileBrowser::fileOpen(const char *pathname) {
void FileBrowser::fileOpen(FileBrowser::Mode requestedMode, function<void (string)> requestedCallback) {
callback = requestedCallback;
if(mode == requestedMode && string(folder, "/") == config.path.current) {
setVisible();
contentsBox.setFocused();
return;
}
filters.reset();
switch(mode = requestedMode) {
case Mode::Cartridge: {
filters.append(".sfc");
break;
}
case Mode::Satellaview: {
filters.append(".bs");
break;
}
case Mode::SufamiTurbo: {
filters.append(".st");
break;
}
case Mode::GameBoy: {
filters.append(".gb");
filters.append(".gbc");
filters.append(".sgb");
}
}
setVisible(false);
setFolder(pathname);
setFolder(config.path.current);
setVisible(true);
contentsBox.setFocused();
}
void FileBrowser::setFolder(const char *pathname) {
string path = pathname;
path.rtrim("/");
if(folder == path) return;
contentsBox.reset();
contents.reset();
@ -43,7 +66,14 @@ void FileBrowser::setFolder(const char *pathname) {
pathBox.setText(folder);
lstring contentsList = directory::contents(folder);
foreach(item, contentsList) {
if(strend(item, "/") || strend(item, ".sfc")) contents.append(item);
if(strend(item, "/")) {
contents.append(item);
} else foreach(filter, filters) {
if(strend(item, filter)) {
contents.append(item);
break;
}
}
}
foreach(item, contents) contentsBox.addItem(item);
contentsBox.setSelection(0);
@ -65,9 +95,10 @@ void FileBrowser::fileActivate() {
if(strend(filename, "/")) {
setFolder(string(folder, "/", filename));
} else {
filename = string(folder, "/", filename);
cartridge.loadNormal(filename);
setVisible(false);
filename = string(folder, "/", filename);
config.path.current = dir(filename);
if(callback) callback(filename);
}
}
}

View File

@ -4,11 +4,14 @@ struct FileBrowser : Window {
Button upButton;
ListBox contentsBox;
void fileOpen(const char *pathname);
enum class Mode : unsigned { Cartridge, Satellaview, SufamiTurbo, GameBoy } mode;
void fileOpen(Mode mode, function<void (string)> callback);
void create();
private:
function<void (string)> callback;
string folder;
lstring filters;
lstring contents;
void folderBrowse();

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

@ -9,6 +9,12 @@ void MainWindow::create() {
system.create(*this, "System");
systemLoadCartridge.create(system, "Load Cartridge ...");
systemLoadCartridgeSpecial.create(system, "Load Special");
systemLoadCartridgeBsxSlotted.create(systemLoadCartridgeSpecial, "Load BS-X Slotted Cartridge ...");
systemLoadCartridgeBsx.create(systemLoadCartridgeSpecial, "Load BS-X Cartridge ...");
systemLoadCartridgeSufamiTurbo.create(systemLoadCartridgeSpecial, "Load Sufami Turbo Cartridge ...");
systemLoadCartridgeSuperGameBoy.create(systemLoadCartridgeSpecial, "Load Super Game Boy Cartridge ...");
systemLoadCartridgeSuperGameBoy.setEnabled(SNES::supergameboy.opened());
systemSeparator1.create(system);
systemPower.create(system, "Power Cycle");
systemReset.create(system, "Reset");
@ -30,9 +36,14 @@ void MainWindow::create() {
if(config.video.scale == 3) settingsVideoMode3x.setChecked();
if(config.video.scale == 4) settingsVideoMode4x.setChecked();
if(config.video.scale == 5) settingsVideoMode5x.setChecked();
settingsVideoModeSeparator.create(settingsVideoMode);
settingsVideoModeSeparator1.create(settingsVideoMode);
settingsVideoModeAspectRatioCorrection.create(settingsVideoMode, "Correct Aspect Ratio");
settingsVideoModeAspectRatioCorrection.setChecked(config.video.aspectRatioCorrection);
settingsVideoModeSeparator2.create(settingsVideoMode);
settingsVideoModeNTSC.create(settingsVideoMode, "NTSC");
settingsVideoModePAL.create(settingsVideoModeNTSC, "PAL");
if(config.video.region == 0) settingsVideoModeNTSC.setChecked();
if(config.video.region == 1) settingsVideoModePAL.setChecked();
settingsSmoothVideo.create(settings, "Smooth Video");
settingsSmoothVideo.setChecked(config.video.smooth);
settingsSeparator1.create(settings);
@ -72,9 +83,11 @@ void MainWindow::create() {
setMenuVisible(true);
setStatusVisible(true);
systemLoadCartridge.onTick = []() {
utility.loadCartridgeNormal();
};
systemLoadCartridge.onTick = []() { utility.loadCartridgeNormal(); };
systemLoadCartridgeBsxSlotted.onTick = []() { singleSlotLoader.loadCartridgeBsxSlotted(); };
systemLoadCartridgeBsx.onTick = []() { singleSlotLoader.loadCartridgeBsx(); };
systemLoadCartridgeSufamiTurbo.onTick = []() { doubleSlotLoader.loadCartridgeSufamiTurbo(); };
systemLoadCartridgeSuperGameBoy.onTick = []() { singleSlotLoader.loadCartridgeSuperGameBoy(); };
systemPower.onTick = []() {
SNES::system.power();
@ -93,9 +106,13 @@ void MainWindow::create() {
settingsVideoMode5x.onTick = []() { utility.setScale(5); };
settingsVideoModeAspectRatioCorrection.onTick = []() {
utility.setAspectRatioCorrection(mainWindow.settingsVideoModeAspectRatioCorrection.checked());
config.video.aspectRatioCorrection = mainWindow.settingsVideoModeAspectRatioCorrection.checked();
utility.setScale();
};
settingsVideoModeNTSC.onTick = []() { config.video.region = 0; utility.setScale(); };
settingsVideoModePAL.onTick = []() { config.video.region = 1; utility.setScale(); };
settingsSmoothVideo.onTick = []() {
config.video.smooth = mainWindow.settingsSmoothVideo.checked();
video.set(Video::Filter, (unsigned)config.video.smooth);

View File

@ -1,6 +1,11 @@
struct MainWindow : Window {
Menu system;
MenuItem systemLoadCartridge;
Menu systemLoadCartridgeSpecial;
MenuItem systemLoadCartridgeBsxSlotted;
MenuItem systemLoadCartridgeBsx;
MenuItem systemLoadCartridgeSufamiTurbo;
MenuItem systemLoadCartridgeSuperGameBoy;
MenuSeparator systemSeparator1;
MenuItem systemPower;
MenuItem systemReset;
@ -14,8 +19,11 @@ struct MainWindow : Window {
MenuRadioItem settingsVideoMode3x;
MenuRadioItem settingsVideoMode4x;
MenuRadioItem settingsVideoMode5x;
MenuSeparator settingsVideoModeSeparator;
MenuSeparator settingsVideoModeSeparator1;
MenuCheckItem settingsVideoModeAspectRatioCorrection;
MenuSeparator settingsVideoModeSeparator2;
MenuRadioItem settingsVideoModeNTSC;
MenuRadioItem settingsVideoModePAL;
MenuCheckItem settingsSmoothVideo;
MenuSeparator settingsSeparator1;
MenuCheckItem settingsSynchronizeVideo;

View File

@ -0,0 +1,147 @@
SingleSlotLoader singleSlotLoader;
DoubleSlotLoader doubleSlotLoader;
void SingleSlotLoader::create() {
application.windows.append(this);
Window::create(0, 0, 256, 256);
setDefaultFont(application.proportionalFont);
unsigned x = 5, y = 5, height = Style::TextBoxHeight, width = 365 + height;
baseLabel.create(*this, x, y, 50, height, "Base:");
basePath.create(*this, x + 50, y, 300, height);
baseBrowse.create(*this, x + 355, y, height, height, "..."); y += height + 5;
slotLabel.create(*this, x, y, 50, height, "Slot:");
slotPath.create(*this, x + 50, y, 300, height);
slotBrowse.create(*this, x + 355, y, height, height, "..."); y += height + 5;
okButton.create(*this, x + width - 85, y, 80, Style::ButtonHeight, "Ok"); y += Style::ButtonHeight + 5;
setGeometry(160, 160, width, y);
baseBrowse.onTick = []() {
fileBrowser.fileOpen(FileBrowser::Mode::Cartridge, [](string filename) {
singleSlotLoader.basePath.setText(filename);
});
};
slotBrowse.onTick = []() {
FileBrowser::Mode fileMode = (singleSlotLoader.mode == Mode::SuperGameBoy
? FileBrowser::Mode::GameBoy : FileBrowser::Mode::Satellaview);
fileBrowser.fileOpen(fileMode, [](string filename) {
singleSlotLoader.slotPath.setText(filename);
});
};
okButton.onTick = { &SingleSlotLoader::load, this };
}
void SingleSlotLoader::loadCartridgeBsxSlotted() {
mode = Mode::BsxSlotted;
setTitle("Load BS-X Slotted Cartridge");
basePath.setText("");
slotPath.setText("");
setVisible();
okButton.setFocused();
}
void SingleSlotLoader::loadCartridgeBsx() {
mode = Mode::Bsx;
setTitle("Load BS-X Cartridge");
basePath.setText(config.path.satellaviewBios);
slotPath.setText("");
setVisible();
okButton.setFocused();
}
void SingleSlotLoader::loadCartridgeSuperGameBoy() {
mode = Mode::SuperGameBoy;
setTitle("Load Super Game Boy cartridge");
basePath.setText(config.path.superGameBoyBios);
slotPath.setText("");
setVisible();
okButton.setFocused();
}
void SingleSlotLoader::load() {
setVisible(false);
switch(mode) {
case Mode::BsxSlotted: {
cartridge.loadBsxSlotted(basePath.text(), slotPath.text());
break;
}
case Mode::Bsx: {
config.path.satellaviewBios = basePath.text();
cartridge.loadBsx(basePath.text(), slotPath.text());
break;
}
case Mode::SuperGameBoy: {
config.path.superGameBoyBios = basePath.text();
cartridge.loadSuperGameBoy(basePath.text(), slotPath.text());
break;
}
}
}
//
void DoubleSlotLoader::create() {
application.windows.append(this);
Window::create(0, 0, 256, 256);
setDefaultFont(application.proportionalFont);
unsigned x = 5, y = 5, height = Style::TextBoxHeight, width = 365 + height;
baseLabel.create(*this, x, y, 50, height, "Base:");
basePath.create(*this, x + 50, y, 300, height);
baseBrowse.create(*this, x + 355, y, height, height, "..."); y += height + 5;
slotALabel.create(*this, x, y, 50, height, "Slot A:");
slotAPath.create(*this, x + 50, y, 300, height);
slotABrowse.create(*this, x + 355, y, height, height, "..."); y += height + 5;
slotBLabel.create(*this, x, y, 50, height, "Slot B:");
slotBPath.create(*this, x + 50, y, 300, height);
slotBBrowse.create(*this, x + 355, y, height, height, "..."); y += height + 5;
okButton.create(*this, x + width - 85, y, 80, Style::ButtonHeight, "Ok"); y += Style::ButtonHeight + 5;
setGeometry(160, 160, width, y);
baseBrowse.onTick = []() {
fileBrowser.fileOpen(FileBrowser::Mode::Cartridge, [](string filename) {
doubleSlotLoader.basePath.setText(filename);
});
};
slotABrowse.onTick = []() {
fileBrowser.fileOpen(FileBrowser::Mode::SufamiTurbo, [](string filename) {
doubleSlotLoader.slotAPath.setText(filename);
});
};
slotBBrowse.onTick = []() {
fileBrowser.fileOpen(FileBrowser::Mode::SufamiTurbo, [](string filename) {
doubleSlotLoader.slotBPath.setText(filename);
});
};
okButton.onTick = { &DoubleSlotLoader::load, this };
}
void DoubleSlotLoader::loadCartridgeSufamiTurbo() {
setTitle("Load Sufami Turbo Cartridge");
basePath.setText(config.path.sufamiTurboBios);
slotAPath.setText("");
slotBPath.setText("");
setVisible();
okButton.setFocused();
}
void DoubleSlotLoader::load() {
setVisible(false);
config.path.sufamiTurboBios = basePath.text();
cartridge.loadSufamiTurbo(basePath.text(), slotAPath.text(), slotBPath.text());
}

View File

@ -0,0 +1,38 @@
struct SingleSlotLoader : Window {
Label baseLabel;
TextBox basePath;
Button baseBrowse;
Label slotLabel;
TextBox slotPath;
Button slotBrowse;
Button okButton;
void create();
void loadCartridgeBsxSlotted();
void loadCartridgeBsx();
void loadCartridgeSuperGameBoy();
enum class Mode : unsigned { BsxSlotted, Bsx, SuperGameBoy } mode;
void load();
};
struct DoubleSlotLoader : Window {
Label baseLabel;
TextBox basePath;
Button baseBrowse;
Label slotALabel;
TextBox slotAPath;
Button slotABrowse;
Label slotBLabel;
TextBox slotBPath;
Button slotBBrowse;
Button okButton;
void create();
void loadCartridgeSufamiTurbo();
void load();
};
extern SingleSlotLoader singleSlotLoader;
extern DoubleSlotLoader doubleSlotLoader;

View File

@ -71,6 +71,20 @@ void Interface::video_refresh(const uint16_t *data, unsigned width, unsigned hei
uint32_t *buffer;
unsigned outpitch;
if(config.video.region == 0 && (height == 239 || height == 478)) {
//NTSC overscan compensation (center image, remove 15 lines)
data += 7 * 1024;
if(height == 239) height = 224;
if(height == 478) height = 448;
}
if(config.video.region == 1 && (height == 224 || height == 448)) {
//PAL underscan compensation (center image, add 15 lines)
data -= 7 * 1024;
if(height == 224) height = 239;
if(height == 448) height = 478;
}
if(video.lock(buffer, outpitch, width, height)) {
for(unsigned y = 0; y < height; y++) {
uint32_t *output = buffer + y * (outpitch >> 2);

View File

@ -33,6 +33,8 @@ void Application::main(int argc, char **argv) {
monospaceFont.create("Liberation Mono", 8);
#endif
SNES::system.init(&interface);
if(config.video.driver == "") config.video.driver = video.default_driver();
if(config.audio.driver == "") config.audio.driver = audio.default_driver();
if(config.input.driver == "") config.input.driver = video.default_driver();
@ -40,6 +42,8 @@ void Application::main(int argc, char **argv) {
palette.update();
mainWindow.create();
fileBrowser.create();
singleSlotLoader.create();
doubleSlotLoader.create();
videoSettings.create();
audioSettings.create();
inputSettings.create();
@ -81,7 +85,6 @@ void Application::main(int argc, char **argv) {
input.init();
}
SNES::system.init(&interface);
if(argc == 2) cartridge.loadNormal(argv[1]);
while(quit == false) {

View File

@ -35,26 +35,28 @@ void Utility::showMessage(const char *text) {
}
void Utility::setScale(unsigned scale) {
if(scale == 0) scale = config.video.scale;
config.video.scale = scale;
unsigned width = 256 * scale;
unsigned height = 224 * scale;
if(config.video.aspectRatioCorrection) width *= 54.0 / 47.0; //PAL = 32.0 / 23.0
unsigned width, height;
if(config.video.region == 0) {
width = 256 * scale;
height = 224 * scale;
if(config.video.aspectRatioCorrection) width *= 54.0 / 47.0;
} else {
width = 256 * scale;
height = 239 * scale;
if(config.video.aspectRatioCorrection) width *= 32.0 / 23.0;
}
mainWindow.viewport.setGeometry(0, 0, width, height);
mainWindow.setGeometry(128, 128, width, height);
}
void Utility::setAspectRatioCorrection(bool aspectRatioCorrection) {
config.video.aspectRatioCorrection = aspectRatioCorrection;
setScale(config.video.scale);
}
void Utility::cartridgeLoaded() {
SNES::system.power();
cheatEditor.load(cartridge.baseName);
mainWindow.synchronize();
utility.setTitle(notdir(cartridge.baseName));
utility.showMessage(string("Loaded ", notdir(cartridge.baseName)));
config.path.current = dir(cartridge.baseName);
}
void Utility::cartridgeUnloaded() {
@ -65,7 +67,9 @@ void Utility::cartridgeUnloaded() {
void Utility::loadCartridgeNormal() {
if(config.settings.useNativeDialogs == false) {
fileBrowser.fileOpen(config.path.current);
fileBrowser.fileOpen(FileBrowser::Mode::Cartridge, [](string filename) {
cartridge.loadNormal(filename);
});
} else {
string filename = os.fileOpen(mainWindow, "SNES cartridges\t*.sfc\nAll files\t*", config.path.current);
if(filename != "") {

View File

@ -4,8 +4,7 @@ struct Utility : property<Utility> {
void setStatus(const char *text);
void showMessage(const char *text);
void setScale(unsigned scale);
void setAspectRatioCorrection(bool aspectRatioCorrection);
void setScale(unsigned scale = 0);
void cartridgeLoaded();
void cartridgeUnloaded();