mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r27 release.
byuu says: Changelog: - nall: merged Path::config() and Path::local() to Path::userData() - ~/.local/share or %appdata or ~/Library/ApplicationSupport - higan, bsnes: render main window icon onto viewport instead of canvas - should hopefully fix a brief flickering glitch that appears on Windows - icarus: improved Super Famicom heuristics for Starfox / Starwing RAM - ruby/Direct3D: handle viewport size changes in lock() instead of output() - fixes icon disappearing when resizing main window - hiro/Windows: remove WS_DISABLED from StatusBar to fix window resize grip - this is experimental: I initially used WS_DISABLED to work around a focus bug - yet trying things now, said bug seems(?) to have gone away at some point ... - bsnes: added advanced settings panel with real-time driver change support I'd like feedback on the real-time driver change, for possible consideration into adding this to higan as well. Some drivers just crash, it's a fact of life. The ASIO driver in particular likes to crash inside the driver itself, without any error messages ever returned to try and catch. When you try to change a driver with a game loaded, it gives you a scary warning, asking if you want to proceed. When you change a driver, it sets a crash flag, and if the driver crashes while initializing, then restarting bsnes will disable the errant driver. If it fails in a recoverable way, then it sets the driver to “None” and warns you that the driver cannot be used. What I'm thinking of further adding is to call emulator→save() to write out the save RAM contents beforehand (although the periodic auto-saving RAM will handle this anyway when it's enabled), and possibly it might be wise to capture an emulator save state, although those can't be taken without advancing the emulator to the next frame, so that might not be a good idea. I'm also thinking we should show some kind of message somewhere when a driver is set to “None”. The status bar can be hidden, so perhaps on the title bar? Or maybe just a warning on startup that a driver is set to “None”.
This commit is contained in:
parent
ec4ab1dc11
commit
2b8df2e70e
|
@ -12,7 +12,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "106.26";
|
static const string Version = "106.27";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org/";
|
static const string Website = "https://byuu.org/";
|
||||||
|
|
|
@ -9,11 +9,8 @@ auto locate(string name) -> string {
|
||||||
string location = {Path::program(), name};
|
string location = {Path::program(), name};
|
||||||
if(inode::exists(location)) return location;
|
if(inode::exists(location)) return location;
|
||||||
|
|
||||||
location = {Path::config(), "bsnes/", name};
|
directory::create({Path::userData(), "bsnes/"});
|
||||||
if(inode::exists(location)) return location;
|
return {Path::userData(), "bsnes/", name};
|
||||||
|
|
||||||
directory::create({Path::local(), "bsnes/"});
|
|
||||||
return {Path::local(), "bsnes/", name};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <nall/main.hpp>
|
#include <nall/main.hpp>
|
||||||
|
|
|
@ -99,6 +99,7 @@ Presentation::Presentation() {
|
||||||
inputSettings.setText("Input ...").onActivate([&] { settingsWindow->show(0); });
|
inputSettings.setText("Input ...").onActivate([&] { settingsWindow->show(0); });
|
||||||
hotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsWindow->show(1); });
|
hotkeySettings.setText("Hotkeys ...").onActivate([&] { settingsWindow->show(1); });
|
||||||
pathSettings.setText("Paths ...").onActivate([&] { settingsWindow->show(2); });
|
pathSettings.setText("Paths ...").onActivate([&] { settingsWindow->show(2); });
|
||||||
|
advancedSettings.setText("Advanced ...").onActivate([&] { settingsWindow->show(3); });
|
||||||
|
|
||||||
toolsMenu.setText("Tools");
|
toolsMenu.setText("Tools");
|
||||||
saveState.setText("Save State").setEnabled(false);
|
saveState.setText("Save State").setEnabled(false);
|
||||||
|
@ -122,10 +123,6 @@ Presentation::Presentation() {
|
||||||
aboutWindow->setCentered(*this).setVisible().setFocused();
|
aboutWindow->setCentered(*this).setVisible().setFocused();
|
||||||
});
|
});
|
||||||
|
|
||||||
image icon{Resource::Icon};
|
|
||||||
icon.alphaBlend(0xff000000);
|
|
||||||
canvas.setIcon(icon).setVisible(false);
|
|
||||||
|
|
||||||
viewport.setDroppable().onDrop([&](auto locations) {
|
viewport.setDroppable().onDrop([&](auto locations) {
|
||||||
program->gameQueue = locations;
|
program->gameQueue = locations;
|
||||||
program->load();
|
program->load();
|
||||||
|
@ -149,10 +146,10 @@ Presentation::Presentation() {
|
||||||
setCentered();
|
setCentered();
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
Application::Windows::onModalChange([](bool modal) {
|
Application::Windows::onModalChange([&](bool modal) {
|
||||||
if(modal && audio) audio->clear();
|
if(modal && audio) audio->clear();
|
||||||
});
|
});
|
||||||
Application::Windows::onScreenSaver([]() -> bool {
|
Application::Windows::onScreenSaver([&]() -> bool {
|
||||||
if(emulator->loaded()) {
|
if(emulator->loaded()) {
|
||||||
if(pauseEmulation.checked()) return true;
|
if(pauseEmulation.checked()) return true;
|
||||||
if(!program->focused() && settingsWindow->input.pauseEmulation.checked()) return true;
|
if(!program->focused() && settingsWindow->input.pauseEmulation.checked()) return true;
|
||||||
|
@ -170,24 +167,27 @@ Presentation::Presentation() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::showIcon() -> void {
|
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {
|
||||||
Application::processEvents();
|
int ox = width - 144;
|
||||||
int width = geometry().width();
|
int oy = height - 128;
|
||||||
int height = geometry().height();
|
if(ox >= 0 && oy >= 0) {
|
||||||
int x = width - 144;
|
image icon{Resource::Icon};
|
||||||
int y = height - 128;
|
icon.alphaBlend(0xff000000);
|
||||||
if(x >= 0 && y >= 0) {
|
for(uint y : range(128)) {
|
||||||
canvas.setVisible(true).setGeometry({x, y, 128, 128});
|
auto target = output + (y + oy) * (length >> 2) + ox;
|
||||||
} else {
|
auto source = (uint32_t*)icon.data() + y * 128;
|
||||||
canvas.setVisible(false);
|
memory::copy(target, source, 128 * sizeof(uint32_t));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
viewport.setGeometry({0, 0, 1, 1});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::clearViewport() -> void {
|
auto Presentation::clearViewport() -> void {
|
||||||
if(!emulator->loaded()) showIcon();
|
|
||||||
if(!video) return;
|
if(!video) return;
|
||||||
|
|
||||||
|
if(!emulator->loaded()) {
|
||||||
|
viewport.setGeometry({0, 0, geometry().width(), geometry().height()});
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t* output;
|
uint32_t* output;
|
||||||
uint length;
|
uint length;
|
||||||
uint width = viewport.geometry().width();
|
uint width = viewport.geometry().width();
|
||||||
|
@ -197,17 +197,21 @@ auto Presentation::clearViewport() -> void {
|
||||||
auto line = output + y * (length >> 2);
|
auto line = output + y * (length >> 2);
|
||||||
for(uint x : range(width)) *line++ = 0xff000000;
|
for(uint x : range(width)) *line++ = 0xff000000;
|
||||||
}
|
}
|
||||||
|
if(!emulator->loaded()) drawIcon(output, length, width, height);
|
||||||
video->unlock();
|
video->unlock();
|
||||||
video->output();
|
video->output();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::resizeViewport() -> void {
|
auto Presentation::resizeViewport() -> void {
|
||||||
if(emulator->loaded()) canvas.setVisible(false);
|
|
||||||
|
|
||||||
uint windowWidth = geometry().width();
|
uint windowWidth = geometry().width();
|
||||||
uint windowHeight = geometry().height();
|
uint windowHeight = geometry().height();
|
||||||
|
|
||||||
|
if(!emulator->loaded()) {
|
||||||
|
viewport.setGeometry({0, 0, windowWidth, windowHeight});
|
||||||
|
return clearViewport();
|
||||||
|
}
|
||||||
|
|
||||||
double width = 224 * (settings["View/AspectCorrection"].boolean() ? 8.0 / 7.0 : 1.0);
|
double width = 224 * (settings["View/AspectCorrection"].boolean() ? 8.0 / 7.0 : 1.0);
|
||||||
double height = (settings["View/OverscanCropping"].boolean() ? 224.0 : 240.0);
|
double height = (settings["View/OverscanCropping"].boolean() ? 224.0 : 240.0);
|
||||||
|
|
||||||
|
@ -265,6 +269,9 @@ auto Presentation::toggleFullscreenMode() -> void {
|
||||||
menuBar.setVisible(true);
|
menuBar.setVisible(true);
|
||||||
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
|
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
|
||||||
}
|
}
|
||||||
|
//hack: give window geometry time to update after toggling fullscreen and menu/status bars
|
||||||
|
usleep(20 * 1000);
|
||||||
|
Application::processEvents();
|
||||||
resizeViewport();
|
resizeViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ struct AboutWindow : Window {
|
||||||
|
|
||||||
struct Presentation : Window {
|
struct Presentation : Window {
|
||||||
Presentation();
|
Presentation();
|
||||||
auto showIcon() -> void;
|
auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void;
|
||||||
auto clearViewport() -> void;
|
auto clearViewport() -> void;
|
||||||
auto resizeViewport() -> void;
|
auto resizeViewport() -> void;
|
||||||
auto resizeWindow() -> void;
|
auto resizeWindow() -> void;
|
||||||
|
@ -49,6 +49,7 @@ struct Presentation : Window {
|
||||||
MenuItem inputSettings{&settingsMenu};
|
MenuItem inputSettings{&settingsMenu};
|
||||||
MenuItem hotkeySettings{&settingsMenu};
|
MenuItem hotkeySettings{&settingsMenu};
|
||||||
MenuItem pathSettings{&settingsMenu};
|
MenuItem pathSettings{&settingsMenu};
|
||||||
|
MenuItem advancedSettings{&settingsMenu};
|
||||||
Menu toolsMenu{&menuBar};
|
Menu toolsMenu{&menuBar};
|
||||||
Menu saveState{&toolsMenu};
|
Menu saveState{&toolsMenu};
|
||||||
MenuItem saveState1{&saveState};
|
MenuItem saveState1{&saveState};
|
||||||
|
@ -67,7 +68,6 @@ struct Presentation : Window {
|
||||||
MenuItem about{&helpMenu};
|
MenuItem about{&helpMenu};
|
||||||
|
|
||||||
FixedLayout layout{this};
|
FixedLayout layout{this};
|
||||||
Canvas canvas{&layout, Geometry{0, 0, 1, 1}};
|
|
||||||
Viewport viewport{&layout, Geometry{0, 0, 1, 1}};
|
Viewport viewport{&layout, Geometry{0, 0, 1, 1}};
|
||||||
|
|
||||||
StatusBar statusBar{this};
|
StatusBar statusBar{this};
|
||||||
|
|
|
@ -14,7 +14,10 @@ Program::Program(string_vector arguments) {
|
||||||
presentation->setVisible();
|
presentation->setVisible();
|
||||||
|
|
||||||
if(settings["Crashed"].boolean()) {
|
if(settings["Crashed"].boolean()) {
|
||||||
MessageDialog().setText("Driver crash detected. Hardware drivers have been disabled.").information();
|
MessageDialog(
|
||||||
|
"Driver crash detected. Hardware drivers have been disabled.\n"
|
||||||
|
"Please reconfigure drivers in the advanced settings panel."
|
||||||
|
).setParent(*presentation).information();
|
||||||
settings["Video/Driver"].setValue("None");
|
settings["Video/Driver"].setValue("None");
|
||||||
settings["Audio/Driver"].setValue("None");
|
settings["Audio/Driver"].setValue("None");
|
||||||
settings["Input/Driver"].setValue("None");
|
settings["Input/Driver"].setValue("None");
|
||||||
|
@ -24,8 +27,29 @@ Program::Program(string_vector arguments) {
|
||||||
settings.save();
|
settings.save();
|
||||||
|
|
||||||
initializeVideoDriver();
|
initializeVideoDriver();
|
||||||
|
if(!video->ready()) {
|
||||||
|
MessageDialog({
|
||||||
|
"Error: failed to initialize ", settings["Video/Driver"].text(), " video driver."
|
||||||
|
}).setParent(*presentation).error();
|
||||||
|
settings["Video/Driver"].setValue("None");
|
||||||
|
initializeVideoDriver();
|
||||||
|
}
|
||||||
initializeAudioDriver();
|
initializeAudioDriver();
|
||||||
|
if(!audio->ready()) {
|
||||||
|
MessageDialog({
|
||||||
|
"Error: failed to initialize ", settings["Audio/Driver"].text(), " audio driver."
|
||||||
|
}).setParent(*presentation).error();
|
||||||
|
settings["Audio/Driver"].setValue("None");
|
||||||
|
initializeAudioDriver();
|
||||||
|
}
|
||||||
initializeInputDriver();
|
initializeInputDriver();
|
||||||
|
if(!input->ready()) {
|
||||||
|
MessageDialog({
|
||||||
|
"Error: failed to initialize ", settings["Input/Driver"].text(), " input driver."
|
||||||
|
}).setParent(*presentation).error();
|
||||||
|
settings["Input/Driver"].setValue("None");
|
||||||
|
initializeInputDriver();
|
||||||
|
}
|
||||||
|
|
||||||
settings["Crashed"].setValue(false);
|
settings["Crashed"].setValue(false);
|
||||||
settings.save();
|
settings.save();
|
||||||
|
|
|
@ -3,12 +3,11 @@ auto Program::initializeVideoDriver() -> void {
|
||||||
video->setContext(presentation->viewport.handle());
|
video->setContext(presentation->viewport.handle());
|
||||||
video->setExclusive(false);
|
video->setExclusive(false);
|
||||||
video->setBlocking(settings["Video/Blocking"].boolean());
|
video->setBlocking(settings["Video/Blocking"].boolean());
|
||||||
if(!video->ready()) {
|
|
||||||
MessageDialog().setText("Failed to initialize video driver").warning();
|
if(video->ready()) {
|
||||||
video = Video::create("None");
|
|
||||||
}
|
|
||||||
presentation->clearViewport();
|
presentation->clearViewport();
|
||||||
updateVideoShader();
|
updateVideoShader();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::initializeAudioDriver() -> void {
|
auto Program::initializeAudioDriver() -> void {
|
||||||
|
@ -29,19 +28,11 @@ auto Program::initializeAudioDriver() -> void {
|
||||||
}
|
}
|
||||||
audio->setLatency(settings["Audio/Latency"].natural());
|
audio->setLatency(settings["Audio/Latency"].natural());
|
||||||
audio->setChannels(2);
|
audio->setChannels(2);
|
||||||
if(!audio->ready()) {
|
|
||||||
MessageDialog().setText("Failed to initialize audio driver").warning();
|
|
||||||
audio = Audio::create("None");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::initializeInputDriver() -> void {
|
auto Program::initializeInputDriver() -> void {
|
||||||
input = Input::create(settings["Input/Driver"].text());
|
input = Input::create(settings["Input/Driver"].text());
|
||||||
input->setContext(presentation->viewport.handle());
|
input->setContext(presentation->viewport.handle());
|
||||||
if(!input->ready()) {
|
|
||||||
MessageDialog().setText("Failed to initialize input driver").warning();
|
|
||||||
input = Input::create("None");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::updateVideoShader() -> void {
|
auto Program::updateVideoShader() -> void {
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
|
setIcon(Icon::Action::Settings);
|
||||||
|
setText("Advanced");
|
||||||
|
|
||||||
|
layout.setMargin(5);
|
||||||
|
|
||||||
|
videoDriverLabel.setText("Video Driver:");
|
||||||
|
for(auto& driver : Video::availableDrivers()) {
|
||||||
|
ComboButtonItem item;
|
||||||
|
item.setText(driver);
|
||||||
|
videoDriverOption.append(item);
|
||||||
|
if(video->driver() == driver) item.setSelected();
|
||||||
|
}
|
||||||
|
videoDriverOption.onChange([&] {
|
||||||
|
auto item = videoDriverOption.selected();
|
||||||
|
videoDriverChange.setEnabled(video->driver() != item.text());
|
||||||
|
});
|
||||||
|
videoDriverChange.setText("Change").setEnabled(false).onActivate([&] {
|
||||||
|
auto item = videoDriverOption.selected();
|
||||||
|
settings["Video/Driver"].setValue(item.text());
|
||||||
|
if(!emulator->loaded() || item.text() == "None" || MessageDialog(
|
||||||
|
"Warning: incompatible drivers may cause bsnes to crash.\n"
|
||||||
|
"It is highly recommended you unload your game first to avoid data loss.\n"
|
||||||
|
"Do you wish to proceed with the video driver change now anyway?"
|
||||||
|
).setParent(*settingsWindow).question() == "Yes") {
|
||||||
|
settings["Crashed"].setValue(true);
|
||||||
|
settings.save();
|
||||||
|
program->initializeVideoDriver();
|
||||||
|
if(!video->ready()) {
|
||||||
|
MessageDialog({
|
||||||
|
"Error: failed to initialize ", item.text(), " video driver."
|
||||||
|
}).setParent(*settingsWindow).error();
|
||||||
|
settings["Video/Driver"].setValue("None");
|
||||||
|
program->initializeVideoDriver();
|
||||||
|
for(auto item : videoDriverOption.items()) {
|
||||||
|
if(video->driver() == item.text()) item.setSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings["Crashed"].setValue(false);
|
||||||
|
settings.save();
|
||||||
|
videoDriverChange.setEnabled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
audioDriverLabel.setText("Audio Driver:");
|
||||||
|
for(auto& driver : Audio::availableDrivers()) {
|
||||||
|
ComboButtonItem item;
|
||||||
|
item.setText(driver);
|
||||||
|
audioDriverOption.append(item);
|
||||||
|
if(audio->driver() == driver) item.setSelected();
|
||||||
|
}
|
||||||
|
audioDriverOption.onChange([&] {
|
||||||
|
auto item = audioDriverOption.selected();
|
||||||
|
audioDriverChange.setEnabled(audio->driver() != item.text());
|
||||||
|
});
|
||||||
|
audioDriverChange.setText("Change").setEnabled(false).onActivate([&] {
|
||||||
|
auto item = audioDriverOption.selected();
|
||||||
|
settings["Audio/Driver"].setValue(item.text());
|
||||||
|
if(!emulator->loaded() || item.text() == "None" || MessageDialog(
|
||||||
|
"Warning: incompatible drivers may cause bsnes to crash.\n"
|
||||||
|
"It is highly recommended you unload your game first to avoid data loss.\n"
|
||||||
|
"Do you wish to proceed with the audio driver change now anyway?"
|
||||||
|
).setParent(*settingsWindow).question() == "Yes") {
|
||||||
|
settings["Crashed"].setValue(true);
|
||||||
|
settings.save();
|
||||||
|
program->initializeAudioDriver();
|
||||||
|
if(!audio->ready()) {
|
||||||
|
MessageDialog({
|
||||||
|
"Error: failed to initialize ", item.text(), " audio driver."
|
||||||
|
}).setParent(*settingsWindow).error();
|
||||||
|
settings["Audio/Driver"].setValue("None");
|
||||||
|
program->initializeAudioDriver();
|
||||||
|
for(auto item : audioDriverOption.items()) {
|
||||||
|
if(audio->driver() == item.text()) item.setSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings["Crashed"].setValue(false);
|
||||||
|
settings.save();
|
||||||
|
audioDriverChange.setEnabled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
inputDriverLabel.setText("Input Driver:");
|
||||||
|
for(auto& driver : Input::availableDrivers()) {
|
||||||
|
ComboButtonItem item;
|
||||||
|
item.setText(driver);
|
||||||
|
inputDriverOption.append(item);
|
||||||
|
if(input->driver() == driver) item.setSelected();
|
||||||
|
}
|
||||||
|
inputDriverOption.onChange([&] {
|
||||||
|
auto item = inputDriverOption.selected();
|
||||||
|
inputDriverChange.setEnabled(input->driver() != item.text());
|
||||||
|
});
|
||||||
|
inputDriverChange.setText("Change").setEnabled(false).onActivate([&] {
|
||||||
|
auto item = inputDriverOption.selected();
|
||||||
|
settings["Input/Driver"].setValue(item.text());
|
||||||
|
if(!emulator->loaded() || item.text() == "None" || MessageDialog(
|
||||||
|
"Warning: incompatible drivers may cause bsnes to crash.\n"
|
||||||
|
"It is highly recommended you unload your game first to avoid data loss.\n"
|
||||||
|
"Do you wish to proceed with the input driver change now anyway?"
|
||||||
|
).setParent(*settingsWindow).question() == "Yes") {
|
||||||
|
settings["Crashed"].setValue(true);
|
||||||
|
settings.save();
|
||||||
|
program->initializeInputDriver();
|
||||||
|
if(!input->ready()) {
|
||||||
|
MessageDialog({
|
||||||
|
"Error: failed to initialize ", item.text(), " input driver."
|
||||||
|
}).setParent(*settingsWindow).error();
|
||||||
|
settings["Input/Driver"].setValue("None");
|
||||||
|
program->initializeInputDriver();
|
||||||
|
for(auto item : inputDriverOption.items()) {
|
||||||
|
if(input->driver() == item.text()) item.setSelected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
settings["Crashed"].setValue(false);
|
||||||
|
settings.save();
|
||||||
|
inputDriverChange.setEnabled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#include "input.cpp"
|
#include "input.cpp"
|
||||||
#include "hotkeys.cpp"
|
#include "hotkeys.cpp"
|
||||||
#include "paths.cpp"
|
#include "paths.cpp"
|
||||||
|
#include "advanced.cpp"
|
||||||
Settings settings;
|
Settings settings;
|
||||||
unique_pointer<SettingsWindow> settingsWindow;
|
unique_pointer<SettingsWindow> settingsWindow;
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,25 @@ public:
|
||||||
Button cheatsReset{&cheatsLayout, Size{80, 0}};
|
Button cheatsReset{&cheatsLayout, Size{80, 0}};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AdvancedSettings : TabFrameItem {
|
||||||
|
AdvancedSettings(TabFrame*);
|
||||||
|
|
||||||
|
public:
|
||||||
|
VerticalLayout layout{this};
|
||||||
|
HorizontalLayout videoDriverLayout{&layout, Size{~0, 0}};
|
||||||
|
Label videoDriverLabel{&videoDriverLayout, Size{75, 0}};
|
||||||
|
ComboButton videoDriverOption{&videoDriverLayout, Size{~0, 0}};
|
||||||
|
Button videoDriverChange{&videoDriverLayout, Size{80, 0}};
|
||||||
|
HorizontalLayout audioDriverLayout{&layout, Size{~0, 0}};
|
||||||
|
Label audioDriverLabel{&audioDriverLayout, Size{75, 0}};
|
||||||
|
ComboButton audioDriverOption{&audioDriverLayout, Size{~0, 0}};
|
||||||
|
Button audioDriverChange{&audioDriverLayout, Size{80, 0}};
|
||||||
|
HorizontalLayout inputDriverLayout{&layout, Size{~0, 0}};
|
||||||
|
Label inputDriverLabel{&inputDriverLayout, Size{75, 0}};
|
||||||
|
ComboButton inputDriverOption{&inputDriverLayout, Size{~0, 0}};
|
||||||
|
Button inputDriverChange{&inputDriverLayout, Size{80, 0}};
|
||||||
|
};
|
||||||
|
|
||||||
struct SettingsWindow : Window {
|
struct SettingsWindow : Window {
|
||||||
SettingsWindow();
|
SettingsWindow();
|
||||||
auto setVisible(bool visible = true) -> SettingsWindow&;
|
auto setVisible(bool visible = true) -> SettingsWindow&;
|
||||||
|
@ -105,6 +124,7 @@ public:
|
||||||
InputSettings input{&panel};
|
InputSettings input{&panel};
|
||||||
HotkeySettings hotkeys{&panel};
|
HotkeySettings hotkeys{&panel};
|
||||||
PathSettings paths{&panel};
|
PathSettings paths{&panel};
|
||||||
|
AdvancedSettings advanced{&panel};
|
||||||
StatusBar statusBar{this};
|
StatusBar statusBar{this};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,8 @@ auto locate(string name) -> string {
|
||||||
string location = {Path::program(), name};
|
string location = {Path::program(), name};
|
||||||
if(inode::exists(location)) return location;
|
if(inode::exists(location)) return location;
|
||||||
|
|
||||||
location = {Path::config(), "higan/", name};
|
directory::create({Path::userData(), "higan/"});
|
||||||
if(inode::exists(location)) return location;
|
return {Path::userData(), "higan/", name};
|
||||||
|
|
||||||
directory::create({Path::local(), "higan/"});
|
|
||||||
return {Path::local(), "higan/", name};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <nall/main.hpp>
|
#include <nall/main.hpp>
|
||||||
|
|
|
@ -143,10 +143,10 @@ Presentation::Presentation() {
|
||||||
setCentered();
|
setCentered();
|
||||||
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
Application::Windows::onModalChange([](bool modal) {
|
Application::Windows::onModalChange([&](bool modal) {
|
||||||
if(modal && audio) audio->clear();
|
if(modal && audio) audio->clear();
|
||||||
});
|
});
|
||||||
Application::Windows::onScreenSaver([]() -> bool {
|
Application::Windows::onScreenSaver([&]() -> bool {
|
||||||
if(emulator && emulator->loaded()) {
|
if(emulator && emulator->loaded()) {
|
||||||
if(program->pause) return true;
|
if(program->pause) return true;
|
||||||
if(!program->focused() && settingsManager->input.pauseEmulation.checked()) return true;
|
if(!program->focused() && settingsManager->input.pauseEmulation.checked()) return true;
|
||||||
|
@ -205,24 +205,27 @@ auto Presentation::updateEmulator() -> void {
|
||||||
emulator->set("Scanline Emulation", scanlineEmulation.checked());
|
emulator->set("Scanline Emulation", scanlineEmulation.checked());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::showIcon() -> void {
|
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {
|
||||||
Application::processEvents();
|
int ox = width - 128;
|
||||||
int width = geometry().width();
|
int oy = height - 128;
|
||||||
int height = geometry().height();
|
if(ox >= 0 && oy >= 0) {
|
||||||
int x = width - 128;
|
image icon{Resource::Icon};
|
||||||
int y = height - 128;
|
icon.alphaBlend(0xff000000);
|
||||||
if(x >= 0 && y >= 0) {
|
for(uint y : range(112)) {
|
||||||
canvas.setVisible(true).setGeometry({x, y, 112, 112});
|
auto target = output + (y + oy) * (length >> 2) + ox;
|
||||||
} else {
|
auto source = (uint32_t*)icon.data() + y * 112;
|
||||||
canvas.setVisible(false);
|
memory::copy(target, source, 112 * sizeof(uint32_t));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
viewport.setGeometry({0, 0, 1, 1});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::clearViewport() -> void {
|
auto Presentation::clearViewport() -> void {
|
||||||
if(!emulator || !emulator->loaded()) showIcon();
|
|
||||||
if(!video) return;
|
if(!video) return;
|
||||||
|
|
||||||
|
if(!emulator || !emulator->loaded()) {
|
||||||
|
viewport.setGeometry({0, 0, geometry().width(), geometry().height()});
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t* output;
|
uint32_t* output;
|
||||||
uint length = 0;
|
uint length = 0;
|
||||||
uint width = viewport.geometry().width();
|
uint width = viewport.geometry().width();
|
||||||
|
@ -232,15 +235,13 @@ auto Presentation::clearViewport() -> void {
|
||||||
auto line = output + y * (length >> 2);
|
auto line = output + y * (length >> 2);
|
||||||
for(uint x : range(width)) *line++ = 0xff000000;
|
for(uint x : range(width)) *line++ = 0xff000000;
|
||||||
}
|
}
|
||||||
|
if(!emulator || !emulator->loaded()) drawIcon(output, length, width, height);
|
||||||
video->unlock();
|
video->unlock();
|
||||||
video->output();
|
video->output();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Presentation::resizeViewport(bool resizeWindow) -> void {
|
auto Presentation::resizeViewport(bool resizeWindow) -> void {
|
||||||
if(emulator && emulator->loaded()) canvas.setVisible(false);
|
|
||||||
|
|
||||||
//clear video area before resizing to avoid seeing distorted video momentarily
|
//clear video area before resizing to avoid seeing distorted video momentarily
|
||||||
clearViewport();
|
clearViewport();
|
||||||
|
|
||||||
|
@ -306,10 +307,14 @@ auto Presentation::resizeViewport(bool resizeWindow) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(emulator && emulator->loaded()) {
|
||||||
viewport.setGeometry({
|
viewport.setGeometry({
|
||||||
(viewportWidth - emulatorWidth) / 2, (viewportHeight - emulatorHeight) / 2,
|
(viewportWidth - emulatorWidth) / 2, (viewportHeight - emulatorHeight) / 2,
|
||||||
emulatorWidth, emulatorHeight
|
emulatorWidth, emulatorHeight
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
viewport.setGeometry({0, 0, geometry().width(), geometry().height()});
|
||||||
|
}
|
||||||
|
|
||||||
//clear video area again to ensure entire viewport area has been painted in
|
//clear video area again to ensure entire viewport area has been painted in
|
||||||
clearViewport();
|
clearViewport();
|
||||||
|
@ -331,6 +336,9 @@ auto Presentation::toggleFullScreen() -> void {
|
||||||
menuBar.setVisible(true);
|
menuBar.setVisible(true);
|
||||||
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
|
statusBar.setVisible(settings["UserInterface/ShowStatusBar"].boolean());
|
||||||
}
|
}
|
||||||
|
//hack: give window geometry time to update after toggling fullscreen and menu/status bars
|
||||||
|
usleep(20 * 1000);
|
||||||
|
Application::processEvents();
|
||||||
resizeViewport();
|
resizeViewport();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct AboutWindow : Window {
|
||||||
struct Presentation : Window {
|
struct Presentation : Window {
|
||||||
Presentation();
|
Presentation();
|
||||||
auto updateEmulator() -> void;
|
auto updateEmulator() -> void;
|
||||||
auto showIcon() -> void;
|
auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void;
|
||||||
auto clearViewport() -> void;
|
auto clearViewport() -> void;
|
||||||
auto resizeViewport(bool resizeWindow = true) -> void;
|
auto resizeViewport(bool resizeWindow = true) -> void;
|
||||||
auto toggleFullScreen() -> void;
|
auto toggleFullScreen() -> void;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace hiro {
|
namespace hiro {
|
||||||
|
|
||||||
Settings::Settings() {
|
Settings::Settings() {
|
||||||
string path = {Path::local(), "hiro/"};
|
string path = {Path::userData(), "hiro/"};
|
||||||
auto document = BML::unserialize(file::read({path, "gtk.bml"}));
|
auto document = BML::unserialize(file::read({path, "gtk.bml"}));
|
||||||
|
|
||||||
auto get = [&](string_view name) {
|
auto get = [&](string_view name) {
|
||||||
|
@ -17,7 +17,7 @@ Settings::Settings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::~Settings() {
|
Settings::~Settings() {
|
||||||
string path = {Path::local(), "hiro/"};
|
string path = {Path::userData(), "hiro/"};
|
||||||
directory::create(path, 0755);
|
directory::create(path, 0755);
|
||||||
|
|
||||||
Markup::Node document;
|
Markup::Node document;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace hiro {
|
namespace hiro {
|
||||||
|
|
||||||
Settings::Settings() {
|
Settings::Settings() {
|
||||||
string path = {Path::local(), "hiro/"};
|
string path = {Path::userData(), "hiro/"};
|
||||||
auto document = BML::unserialize(file::read({path, "qt.bml"}));
|
auto document = BML::unserialize(file::read({path, "qt.bml"}));
|
||||||
|
|
||||||
auto get = [&](string_view name) {
|
auto get = [&](string_view name) {
|
||||||
|
@ -17,7 +17,7 @@ Settings::Settings() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::~Settings() {
|
Settings::~Settings() {
|
||||||
string path = {Path::local(), "hiro/"};
|
string path = {Path::userData(), "hiro/"};
|
||||||
directory::create(path, 0755);
|
directory::create(path, 0755);
|
||||||
|
|
||||||
Markup::Node document;
|
Markup::Node document;
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace hiro {
|
||||||
|
|
||||||
auto pStatusBar::construct() -> void {
|
auto pStatusBar::construct() -> void {
|
||||||
if(auto parent = _parent()) {
|
if(auto parent = _parent()) {
|
||||||
hwnd = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD | WS_DISABLED, 0, 0, 0, 0, parent->hwnd, nullptr, GetModuleHandle(0), 0);
|
hwnd = CreateWindow(STATUSCLASSNAME, L"", WS_CHILD, 0, 0, 0, 0, parent->hwnd, nullptr, GetModuleHandle(0), 0);
|
||||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference);
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&reference);
|
||||||
setEnabled(self().enabled(true));
|
setEnabled(self().enabled(true));
|
||||||
setFont(self().font(true));
|
setFont(self().font(true));
|
||||||
|
|
|
@ -86,11 +86,6 @@ auto SuperFamicom::manifest() const -> string {
|
||||||
output.append(Memory{}.type("RAM").size(size).content("Save").text());
|
output.append(Memory{}.type("RAM").size(size).content("Save").text());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(board(0) == "GSU" && !ramSize() && !expansionRamSize()) {
|
|
||||||
//Starfox / Starwing reports having no RAM; but all GSU boards contain expansion RAM
|
|
||||||
output.append(Memory{}.type("RAM").size(0x8000).content("Save").isVolatile().text());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0) {
|
if(0) {
|
||||||
} else if(board(0) == "ARM") {
|
} else if(board(0) == "ARM") {
|
||||||
output.append(Memory{}.type("ROM").size(0x20000).content("Program").manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).text());
|
output.append(Memory{}.type("ROM").size(0x20000).content("Program").manufacturer("SETA").architecture("ARM6").identifier(firmwareARM()).text());
|
||||||
|
@ -273,10 +268,7 @@ auto SuperFamicom::board() const -> string {
|
||||||
}
|
}
|
||||||
if(!board) board.append(mode);
|
if(!board) board.append(mode);
|
||||||
|
|
||||||
if(cartridgeTypeLo == 0x1 || cartridgeTypeLo == 0x4) board.append("RAM-"); //RAM without battery
|
if(ramSize() || expansionRamSize()) board.append("RAM-");
|
||||||
if(cartridgeTypeLo == 0x2 || cartridgeTypeLo == 0x5) board.append("RAM-"); //RAM with battery
|
|
||||||
if(cartridgeTypeLo == 0x6); //battery without RAM
|
|
||||||
|
|
||||||
if(epsonRTC) board.append("EPSONRTC-");
|
if(epsonRTC) board.append("EPSONRTC-");
|
||||||
if(sharpRTC) board.append("SHARPRTC-");
|
if(sharpRTC) board.append("SHARPRTC-");
|
||||||
|
|
||||||
|
@ -439,9 +431,14 @@ auto SuperFamicom::ramSize() const -> uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SuperFamicom::expansionRamSize() const -> uint {
|
auto SuperFamicom::expansionRamSize() const -> uint {
|
||||||
if(data[headerAddress + 0x2a] != 0x33) return 0;
|
if(data[headerAddress + 0x2a] == 0x33) {
|
||||||
auto ramSize = data[headerAddress + 0x0d] & 7;
|
auto ramSize = data[headerAddress + 0x0d] & 7;
|
||||||
if(ramSize) return 1024 << ramSize;
|
if(ramSize) return 1024 << ramSize;
|
||||||
|
}
|
||||||
|
if((data[headerAddress + 0x26] >> 4) == 1) {
|
||||||
|
//GSU: Starfox / Starwing lacks an extended header; but still has expansion RAM
|
||||||
|
return 0x8000;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ auto locate(string name) -> string {
|
||||||
string location = {Path::program(), name};
|
string location = {Path::program(), name};
|
||||||
if(inode::exists(location)) return location;
|
if(inode::exists(location)) return location;
|
||||||
|
|
||||||
directory::create({Path::local(), "icarus/"});
|
directory::create({Path::userData(), "icarus/"});
|
||||||
return {Path::local(), "icarus/", name};
|
return {Path::userData(), "icarus/", name};
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "settings.cpp"
|
#include "settings.cpp"
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace nall { namespace Decode {
|
||||||
|
|
||||||
|
inline auto HTML(const string& input) -> string {
|
||||||
|
string output;
|
||||||
|
for(uint n = 0; n < input.size();) {
|
||||||
|
if(input[n] == '&') {
|
||||||
|
if(input(n + 1) == 'a' && input(n + 2) == 'm' && input(n + 3) == 'p' && input(n + 4) == ';') {
|
||||||
|
output.append('&');
|
||||||
|
n += 5;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(input(n + 1) == 'l' && input(n + 2) == 't' && input(n + 3) == ';') {
|
||||||
|
output.append('<');
|
||||||
|
n += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(input(n + 1) == 'g' && input(n + 2) == 't' && input(n + 3) == ';') {
|
||||||
|
output.append('>');
|
||||||
|
n += 4;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(input(n + 1) == 'q' && input(n + 2) == 'u' && input(n + 3) == 'o' && input(n + 4) == 't' && input(n + 5) == ';') {
|
||||||
|
output.append('"');
|
||||||
|
n += 6;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(input(n + 1) == 'a' && input(n + 2) == 'p' && input(n + 3) == 'o' && input(n + 4) == 's' && input(n + 5) == ';') {
|
||||||
|
output.append('\'');
|
||||||
|
n += 6;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.append(input[n++]);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace nall { namespace Encode {
|
||||||
|
|
||||||
|
inline auto HTML(const string& input) -> string {
|
||||||
|
string output;
|
||||||
|
for(char c : input) {
|
||||||
|
if(c == '&' ) { output.append("&" ); continue; }
|
||||||
|
if(c == '<' ) { output.append("<" ); continue; }
|
||||||
|
if(c == '>' ) { output.append(">" ); continue; }
|
||||||
|
if(c == '"' ) { output.append("""); continue; }
|
||||||
|
if(c == '\'') { output.append("'"); continue; }
|
||||||
|
output.append(c);
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}}
|
|
@ -62,12 +62,14 @@
|
||||||
#include <nall/decode/base64.hpp>
|
#include <nall/decode/base64.hpp>
|
||||||
#include <nall/decode/bmp.hpp>
|
#include <nall/decode/bmp.hpp>
|
||||||
#include <nall/decode/gzip.hpp>
|
#include <nall/decode/gzip.hpp>
|
||||||
|
#include <nall/decode/html.hpp>
|
||||||
#include <nall/decode/inflate.hpp>
|
#include <nall/decode/inflate.hpp>
|
||||||
#include <nall/decode/png.hpp>
|
#include <nall/decode/png.hpp>
|
||||||
#include <nall/decode/url.hpp>
|
#include <nall/decode/url.hpp>
|
||||||
#include <nall/decode/zip.hpp>
|
#include <nall/decode/zip.hpp>
|
||||||
#include <nall/encode/base.hpp>
|
#include <nall/encode/base.hpp>
|
||||||
#include <nall/encode/base64.hpp>
|
#include <nall/encode/base64.hpp>
|
||||||
|
#include <nall/encode/html.hpp>
|
||||||
#include <nall/encode/url.hpp>
|
#include <nall/encode/url.hpp>
|
||||||
#include <nall/hash/crc16.hpp>
|
#include <nall/hash/crc16.hpp>
|
||||||
#include <nall/hash/crc32.hpp>
|
#include <nall/hash/crc32.hpp>
|
||||||
|
|
|
@ -69,9 +69,10 @@ inline auto user() -> string {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// /home/username/.config/
|
// /home/username/.local/share/
|
||||||
|
// ~/Library/Application Support/
|
||||||
// c:/users/username/appdata/roaming/
|
// c:/users/username/appdata/roaming/
|
||||||
inline auto config() -> string {
|
inline auto userData() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
|
@ -80,24 +81,6 @@ inline auto config() -> string {
|
||||||
#elif defined(PLATFORM_MACOS)
|
#elif defined(PLATFORM_MACOS)
|
||||||
string result = {Path::user(), "Library/Application Support/"};
|
string result = {Path::user(), "Library/Application Support/"};
|
||||||
#else
|
#else
|
||||||
string result = {Path::user(), ".config/"};
|
|
||||||
#endif
|
|
||||||
if(!result) result = ".";
|
|
||||||
if(!result.endsWith("/")) result.append("/");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// /home/username/.local/share/
|
|
||||||
// c:/users/username/appdata/local/
|
|
||||||
inline auto local() -> string {
|
|
||||||
#if defined(PLATFORM_WINDOWS)
|
|
||||||
wchar_t path[PATH_MAX] = L"";
|
|
||||||
SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
|
||||||
string result = (const char*)utf8_t(path);
|
|
||||||
result.transform("\\", "/");
|
|
||||||
#elif defined(PLATFORM_MACOS)
|
|
||||||
string result = {Path::user(), "Library/Application Support/"};
|
|
||||||
#else
|
|
||||||
string result = {Path::user(), ".local/share/"};
|
string result = {Path::user(), ".local/share/"};
|
||||||
#endif
|
#endif
|
||||||
if(!result) result = ".";
|
if(!result) result = ".";
|
||||||
|
@ -108,7 +91,7 @@ inline auto local() -> string {
|
||||||
// /usr/share
|
// /usr/share
|
||||||
// /Library/Application Support/
|
// /Library/Application Support/
|
||||||
// c:/ProgramData/
|
// c:/ProgramData/
|
||||||
inline auto shared() -> string {
|
inline auto sharedData() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
SHGetFolderPathW(nullptr, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||||
|
@ -126,7 +109,7 @@ inline auto shared() -> string {
|
||||||
|
|
||||||
// /tmp
|
// /tmp
|
||||||
// c:/users/username/AppData/Local/Temp/
|
// c:/users/username/AppData/Local/Temp/
|
||||||
inline auto temp() -> string {
|
inline auto temporary() -> string {
|
||||||
#if defined(PLATFORM_WINDOWS)
|
#if defined(PLATFORM_WINDOWS)
|
||||||
wchar_t path[PATH_MAX] = L"";
|
wchar_t path[PATH_MAX] = L"";
|
||||||
GetTempPathW(PATH_MAX, path);
|
GetTempPathW(PATH_MAX, path);
|
||||||
|
|
|
@ -175,7 +175,7 @@ public:
|
||||||
|
|
||||||
//core.hpp
|
//core.hpp
|
||||||
inline auto operator[](uint) const -> const char&;
|
inline auto operator[](uint) const -> const char&;
|
||||||
inline auto operator()(uint, char) const -> char;
|
inline auto operator()(uint, char = 0) const -> char;
|
||||||
template<typename... P> inline auto assign(P&&...) -> type&;
|
template<typename... P> inline auto assign(P&&...) -> type&;
|
||||||
template<typename T, typename... P> inline auto prepend(const T&, P&&...) -> type&;
|
template<typename T, typename... P> inline auto prepend(const T&, P&&...) -> type&;
|
||||||
template<typename... P> inline auto prepend(const nall::string_format&, P&&...) -> type&;
|
template<typename... P> inline auto prepend(const nall::string_format&, P&&...) -> type&;
|
||||||
|
|
|
@ -11,6 +11,16 @@ struct InputXlib : Input {
|
||||||
InputXlib() : _keyboard(*this), _mouse(*this) { initialize(); }
|
InputXlib() : _keyboard(*this), _mouse(*this) { initialize(); }
|
||||||
~InputXlib() { terminate(); }
|
~InputXlib() { terminate(); }
|
||||||
|
|
||||||
|
auto ready() -> bool { return _ready; }
|
||||||
|
|
||||||
|
auto context() -> uintptr { return _context; }
|
||||||
|
|
||||||
|
auto setContext(uintptr context) -> bool {
|
||||||
|
if(_context == context) return true;
|
||||||
|
_context = context;
|
||||||
|
return initialize();
|
||||||
|
}
|
||||||
|
|
||||||
auto acquired() -> bool {
|
auto acquired() -> bool {
|
||||||
return _mouse.acquired();
|
return _mouse.acquired();
|
||||||
}
|
}
|
||||||
|
@ -37,6 +47,7 @@ struct InputXlib : Input {
|
||||||
private:
|
private:
|
||||||
auto initialize() -> bool {
|
auto initialize() -> bool {
|
||||||
terminate();
|
terminate();
|
||||||
|
if(!_context) return false;
|
||||||
if(!_keyboard.initialize()) return false;
|
if(!_keyboard.initialize()) return false;
|
||||||
if(!_mouse.initialize(_context)) return false;
|
if(!_mouse.initialize(_context)) return false;
|
||||||
return _ready = true;
|
return _ready = true;
|
||||||
|
|
|
@ -68,46 +68,49 @@ using namespace ruby;
|
||||||
|
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
auto Video::create(const string& driver) -> Video* {
|
auto Video::create(string driver) -> Video* {
|
||||||
if(!driver) return create(optimalDriver());
|
Video* video = nullptr;
|
||||||
|
if(!driver) driver = optimalDriver();
|
||||||
|
|
||||||
#if defined(VIDEO_CGL)
|
#if defined(VIDEO_CGL)
|
||||||
if(driver == "OpenGL") return new VideoCGL;
|
if(driver == "OpenGL") video = new VideoCGL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECT3D)
|
#if defined(VIDEO_DIRECT3D)
|
||||||
if(driver == "Direct3D") return new VideoDirect3D;
|
if(driver == "Direct3D") video = new VideoDirect3D;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_DIRECTDRAW)
|
#if defined(VIDEO_DIRECTDRAW)
|
||||||
if(driver == "DirectDraw") return new VideoDirectDraw;
|
if(driver == "DirectDraw") video = new VideoDirectDraw;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_GDI)
|
#if defined(VIDEO_GDI)
|
||||||
if(driver == "GDI") return new VideoGDI;
|
if(driver == "GDI") video = new VideoGDI;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_GLX)
|
#if defined(VIDEO_GLX)
|
||||||
if(driver == "OpenGL") return new VideoGLX;
|
if(driver == "OpenGL") video = new VideoGLX;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_GLX2)
|
#if defined(VIDEO_GLX2)
|
||||||
if(driver == "OpenGL2") return new VideoGLX2;
|
if(driver == "OpenGL2") video = new VideoGLX2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_WGL)
|
#if defined(VIDEO_WGL)
|
||||||
if(driver == "OpenGL") return new VideoWGL;
|
if(driver == "OpenGL") video = new VideoWGL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_XSHM)
|
#if defined(VIDEO_XSHM)
|
||||||
if(driver == "XShm") return new VideoXShm;
|
if(driver == "XShm") video = new VideoXShm;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_XVIDEO)
|
#if defined(VIDEO_XVIDEO)
|
||||||
if(driver == "XVideo") return new VideoXVideo;
|
if(driver == "XVideo") video = new VideoXVideo;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return new Video;
|
if(!video) driver = "None", video = new Video;
|
||||||
|
video->_driver = driver;
|
||||||
|
return video;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Video::optimalDriver() -> string {
|
auto Video::optimalDriver() -> string {
|
||||||
|
@ -246,50 +249,53 @@ auto Video::availableDrivers() -> string_vector {
|
||||||
|
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
auto Audio::create(const string& driver) -> Audio* {
|
auto Audio::create(string driver) -> Audio* {
|
||||||
if(!driver) return create(optimalDriver());
|
Audio* audio = nullptr;
|
||||||
|
if(!driver) driver = optimalDriver();
|
||||||
|
|
||||||
#if defined(AUDIO_ALSA)
|
#if defined(AUDIO_ALSA)
|
||||||
if(driver == "ALSA") return new AudioALSA;
|
if(driver == "ALSA") audio = new AudioALSA;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_AO)
|
#if defined(AUDIO_AO)
|
||||||
if(driver == "libao") return new AudioAO;
|
if(driver == "libao") audio = new AudioAO;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_ASIO)
|
#if defined(AUDIO_ASIO)
|
||||||
if(driver == "ASIO") return new AudioASIO;
|
if(driver == "ASIO") audio = new AudioASIO;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_DIRECTSOUND)
|
#if defined(AUDIO_DIRECTSOUND)
|
||||||
if(driver == "DirectSound") return new AudioDirectSound;
|
if(driver == "DirectSound") audio = new AudioDirectSound;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_OPENAL)
|
#if defined(AUDIO_OPENAL)
|
||||||
if(driver == "OpenAL") return new AudioOpenAL;
|
if(driver == "OpenAL") audio = new AudioOpenAL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_OSS)
|
#if defined(AUDIO_OSS)
|
||||||
if(driver == "OSS") return new AudioOSS;
|
if(driver == "OSS") audio = new AudioOSS;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_PULSEAUDIO)
|
#if defined(AUDIO_PULSEAUDIO)
|
||||||
if(driver == "PulseAudio") return new AudioPulseAudio;
|
if(driver == "PulseAudio") audio = new AudioPulseAudio;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_PULSEAUDIOSIMPLE)
|
#if defined(AUDIO_PULSEAUDIOSIMPLE)
|
||||||
if(driver == "PulseAudioSimple") return new AudioPulseAudioSimple;
|
if(driver == "PulseAudioSimple") audio = new AudioPulseAudioSimple;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_WASAPI)
|
#if defined(AUDIO_WASAPI)
|
||||||
if(driver == "WASAPI") return new AudioWASAPI;
|
if(driver == "WASAPI") audio = new AudioWASAPI;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(AUDIO_XAUDIO2)
|
#if defined(AUDIO_XAUDIO2)
|
||||||
if(driver == "XAudio2") return new AudioXAudio2;
|
if(driver == "XAudio2") audio = new AudioXAudio2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return new Audio;
|
if(!audio) driver = "None", audio = new Audio;
|
||||||
|
audio->_driver = driver;
|
||||||
|
return audio;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Audio::optimalDriver() -> string {
|
auto Audio::optimalDriver() -> string {
|
||||||
|
@ -420,34 +426,37 @@ auto Audio::availableDrivers() -> string_vector {
|
||||||
|
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
auto Input::create(const string& driver) -> Input* {
|
auto Input::create(string driver) -> Input* {
|
||||||
if(!driver) return create(optimalDriver());
|
Input* input = nullptr;
|
||||||
|
if(!driver) driver = optimalDriver();
|
||||||
|
|
||||||
#if defined(INPUT_WINDOWS)
|
#if defined(INPUT_WINDOWS)
|
||||||
if(driver == "Windows") return new InputWindows;
|
if(driver == "Windows") input = new InputWindows;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_QUARTZ)
|
#if defined(INPUT_QUARTZ)
|
||||||
if(driver == "Quartz") return new InputQuartz;
|
if(driver == "Quartz") input = new InputQuartz;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_CARBON)
|
#if defined(INPUT_CARBON)
|
||||||
if(driver == "Carbon") return new InputCarbon;
|
if(driver == "Carbon") input = new InputCarbon;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_UDEV)
|
#if defined(INPUT_UDEV)
|
||||||
if(driver == "udev") return new InputUdev;
|
if(driver == "udev") input = new InputUdev;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_SDL)
|
#if defined(INPUT_SDL)
|
||||||
if(driver == "SDL") return new InputSDL;
|
if(driver == "SDL") input = new InputSDL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(INPUT_XLIB)
|
#if defined(INPUT_XLIB)
|
||||||
if(driver == "Xlib") return new InputXlib;
|
if(driver == "Xlib") input = new InputXlib;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return new Input;
|
if(!input) driver = "None", input = new Input;
|
||||||
|
input->_driver = driver;
|
||||||
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Input::optimalDriver() -> string {
|
auto Input::optimalDriver() -> string {
|
||||||
|
|
|
@ -5,18 +5,15 @@
|
||||||
namespace ruby {
|
namespace ruby {
|
||||||
|
|
||||||
struct Video {
|
struct Video {
|
||||||
static auto create(const nall::string& driver = "") -> Video*;
|
static auto create(nall::string driver = "") -> Video*;
|
||||||
static auto optimalDriver() -> nall::string;
|
static auto optimalDriver() -> nall::string;
|
||||||
static auto safestDriver() -> nall::string;
|
static auto safestDriver() -> nall::string;
|
||||||
static auto availableDrivers() -> nall::string_vector;
|
static auto availableDrivers() -> nall::string_vector;
|
||||||
|
|
||||||
struct Information {
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~Video() = default;
|
virtual ~Video() = default;
|
||||||
|
|
||||||
virtual auto ready() -> bool { return true; }
|
virtual auto ready() -> bool { return true; }
|
||||||
virtual auto information() -> Information { return {}; }
|
virtual auto driver() -> nall::string { return _driver; }
|
||||||
|
|
||||||
virtual auto exclusive() -> bool { return false; }
|
virtual auto exclusive() -> bool { return false; }
|
||||||
virtual auto context() -> uintptr { return 0; }
|
virtual auto context() -> uintptr { return 0; }
|
||||||
|
@ -36,10 +33,13 @@ struct Video {
|
||||||
virtual auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; }
|
virtual auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { return false; }
|
||||||
virtual auto unlock() -> void {}
|
virtual auto unlock() -> void {}
|
||||||
virtual auto output() -> void {}
|
virtual auto output() -> void {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nall::string _driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Audio {
|
struct Audio {
|
||||||
static auto create(const nall::string& driver = "") -> Audio*;
|
static auto create(nall::string driver = "") -> Audio*;
|
||||||
static auto optimalDriver() -> nall::string;
|
static auto optimalDriver() -> nall::string;
|
||||||
static auto safestDriver() -> nall::string;
|
static auto safestDriver() -> nall::string;
|
||||||
static auto availableDrivers() -> nall::string_vector;
|
static auto availableDrivers() -> nall::string_vector;
|
||||||
|
@ -52,6 +52,8 @@ struct Audio {
|
||||||
virtual auto availableChannels() -> nall::vector<uint> { return {2}; }
|
virtual auto availableChannels() -> nall::vector<uint> { return {2}; }
|
||||||
|
|
||||||
virtual auto ready() -> bool { return true; }
|
virtual auto ready() -> bool { return true; }
|
||||||
|
virtual auto driver() -> nall::string { return _driver; }
|
||||||
|
|
||||||
virtual auto exclusive() -> bool { return false; }
|
virtual auto exclusive() -> bool { return false; }
|
||||||
virtual auto context() -> uintptr { return 0; }
|
virtual auto context() -> uintptr { return 0; }
|
||||||
virtual auto device() -> nall::string { return "None"; }
|
virtual auto device() -> nall::string { return "None"; }
|
||||||
|
@ -70,21 +72,21 @@ struct Audio {
|
||||||
|
|
||||||
virtual auto clear() -> void {}
|
virtual auto clear() -> void {}
|
||||||
virtual auto output(const double samples[]) -> void {}
|
virtual auto output(const double samples[]) -> void {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nall::string _driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Input {
|
struct Input {
|
||||||
static auto create(const nall::string& driver = "") -> Input*;
|
static auto create(nall::string driver = "") -> Input*;
|
||||||
static auto optimalDriver() -> nall::string;
|
static auto optimalDriver() -> nall::string;
|
||||||
static auto safestDriver() -> nall::string;
|
static auto safestDriver() -> nall::string;
|
||||||
static auto availableDrivers() -> nall::string_vector;
|
static auto availableDrivers() -> nall::string_vector;
|
||||||
|
|
||||||
struct Information {
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~Input() = default;
|
virtual ~Input() = default;
|
||||||
|
|
||||||
virtual auto ready() -> bool { return true; }
|
virtual auto ready() -> bool { return true; }
|
||||||
virtual auto information() -> Information { return {}; }
|
virtual auto driver() -> nall::string { return _driver; }
|
||||||
|
|
||||||
virtual auto context() -> uintptr { return 0; }
|
virtual auto context() -> uintptr { return 0; }
|
||||||
|
|
||||||
|
@ -102,6 +104,7 @@ struct Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
nall::string _driver;
|
||||||
nall::function<void (nall::shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue)> _onChange;
|
nall::function<void (nall::shared_pointer<nall::HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue)> _onChange;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,12 @@ struct VideoDirect3D : Video {
|
||||||
if(!ready()) return false;
|
if(!ready()) return false;
|
||||||
if(_lost && !recover()) return false;
|
if(_lost && !recover()) return false;
|
||||||
|
|
||||||
|
//if output size changed, driver must be re-initialized.
|
||||||
|
//failure to do so causes scaling issues on some video drivers.
|
||||||
|
RECT rectangle;
|
||||||
|
GetClientRect((HWND)_context, &rectangle);
|
||||||
|
if(_windowWidth != rectangle.right || _windowHeight != rectangle.bottom) initialize();
|
||||||
|
|
||||||
if(width != _inputWidth || height != _inputHeight) {
|
if(width != _inputWidth || height != _inputHeight) {
|
||||||
resize(_inputWidth = width, _inputHeight = height);
|
resize(_inputWidth = width, _inputHeight = height);
|
||||||
}
|
}
|
||||||
|
@ -91,13 +97,6 @@ struct VideoDirect3D : Video {
|
||||||
if(!ready()) return;
|
if(!ready()) return;
|
||||||
if(_lost && !recover()) return;
|
if(_lost && !recover()) return;
|
||||||
|
|
||||||
RECT rectangle;
|
|
||||||
GetClientRect((HWND)_context, &rectangle);
|
|
||||||
|
|
||||||
//if output size changed, driver must be re-initialized.
|
|
||||||
//failure to do so causes scaling issues on some video drivers.
|
|
||||||
if(_windowWidth != rectangle.right || _windowHeight != rectangle.bottom) initialize();
|
|
||||||
|
|
||||||
_device->BeginScene();
|
_device->BeginScene();
|
||||||
uint x = 0, y = 0;
|
uint x = 0, y = 0;
|
||||||
if(_exclusive) {
|
if(_exclusive) {
|
||||||
|
|
Loading…
Reference in New Issue