mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r43 release.
byuu says: Changelog: - bsnes: added video settings panel - bsnes: added audio settings panel - bsnes: disable assign/clear buttons at startup for hotkeys panel - bsnes: program initialization restructured: drivers initialize last - this lets me reinitialize the settings panel values on driver changes - so eg things like input/hotkey remappings should work after input driver changes now - ... but I had to disable the window icon for this ... it takes too long to show up this way - bsnes: added synchronize video/audio options to settings menu - bsnes: added audio skew slider for video/audio synchronization - bsnes: state manager edit/remove works on game ROM .bsz archives now - bsnes: removed View→Color Emulation; default to 150% gamma instead (it's a touch brighter but similar) At this point, I'm pretty much ready to make an initial beta release for wider testing. Please use this WIP to indicate any must-fix issues before I do so.
This commit is contained in:
parent
5b97fa2415
commit
b14c6bf155
|
@ -13,7 +13,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.42";
|
||||
static const string Version = "106.43";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -176,6 +176,14 @@ auto InputMapping::displayName() -> string {
|
|||
|
||||
InputManager::InputManager() {
|
||||
inputManager = this;
|
||||
}
|
||||
|
||||
auto InputManager::initialize() -> void {
|
||||
devices.reset();
|
||||
ports.reset();
|
||||
hotkeys.reset();
|
||||
|
||||
if(!input) return;
|
||||
input->onChange({&InputManager::onChange, this});
|
||||
frequency = max(1u, settings["Input/Frequency"].natural());
|
||||
|
||||
|
@ -197,6 +205,7 @@ InputManager::InputManager() {
|
|||
}
|
||||
|
||||
bindHotkeys();
|
||||
poll();
|
||||
}
|
||||
|
||||
auto InputManager::bind() -> void {
|
||||
|
|
|
@ -54,6 +54,7 @@ struct InputPort {
|
|||
|
||||
struct InputManager {
|
||||
InputManager();
|
||||
auto initialize() -> void;
|
||||
auto bind() -> void;
|
||||
auto poll() -> void;
|
||||
auto onChange(shared_pointer<HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void;
|
||||
|
|
|
@ -85,14 +85,19 @@ Presentation::Presentation() {
|
|||
settings["View/BlurEmulation"].setValue(blurEmulation.checked());
|
||||
emulator->set("Blur Emulation", blurEmulation.checked());
|
||||
}).doToggle();
|
||||
colorEmulation.setText("Color Emulation").setChecked(settings["View/ColorEmulation"].boolean()).onToggle([&] {
|
||||
settings["View/ColorEmulation"].setValue(colorEmulation.checked());
|
||||
emulator->set("Color Emulation", colorEmulation.checked());
|
||||
}).doToggle();
|
||||
shaderMenu.setText("Shader");
|
||||
updateShaders();
|
||||
synchronizeVideo.setText("Synchronize Video").setChecked(settings["Video/Blocking"].boolean()).onToggle([&] {
|
||||
settings["Video/Blocking"].setValue(synchronizeVideo.checked());
|
||||
program->updateVideoBlocking();
|
||||
});
|
||||
synchronizeAudio.setText("Synchronize Audio").setChecked(settings["Audio/Blocking"].boolean()).onToggle([&] {
|
||||
settings["Audio/Blocking"].setValue(synchronizeAudio.checked());
|
||||
program->updateAudioBlocking();
|
||||
});
|
||||
muteAudio.setText("Mute Audio").setChecked(settings["Audio/Mute"].boolean()).onToggle([&] {
|
||||
settings["Audio/Mute"].setValue(muteAudio.checked());
|
||||
program->updateAudioEffects();
|
||||
});
|
||||
showStatusBar.setText("Show Status Bar").setChecked(settings["UserInterface/ShowStatusBar"].boolean()).onToggle([&] {
|
||||
settings["UserInterface/ShowStatusBar"].setValue(showStatusBar.checked());
|
||||
|
@ -196,6 +201,8 @@ Presentation::Presentation() {
|
|||
}
|
||||
|
||||
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {
|
||||
return;
|
||||
|
||||
int ox = width - 144;
|
||||
int oy = height - 128;
|
||||
if(ox >= 0 && oy >= 0) {
|
||||
|
|
|
@ -46,11 +46,13 @@ struct Presentation : Window {
|
|||
MenuCheckItem overscanCropping{&viewMenu};
|
||||
MenuCheckItem integralScaling{&viewMenu};
|
||||
MenuCheckItem blurEmulation{&viewMenu};
|
||||
MenuCheckItem colorEmulation{&viewMenu};
|
||||
Menu shaderMenu{&settingsMenu};
|
||||
MenuSeparator settingsSeparatorA{&settingsMenu};
|
||||
MenuCheckItem synchronizeVideo{&settingsMenu};
|
||||
MenuCheckItem synchronizeAudio{&settingsMenu};
|
||||
MenuCheckItem muteAudio{&settingsMenu};
|
||||
MenuCheckItem showStatusBar{&settingsMenu};
|
||||
MenuSeparator settingsSeparator{&settingsMenu};
|
||||
MenuSeparator settingsSeparatorB{&settingsMenu};
|
||||
MenuItem videoSettings{&settingsMenu};
|
||||
MenuItem audioSettings{&settingsMenu};
|
||||
MenuItem inputSettings{&settingsMenu};
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
auto Program::updateAudioDriver() -> void {
|
||||
audio = Audio::create(settings["Audio/Driver"].text());
|
||||
audio->setContext(presentation->viewport.handle());
|
||||
audio->setChannels(2);
|
||||
updateAudioExclusive();
|
||||
updateAudioDevice();
|
||||
updateAudioBlocking();
|
||||
|
||||
settingsWindow->advanced.updateAudioDriver();
|
||||
|
||||
if(!audio->ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize [", settings["Audio/Driver"].text(), "] audio driver."
|
||||
}).error();
|
||||
settings["Audio/Driver"].setValue("None");
|
||||
return updateAudioDriver();
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::updateAudioExclusive() -> void {
|
||||
if(!audio) return;
|
||||
audio->clear();
|
||||
audio->setExclusive(settings["Audio/Exclusive"].boolean());
|
||||
updateAudioFrequency();
|
||||
updateAudioLatency();
|
||||
}
|
||||
|
||||
auto Program::updateAudioDevice() -> void {
|
||||
if(!audio) return;
|
||||
audio->clear();
|
||||
if(!audio->availableDevices().find(settings["Audio/Device"].text())) {
|
||||
settings["Audio/Device"].setValue(audio->availableDevices()(0));
|
||||
}
|
||||
audio->setDevice(settings["Audio/Device"].text());
|
||||
updateAudioFrequency();
|
||||
updateAudioLatency();
|
||||
settingsWindow->audio.updateDevice();
|
||||
}
|
||||
|
||||
auto Program::updateAudioBlocking() -> void {
|
||||
audio->setBlocking(settings["Audio/Blocking"].boolean());
|
||||
}
|
||||
|
||||
auto Program::updateAudioFrequency() -> void {
|
||||
if(!audio) return;
|
||||
audio->clear();
|
||||
if(!audio->availableFrequencies().find(settings["Audio/Frequency"].real())) {
|
||||
settings["Audio/Frequency"].setValue(audio->availableFrequencies()(0));
|
||||
}
|
||||
audio->setFrequency(settings["Audio/Frequency"].real());
|
||||
Emulator::audio.setFrequency(settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer());
|
||||
settingsWindow->audio.updateFrequency();
|
||||
}
|
||||
|
||||
auto Program::updateAudioLatency() -> void {
|
||||
if(!audio) return;
|
||||
audio->clear();
|
||||
if(!audio->availableLatencies().find(settings["Audio/Latency"].natural())) {
|
||||
settings["Audio/Latency"].setValue(audio->availableLatencies()(0));
|
||||
}
|
||||
audio->setLatency(settings["Audio/Latency"].natural());
|
||||
settingsWindow->audio.updateLatency();
|
||||
}
|
||||
|
||||
auto Program::updateAudioEffects() -> void {
|
||||
double volume = settings["Audio/Mute"].boolean() ? 0.0 : settings["Audio/Volume"].natural() * 0.01;
|
||||
Emulator::audio.setVolume(volume);
|
||||
|
||||
double balance = max(-1.0, min(+1.0, (settings["Audio/Balance"].integer() - 50) / 50.0));
|
||||
Emulator::audio.setBalance(balance);
|
||||
|
||||
bool reverb = settings["Audio/Reverb"].boolean();
|
||||
Emulator::audio.setReverb(reverb);
|
||||
}
|
|
@ -7,9 +7,11 @@ auto Program::load() -> void {
|
|||
Emulator::audio.reset(2, audio->frequency());
|
||||
if(emulator->load(media.id)) {
|
||||
gameQueue = {};
|
||||
connectDevices();
|
||||
updateInputDevices();
|
||||
applyHacks();
|
||||
emulator->power();
|
||||
updateVideoPalette();
|
||||
updateAudioEffects();
|
||||
showMessage(!appliedPatch() ? "Game loaded" : "Game loaded and patch applied");
|
||||
presentation->setTitle(emulator->title());
|
||||
presentation->resetSystem.setEnabled(true);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
auto Program::updateInputDriver() -> void {
|
||||
input = Input::create(settings["Input/Driver"].text());
|
||||
input->setContext(presentation->viewport.handle());
|
||||
|
||||
inputManager->initialize();
|
||||
settingsWindow->input.reloadPorts();
|
||||
settingsWindow->hotkeys.reloadMappings();
|
||||
settingsWindow->advanced.updateInputDriver();
|
||||
|
||||
if(!input->ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize [", settings["Input/Driver"].text(), "] input driver."
|
||||
}).error();
|
||||
settings["Input/Driver"].setValue("None");
|
||||
return updateInputDriver();
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::updateInputDevices() -> void {
|
||||
for(auto& port : emulator->ports) {
|
||||
auto path = string{"Emulator/", port.name}.replace(" ", "");
|
||||
auto name = settings(path).text();
|
||||
for(auto& device : port.devices) {
|
||||
if(device.name == name) {
|
||||
emulator->connect(port.id, device.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -200,12 +200,7 @@ auto Program::videoRefresh(const uint32* data, uint pitch, uint width, uint heig
|
|||
}
|
||||
|
||||
auto Program::audioSample(const double* samples, uint channels) -> void {
|
||||
if(presentation->muteAudio.checked()) {
|
||||
static const double mutedSamples[] = {0.0, 0.0};
|
||||
audio->output(mutedSamples);
|
||||
} else {
|
||||
audio->output(samples);
|
||||
}
|
||||
audio->output(samples);
|
||||
}
|
||||
|
||||
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#include "game-rom.cpp"
|
||||
#include "paths.cpp"
|
||||
#include "states.cpp"
|
||||
#include "video.cpp"
|
||||
#include "audio.cpp"
|
||||
#include "input.cpp"
|
||||
#include "utility.cpp"
|
||||
#include "patch.cpp"
|
||||
#include "hacks.cpp"
|
||||
|
@ -17,6 +20,14 @@ Program::Program(string_vector arguments) {
|
|||
new Presentation;
|
||||
presentation->setVisible();
|
||||
|
||||
new InputManager;
|
||||
new SettingsWindow;
|
||||
new CheatDatabase;
|
||||
new CheatWindow;
|
||||
new StateWindow;
|
||||
new ToolsWindow;
|
||||
new AboutWindow;
|
||||
|
||||
if(settings["Crashed"].boolean()) {
|
||||
MessageDialog(
|
||||
"Driver crash detected. Hardware drivers have been disabled.\n"
|
||||
|
@ -29,43 +40,12 @@ Program::Program(string_vector arguments) {
|
|||
|
||||
settings["Crashed"].setValue(true);
|
||||
settings.save();
|
||||
|
||||
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();
|
||||
if(!audio->ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize ", settings["Audio/Driver"].text(), " audio driver."
|
||||
}).setParent(*presentation).error();
|
||||
settings["Audio/Driver"].setValue("None");
|
||||
initializeAudioDriver();
|
||||
}
|
||||
initializeInputDriver();
|
||||
if(!input->ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize ", settings["Input/Driver"].text(), " input driver."
|
||||
}).setParent(*presentation).error();
|
||||
settings["Input/Driver"].setValue("None");
|
||||
initializeInputDriver();
|
||||
}
|
||||
|
||||
updateVideoDriver();
|
||||
updateAudioDriver();
|
||||
updateInputDriver();
|
||||
settings["Crashed"].setValue(false);
|
||||
settings.save();
|
||||
|
||||
new InputManager;
|
||||
new SettingsWindow;
|
||||
new CheatDatabase;
|
||||
new CheatWindow;
|
||||
new StateWindow;
|
||||
new ToolsWindow;
|
||||
new AboutWindow;
|
||||
|
||||
arguments.takeLeft(); //ignore program location in argument parsing
|
||||
for(auto& argument : arguments) {
|
||||
if(argument == "--fullscreen") {
|
||||
|
|
|
@ -45,16 +45,33 @@ struct Program : Emulator::Platform {
|
|||
auto statePath() -> string;
|
||||
|
||||
//states.cpp
|
||||
auto managedStates() -> string_vector;
|
||||
auto loadState(string filename) -> bool;
|
||||
auto saveState(string filename) -> bool;
|
||||
auto saveRecoveryState() -> bool;
|
||||
auto removeState(string filename) -> bool;
|
||||
auto renameState(string from, string to) -> bool;
|
||||
|
||||
//video.cpp
|
||||
auto updateVideoDriver() -> void;
|
||||
auto updateVideoBlocking() -> void;
|
||||
auto updateVideoShader() -> void;
|
||||
auto updateVideoPalette() -> void;
|
||||
|
||||
//audio.cpp
|
||||
auto updateAudioDriver() -> void;
|
||||
auto updateAudioExclusive() -> void;
|
||||
auto updateAudioDevice() -> void;
|
||||
auto updateAudioBlocking() -> void;
|
||||
auto updateAudioFrequency() -> void;
|
||||
auto updateAudioLatency() -> void;
|
||||
auto updateAudioEffects() -> void;
|
||||
|
||||
//input.cpp
|
||||
auto updateInputDriver() -> void;
|
||||
auto updateInputDevices() -> void;
|
||||
|
||||
//utility.cpp
|
||||
auto initializeVideoDriver() -> void;
|
||||
auto initializeAudioDriver() -> void;
|
||||
auto initializeInputDriver() -> void;
|
||||
auto updateVideoShader() -> void;
|
||||
auto connectDevices() -> void;
|
||||
auto showMessage(string text) -> void;
|
||||
auto showFrameRate(string text) -> void;
|
||||
auto updateStatus() -> void;
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
auto Program::managedStates() -> string_vector {
|
||||
if(!emulator->loaded()) return {};
|
||||
|
||||
if(gamePath().endsWith("/")) {
|
||||
return directory::ifiles({statePath(), "managed/"}, "*.bst");
|
||||
} else {
|
||||
Decode::ZIP input;
|
||||
if(input.open(statePath())) {
|
||||
string_vector filenames;
|
||||
for(auto& file : input.file) {
|
||||
if(file.name.match("managed/*.bst")) filenames.append(file.name);
|
||||
}
|
||||
filenames.isort();
|
||||
return filenames;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Program::loadState(string filename) -> bool {
|
||||
if(!emulator->loaded()) return false;
|
||||
|
||||
|
@ -44,10 +64,7 @@ auto Program::saveState(string filename) -> bool {
|
|||
} else {
|
||||
string location = {filename, ".bst"};
|
||||
|
||||
struct State {
|
||||
string name;
|
||||
vector<uint8_t> memory;
|
||||
};
|
||||
struct State { string name; vector<uint8_t> memory; };
|
||||
vector<State> states;
|
||||
|
||||
Decode::ZIP input;
|
||||
|
@ -76,3 +93,70 @@ auto Program::saveRecoveryState() -> bool {
|
|||
this->statusTime = statusTime;
|
||||
this->statusMessage = statusMessage;
|
||||
}
|
||||
|
||||
auto Program::removeState(string filename) -> bool {
|
||||
if(!emulator->loaded()) return false;
|
||||
|
||||
if(gamePath().endsWith("/")) {
|
||||
string location = {statePath(), filename, ".bst"};
|
||||
return file::remove(location);
|
||||
} else {
|
||||
bool found = false;
|
||||
string location = {filename, ".bst"};
|
||||
|
||||
struct State { string name; vector<uint8_t> memory; };
|
||||
vector<State> states;
|
||||
|
||||
Decode::ZIP input;
|
||||
if(input.open(statePath())) {
|
||||
for(auto& file : input.file) {
|
||||
if(file.name == location) { found = true; continue; }
|
||||
states.append({file.name, input.extract(file)});
|
||||
}
|
||||
}
|
||||
|
||||
if(states) {
|
||||
Encode::ZIP output{statePath()};
|
||||
for(auto& state : states) {
|
||||
output.append(state.name, state.memory.data(), state.memory.size());
|
||||
}
|
||||
} else {
|
||||
//remove .bsz file if there are no states left in the archive
|
||||
file::remove(statePath());
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::renameState(string from, string to) -> bool {
|
||||
if(!emulator->loaded()) return false;
|
||||
|
||||
if(gamePath().endsWith("/")) {
|
||||
from = {statePath(), from, ".bst"};
|
||||
to = {statePath(), to, ".bst."};
|
||||
return file::rename(from, to);
|
||||
} else {
|
||||
bool found = false;
|
||||
from = {from, ".bst"};
|
||||
to = {to, ".bst"};
|
||||
|
||||
struct State { string name; vector<uint8_t> memory; };
|
||||
vector<State> states;
|
||||
|
||||
Decode::ZIP input;
|
||||
if(input.open(statePath())) {
|
||||
for(auto& file : input.file) {
|
||||
if(file.name == from) { found = true; file.name = to; }
|
||||
states.append({file.name, input.extract(file)});
|
||||
}
|
||||
}
|
||||
|
||||
Encode::ZIP output{statePath()};
|
||||
for(auto& state : states) {
|
||||
output.append(state.name, state.memory.data(), state.memory.size());
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,70 +1,3 @@
|
|||
auto Program::initializeVideoDriver() -> void {
|
||||
video = Video::create(settings["Video/Driver"].text());
|
||||
video->setContext(presentation->viewport.handle());
|
||||
video->setExclusive(false);
|
||||
video->setBlocking(settings["Video/Blocking"].boolean());
|
||||
|
||||
if(video->ready()) {
|
||||
presentation->clearViewport();
|
||||
updateVideoShader();
|
||||
}
|
||||
|
||||
video->onUpdate([&](uint width, uint height) {
|
||||
if(!emulator->loaded()) presentation->clearViewport();
|
||||
});
|
||||
}
|
||||
|
||||
auto Program::initializeAudioDriver() -> void {
|
||||
audio = Audio::create(settings["Audio/Driver"].text());
|
||||
audio->setContext(presentation->viewport.handle());
|
||||
audio->setExclusive(false);
|
||||
audio->setBlocking(settings["Audio/Blocking"].boolean());
|
||||
if(!audio->availableDevices().find(settings["Audio/Device"].text())) {
|
||||
settings["Audio/Device"].setValue(audio->availableDevices()(0));
|
||||
}
|
||||
audio->setDevice(settings["Audio/Device"].text());
|
||||
if(!audio->availableFrequencies().find(settings["Audio/Frequency"].real())) {
|
||||
settings["Audio/Frequency"].setValue(audio->availableFrequencies()(0));
|
||||
}
|
||||
audio->setFrequency(settings["Audio/Frequency"].real());
|
||||
if(!audio->availableLatencies().find(settings["Audio/Latency"].natural())) {
|
||||
settings["Audio/Latency"].setValue(audio->availableLatencies()(0));
|
||||
}
|
||||
audio->setLatency(settings["Audio/Latency"].natural());
|
||||
audio->setChannels(2);
|
||||
}
|
||||
|
||||
auto Program::initializeInputDriver() -> void {
|
||||
input = Input::create(settings["Input/Driver"].text());
|
||||
input->setContext(presentation->viewport.handle());
|
||||
}
|
||||
|
||||
auto Program::updateVideoShader() -> void {
|
||||
if(settings["Video/Driver"].text() == "OpenGL"
|
||||
&& settings["Video/Shader"].text() != "None"
|
||||
&& settings["Video/Shader"].text() != "Blur"
|
||||
) {
|
||||
video->setSmooth(false);
|
||||
video->setShader(settings["Video/Shader"].text());
|
||||
} else {
|
||||
video->setSmooth(settings["Video/Shader"].text() == "Blur");
|
||||
video->setShader("");
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::connectDevices() -> void {
|
||||
for(auto& port : emulator->ports) {
|
||||
auto path = string{"Emulator/", port.name}.replace(" ", "");
|
||||
auto name = settings(path).text();
|
||||
for(auto& device : port.devices) {
|
||||
if(device.name == name) {
|
||||
emulator->connect(port.id, device.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::showMessage(string text) -> void {
|
||||
statusTime = chrono::timestamp();
|
||||
statusMessage = text;
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
auto Program::updateVideoDriver() -> void {
|
||||
video = Video::create(settings["Video/Driver"].text());
|
||||
video->setContext(presentation->viewport.handle());
|
||||
video->setExclusive(false);
|
||||
updateVideoBlocking();
|
||||
updateVideoShader();
|
||||
|
||||
if(video->ready()) {
|
||||
presentation->clearViewport();
|
||||
updateVideoShader();
|
||||
}
|
||||
|
||||
video->onUpdate([&](uint width, uint height) {
|
||||
if(!emulator->loaded()) presentation->clearViewport();
|
||||
});
|
||||
|
||||
settingsWindow->advanced.updateVideoDriver();
|
||||
|
||||
if(!video->ready()) {
|
||||
MessageDialog({
|
||||
"Error: failed to initialize [", settings["Video/Driver"].text(), "] video driver."
|
||||
}).error();
|
||||
settings["Video/Driver"].setValue("None");
|
||||
return updateVideoDriver();
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::updateVideoBlocking() -> void {
|
||||
video->setBlocking(settings["Video/Blocking"].boolean());
|
||||
}
|
||||
|
||||
auto Program::updateVideoShader() -> void {
|
||||
if(settings["Video/Driver"].text() == "OpenGL"
|
||||
&& settings["Video/Shader"].text() != "None"
|
||||
&& settings["Video/Shader"].text() != "Blur"
|
||||
) {
|
||||
video->setSmooth(false);
|
||||
video->setShader(settings["Video/Shader"].text());
|
||||
} else {
|
||||
video->setSmooth(settings["Video/Shader"].text() == "Blur");
|
||||
video->setShader("");
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::updateVideoPalette() -> void {
|
||||
emulator->set("Color Emulation", false);
|
||||
double luminance = settings["Video/Luminance"].natural() / 100.0;
|
||||
double saturation = settings["Video/Saturation"].natural() / 100.0;
|
||||
double gamma = settings["Video/Gamma"].natural() / 100.0;
|
||||
Emulator::video.setLuminance(luminance);
|
||||
Emulator::video.setSaturation(saturation);
|
||||
Emulator::video.setGamma(gamma);
|
||||
Emulator::video.setPalette();
|
||||
}
|
|
@ -6,12 +6,6 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||
driversLabel.setText("Drivers").setFont(Font().setBold());
|
||||
|
||||
videoDriverLabel.setText("Video:");
|
||||
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();
|
||||
settings["Video/Driver"].setValue(item.text());
|
||||
|
@ -24,29 +18,13 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||
program->saveRecoveryState();
|
||||
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();
|
||||
}
|
||||
}
|
||||
program->updateVideoDriver();
|
||||
settings["Crashed"].setValue(false);
|
||||
settings.save();
|
||||
}
|
||||
});
|
||||
|
||||
audioDriverLabel.setText("Audio:");
|
||||
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();
|
||||
settings["Audio/Driver"].setValue(item.text());
|
||||
|
@ -59,29 +37,13 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||
program->saveRecoveryState();
|
||||
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();
|
||||
}
|
||||
}
|
||||
program->updateAudioDriver();
|
||||
settings["Crashed"].setValue(false);
|
||||
settings.save();
|
||||
}
|
||||
});
|
||||
|
||||
inputDriverLabel.setText("Input:");
|
||||
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();
|
||||
settings["Input/Driver"].setValue(item.text());
|
||||
|
@ -94,17 +56,7 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||
program->saveRecoveryState();
|
||||
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();
|
||||
}
|
||||
}
|
||||
program->updateInputDriver();
|
||||
settings["Crashed"].setValue(false);
|
||||
settings.save();
|
||||
}
|
||||
|
@ -123,5 +75,35 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||
settings["Emulator/Hack/FastSuperFX"].setValue({superFXClock.position() * 10 + 100, "%"});
|
||||
superFXValue.setText(settings["Emulator/Hack/FastSuperFX"].text());
|
||||
}).doChange();
|
||||
hacksNote.setFont(Font().setItalic()).setText("Note: hack setting changes do not take effect until after reloading games.");
|
||||
hacksNote.setForegroundColor({224, 0, 0}).setText("Note: hack setting changes do not take effect until after reloading games.");
|
||||
}
|
||||
|
||||
auto AdvancedSettings::updateVideoDriver() -> void {
|
||||
videoDriverOption.reset();
|
||||
for(auto& driver : Video::availableDrivers()) {
|
||||
ComboButtonItem item;
|
||||
item.setText(driver);
|
||||
videoDriverOption.append(item);
|
||||
if(video && video->driver() == driver) item.setSelected();
|
||||
}
|
||||
}
|
||||
|
||||
auto AdvancedSettings::updateAudioDriver() -> void {
|
||||
audioDriverOption.reset();
|
||||
for(auto& driver : Audio::availableDrivers()) {
|
||||
ComboButtonItem item;
|
||||
item.setText(driver);
|
||||
audioDriverOption.append(item);
|
||||
if(audio && audio->driver() == driver) item.setSelected();
|
||||
}
|
||||
}
|
||||
|
||||
auto AdvancedSettings::updateInputDriver() -> void {
|
||||
inputDriverOption.reset();
|
||||
for(auto& driver : Input::availableDrivers()) {
|
||||
ComboButtonItem item;
|
||||
item.setText(driver);
|
||||
inputDriverOption.append(item);
|
||||
if(input && input->driver() == driver) item.setSelected();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,87 @@
|
|||
AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||
setIcon(Icon::Device::Speaker);
|
||||
setText("Audio");
|
||||
|
||||
layout.setMargin(5);
|
||||
|
||||
driverLabel.setFont(Font().setBold()).setText("Driver");
|
||||
deviceLabel.setText("Device:");
|
||||
deviceList.onChange([&] {
|
||||
settings["Audio/Device"].setValue(deviceList.selected().text());
|
||||
program->updateAudioDevice();
|
||||
});
|
||||
frequencyLabel.setText("Frequency:");
|
||||
frequencyList.onChange([&] {
|
||||
settings["Audio/Frequency"].setValue(frequencyList.selected().text());
|
||||
program->updateAudioFrequency();
|
||||
});
|
||||
latencyLabel.setText("Latency:");
|
||||
latencyList.onChange([&] {
|
||||
settings["Audio/Latency"].setValue(latencyList.selected().text());
|
||||
program->updateAudioLatency();
|
||||
});
|
||||
exclusiveMode.setText("Exclusive mode").setChecked(settings["Audio/Exclusive"].boolean()).onToggle([&] {
|
||||
settings["Audio/Exclusive"].setValue(exclusiveMode.checked());
|
||||
program->updateAudioExclusive();
|
||||
});
|
||||
|
||||
effectsLabel.setFont(Font().setBold()).setText("Effects");
|
||||
skewLabel.setText("Skew:");
|
||||
skewValue.setAlignment(0.5);
|
||||
skewSlider.setLength(10001).setPosition(settings["Audio/Skew"].integer() + 5000).onChange([&] {
|
||||
string value = {skewSlider.position() > 5000 ? "+" : "", (int)skewSlider.position() - 5000};
|
||||
settings["Audio/Skew"].setValue(value);
|
||||
skewValue.setText(value);
|
||||
program->updateAudioFrequency();
|
||||
}).doChange();
|
||||
volumeLabel.setText("Volume:");
|
||||
volumeValue.setAlignment(0.5);
|
||||
volumeSlider.setLength(201).setPosition(settings["Audio/Volume"].natural()).onChange([&] {
|
||||
string value = {volumeSlider.position(), "%"};
|
||||
settings["Audio/Volume"].setValue(value);
|
||||
volumeValue.setText(value);
|
||||
program->updateAudioEffects();
|
||||
}).doChange();
|
||||
balanceLabel.setText("Balance:");
|
||||
balanceValue.setAlignment(0.5);
|
||||
balanceSlider.setLength(101).setPosition(settings["Audio/Balance"].natural()).onChange([&] {
|
||||
string value = {balanceSlider.position(), "%"};
|
||||
settings["Audio/Balance"].setValue(value);
|
||||
balanceValue.setText(value);
|
||||
program->updateAudioEffects();
|
||||
}).doChange();
|
||||
reverb.setText("Reverb").setChecked(settings["Audio/Reverb"].boolean()).onToggle([&] {
|
||||
settings["Audio/Reverb"].setValue(reverb.checked());
|
||||
program->updateAudioEffects();
|
||||
});
|
||||
}
|
||||
|
||||
auto AudioSettings::updateDevice() -> void {
|
||||
deviceList.reset();
|
||||
for(auto& device : audio->availableDevices()) {
|
||||
deviceList.append(ComboButtonItem().setText(device));
|
||||
if(device == settings["Audio/Device"].text()) {
|
||||
deviceList.items().right().setSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto AudioSettings::updateFrequency() -> void {
|
||||
frequencyList.reset();
|
||||
for(auto& frequency : audio->availableFrequencies()) {
|
||||
frequencyList.append(ComboButtonItem().setText((uint)frequency));
|
||||
if(frequency == settings["Audio/Frequency"].real()) {
|
||||
frequencyList.items().right().setSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto AudioSettings::updateLatency() -> void {
|
||||
latencyList.reset();
|
||||
for(auto& latency : audio->availableLatencies()) {
|
||||
latencyList.append(ComboButtonItem().setText(latency));
|
||||
if(latency == settings["Audio/Latency"].natural()) {
|
||||
latencyList.items().right().setSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,6 @@ HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||
}
|
||||
refreshMappings();
|
||||
});
|
||||
|
||||
reloadMappings();
|
||||
refreshMappings();
|
||||
}
|
||||
|
||||
auto HotkeySettings::reloadMappings() -> void {
|
||||
|
@ -38,7 +35,8 @@ auto HotkeySettings::reloadMappings() -> void {
|
|||
.append(TableViewCell())
|
||||
);
|
||||
}
|
||||
mappingList.resizeColumns();
|
||||
refreshMappings();
|
||||
mappingList.doChange();
|
||||
}
|
||||
|
||||
auto HotkeySettings::refreshMappings() -> void {
|
||||
|
|
|
@ -35,8 +35,6 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) {
|
|||
}
|
||||
refreshMappings();
|
||||
});
|
||||
|
||||
reloadPorts();
|
||||
}
|
||||
|
||||
auto InputSettings::updateControls() -> void {
|
||||
|
|
|
@ -20,6 +20,9 @@ Settings::Settings() {
|
|||
set("Video/Exclusive", false);
|
||||
set("Video/Blocking", false);
|
||||
set("Video/Shader", "Blur");
|
||||
set("Video/Luminance", "100%");
|
||||
set("Video/Saturation", "100%");
|
||||
set("Video/Gamma", "150%");
|
||||
|
||||
set("Audio/Driver", Audio::safestDriver());
|
||||
set("Audio/Exclusive", false);
|
||||
|
@ -28,6 +31,10 @@ Settings::Settings() {
|
|||
set("Audio/Frequency", 48000.0);
|
||||
set("Audio/Latency", 0);
|
||||
set("Audio/Mute", false);
|
||||
set("Audio/Skew", "0");
|
||||
set("Audio/Volume", "100%");
|
||||
set("Audio/Balance", "50%");
|
||||
set("Audio/Reverb", false);
|
||||
|
||||
set("Input/Driver", Input::safestDriver());
|
||||
set("Input/Frequency", 5);
|
||||
|
@ -38,7 +45,6 @@ Settings::Settings() {
|
|||
set("View/OverscanCropping", true);
|
||||
set("View/IntegralScaling", true);
|
||||
set("View/BlurEmulation", true);
|
||||
set("View/ColorEmulation", true);
|
||||
|
||||
set("Path/Games", "");
|
||||
set("Path/Patches", "");
|
||||
|
|
|
@ -5,10 +5,57 @@ struct Settings : Markup::Node {
|
|||
|
||||
struct VideoSettings : TabFrameItem {
|
||||
VideoSettings(TabFrame*);
|
||||
|
||||
public:
|
||||
VerticalLayout layout{this};
|
||||
Label colorAdjustmentLabel{&layout, Size{~0, 0}, 2};
|
||||
HorizontalLayout luminanceLayout{&layout, Size{~0, 0}};
|
||||
Label luminanceLabel{&luminanceLayout, Size{65, 0}};
|
||||
Label luminanceValue{&luminanceLayout, Size{50, 0}};
|
||||
HorizontalSlider luminanceSlider{&luminanceLayout, Size{~0, 0}};
|
||||
HorizontalLayout saturationLayout{&layout, Size{~0, 0}};
|
||||
Label saturationLabel{&saturationLayout, Size{65, 0}};
|
||||
Label saturationValue{&saturationLayout, Size{50, 0}};
|
||||
HorizontalSlider saturationSlider{&saturationLayout, Size{~0, 0}};
|
||||
HorizontalLayout gammaLayout{&layout, Size{~0, 0}};
|
||||
Label gammaLabel{&gammaLayout, Size{65, 0}};
|
||||
Label gammaValue{&gammaLayout, Size{50, 0}};
|
||||
HorizontalSlider gammaSlider{&gammaLayout, Size{~0, 0}};
|
||||
Label fullscreenLabel{&layout, Size{~0, 0}, 2};
|
||||
CheckLabel exclusiveMode{&layout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct AudioSettings : TabFrameItem {
|
||||
AudioSettings(TabFrame*);
|
||||
auto updateDevice() -> void;
|
||||
auto updateFrequency() -> void;
|
||||
auto updateLatency() -> void;
|
||||
|
||||
public:
|
||||
VerticalLayout layout{this};
|
||||
Label driverLabel{&layout, Size{~0, 0}, 2};
|
||||
HorizontalLayout driverLayout{&layout, Size{~0, 0}};
|
||||
Label deviceLabel{&driverLayout, Size{0, 0}};
|
||||
ComboButton deviceList{&driverLayout, Size{~0, 0}};
|
||||
Label frequencyLabel{&driverLayout, Size{0, 0}};
|
||||
ComboButton frequencyList{&driverLayout, Size{80, 0}};
|
||||
Label latencyLabel{&driverLayout, Size{0, 0}};
|
||||
ComboButton latencyList{&driverLayout, Size{80, 0}};
|
||||
CheckLabel exclusiveMode{&layout, Size{~0, 0}};
|
||||
Label effectsLabel{&layout, Size{~0, 0}, 2};
|
||||
HorizontalLayout skewLayout{&layout, Size{~0, 0}};
|
||||
Label skewLabel{&skewLayout, Size{65, 0}};
|
||||
Label skewValue{&skewLayout, Size{50, 0}};
|
||||
HorizontalSlider skewSlider{&skewLayout, Size{~0, 0}};
|
||||
HorizontalLayout volumeLayout{&layout, Size{~0, 0}};
|
||||
Label volumeLabel{&volumeLayout, Size{65, 0}};
|
||||
Label volumeValue{&volumeLayout, Size{50, 0}};
|
||||
HorizontalSlider volumeSlider{&volumeLayout, Size{~0, 0}};
|
||||
HorizontalLayout balanceLayout{&layout, Size{~0, 0}};
|
||||
Label balanceLabel{&balanceLayout, Size{65, 0}};
|
||||
Label balanceValue{&balanceLayout, Size{50, 0}};
|
||||
HorizontalSlider balanceSlider{&balanceLayout, Size{~0, 0}};
|
||||
CheckLabel reverb{&layout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct InputSettings : TabFrameItem {
|
||||
|
@ -104,6 +151,9 @@ public:
|
|||
|
||||
struct AdvancedSettings : TabFrameItem {
|
||||
AdvancedSettings(TabFrame*);
|
||||
auto updateVideoDriver() -> void;
|
||||
auto updateAudioDriver() -> void;
|
||||
auto updateInputDriver() -> void;
|
||||
|
||||
public:
|
||||
VerticalLayout layout{this};
|
||||
|
|
|
@ -1,4 +1,37 @@
|
|||
VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||
setIcon(Icon::Device::Display);
|
||||
setText("Video");
|
||||
|
||||
layout.setMargin(5);
|
||||
|
||||
colorAdjustmentLabel.setFont(Font().setBold()).setText("Color Adjustment");
|
||||
luminanceLabel.setText("Luminance:");
|
||||
luminanceValue.setAlignment(0.5);
|
||||
luminanceSlider.setLength(101).setPosition(settings["Video/Luminance"].natural()).onChange([&] {
|
||||
string value = {luminanceSlider.position(), "%"};
|
||||
settings["Video/Luminance"].setValue(value);
|
||||
luminanceValue.setText(value);
|
||||
program->updateVideoPalette();
|
||||
}).doChange();
|
||||
saturationLabel.setText("Saturation:");
|
||||
saturationValue.setAlignment(0.5);
|
||||
saturationSlider.setLength(201).setPosition(settings["Video/Saturation"].natural()).onChange([&] {
|
||||
string value = {saturationSlider.position(), "%"};
|
||||
settings["Video/Saturation"].setValue(value);
|
||||
saturationValue.setText(value);
|
||||
program->updateVideoPalette();
|
||||
}).doChange();
|
||||
gammaLabel.setText("Gamma:");
|
||||
gammaValue.setAlignment(0.5);
|
||||
gammaSlider.setLength(101).setPosition(settings["Video/Gamma"].natural() - 100).onChange([&] {
|
||||
string value = {100 + gammaSlider.position(), "%"};
|
||||
settings["Video/Gamma"].setValue(value);
|
||||
gammaValue.setText(value);
|
||||
program->updateVideoPalette();
|
||||
}).doChange();
|
||||
|
||||
fullscreenLabel.setFont(Font().setBold()).setText("Fullscreen");
|
||||
exclusiveMode.setText("Exclusive mode").setChecked(settings["Video/Exclusive"].boolean()).onToggle([&] {
|
||||
settings["Video/Exclusive"].setValue(exclusiveMode.checked());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -107,27 +107,10 @@ auto StateManager::loadStates() -> void {
|
|||
stateList.append(TableViewHeader().setVisible(false)
|
||||
.append(TableViewColumn().setExpandable())
|
||||
);
|
||||
if(program->gamePath().endsWith("/")) {
|
||||
for(auto filename : directory::ifiles({program->statePath(), "managed/"}, "*.bst")) {
|
||||
stateList.append(TableViewItem()
|
||||
.append(TableViewCell().setText(filename.trimRight(".bst", 1L)))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
Decode::ZIP input;
|
||||
if(input.open(program->statePath())) {
|
||||
string_vector states;
|
||||
for(auto& file : input.file) {
|
||||
if(!file.name.match("managed/*.bst")) continue;
|
||||
states.append(Location::prefix(file.name));
|
||||
}
|
||||
states.isort();
|
||||
for(auto& state : states) {
|
||||
stateList.append(TableViewItem()
|
||||
.append(TableViewCell().setText(state))
|
||||
);
|
||||
}
|
||||
}
|
||||
for(auto filename : program->managedStates()) {
|
||||
stateList.append(TableViewItem()
|
||||
.append(TableViewCell().setText(filename.trimRight(".bst", 1L)))
|
||||
);
|
||||
}
|
||||
stateList.resizeColumns().doChange();
|
||||
}
|
||||
|
@ -143,10 +126,10 @@ auto StateManager::createState(string name) -> void {
|
|||
|
||||
auto StateManager::modifyState(string name) -> void {
|
||||
if(auto item = stateList.selected()) {
|
||||
string from = {program->statePath(), "managed/", item.cell(0).text(), ".bst"};
|
||||
string to = {program->statePath(), "managed/", name, ".bst"};
|
||||
string from = {"managed/", item.cell(0).text()};
|
||||
string to = {"managed/", name};
|
||||
if(from != to) {
|
||||
file::rename(from, to);
|
||||
program->renameState(from, to);
|
||||
loadStates();
|
||||
for(auto item : stateList.items()) {
|
||||
if(item.cell(0).text() == name) item.setSelected();
|
||||
|
@ -161,8 +144,7 @@ auto StateManager::removeStates() -> void {
|
|||
if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?")
|
||||
.setParent(*toolsWindow).question() == "Yes") {
|
||||
for(auto item : batched) {
|
||||
string location = {program->statePath(), "managed/", item.cell(0).text(), ".bst"};
|
||||
file::remove(location);
|
||||
program->removeState({"managed/", item.cell(0).text()});
|
||||
}
|
||||
loadStates();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue