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 {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
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 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/";
|
||||||
|
|
|
@ -176,6 +176,14 @@ auto InputMapping::displayName() -> string {
|
||||||
|
|
||||||
InputManager::InputManager() {
|
InputManager::InputManager() {
|
||||||
inputManager = this;
|
inputManager = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto InputManager::initialize() -> void {
|
||||||
|
devices.reset();
|
||||||
|
ports.reset();
|
||||||
|
hotkeys.reset();
|
||||||
|
|
||||||
|
if(!input) return;
|
||||||
input->onChange({&InputManager::onChange, this});
|
input->onChange({&InputManager::onChange, this});
|
||||||
frequency = max(1u, settings["Input/Frequency"].natural());
|
frequency = max(1u, settings["Input/Frequency"].natural());
|
||||||
|
|
||||||
|
@ -197,6 +205,7 @@ InputManager::InputManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bindHotkeys();
|
bindHotkeys();
|
||||||
|
poll();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto InputManager::bind() -> void {
|
auto InputManager::bind() -> void {
|
||||||
|
|
|
@ -54,6 +54,7 @@ struct InputPort {
|
||||||
|
|
||||||
struct InputManager {
|
struct InputManager {
|
||||||
InputManager();
|
InputManager();
|
||||||
|
auto initialize() -> void;
|
||||||
auto bind() -> void;
|
auto bind() -> void;
|
||||||
auto poll() -> void;
|
auto poll() -> void;
|
||||||
auto onChange(shared_pointer<HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue) -> 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());
|
settings["View/BlurEmulation"].setValue(blurEmulation.checked());
|
||||||
emulator->set("Blur Emulation", blurEmulation.checked());
|
emulator->set("Blur Emulation", blurEmulation.checked());
|
||||||
}).doToggle();
|
}).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");
|
shaderMenu.setText("Shader");
|
||||||
updateShaders();
|
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([&] {
|
muteAudio.setText("Mute Audio").setChecked(settings["Audio/Mute"].boolean()).onToggle([&] {
|
||||||
settings["Audio/Mute"].setValue(muteAudio.checked());
|
settings["Audio/Mute"].setValue(muteAudio.checked());
|
||||||
|
program->updateAudioEffects();
|
||||||
});
|
});
|
||||||
showStatusBar.setText("Show Status Bar").setChecked(settings["UserInterface/ShowStatusBar"].boolean()).onToggle([&] {
|
showStatusBar.setText("Show Status Bar").setChecked(settings["UserInterface/ShowStatusBar"].boolean()).onToggle([&] {
|
||||||
settings["UserInterface/ShowStatusBar"].setValue(showStatusBar.checked());
|
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 {
|
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {
|
||||||
|
return;
|
||||||
|
|
||||||
int ox = width - 144;
|
int ox = width - 144;
|
||||||
int oy = height - 128;
|
int oy = height - 128;
|
||||||
if(ox >= 0 && oy >= 0) {
|
if(ox >= 0 && oy >= 0) {
|
||||||
|
|
|
@ -46,11 +46,13 @@ struct Presentation : Window {
|
||||||
MenuCheckItem overscanCropping{&viewMenu};
|
MenuCheckItem overscanCropping{&viewMenu};
|
||||||
MenuCheckItem integralScaling{&viewMenu};
|
MenuCheckItem integralScaling{&viewMenu};
|
||||||
MenuCheckItem blurEmulation{&viewMenu};
|
MenuCheckItem blurEmulation{&viewMenu};
|
||||||
MenuCheckItem colorEmulation{&viewMenu};
|
|
||||||
Menu shaderMenu{&settingsMenu};
|
Menu shaderMenu{&settingsMenu};
|
||||||
|
MenuSeparator settingsSeparatorA{&settingsMenu};
|
||||||
|
MenuCheckItem synchronizeVideo{&settingsMenu};
|
||||||
|
MenuCheckItem synchronizeAudio{&settingsMenu};
|
||||||
MenuCheckItem muteAudio{&settingsMenu};
|
MenuCheckItem muteAudio{&settingsMenu};
|
||||||
MenuCheckItem showStatusBar{&settingsMenu};
|
MenuCheckItem showStatusBar{&settingsMenu};
|
||||||
MenuSeparator settingsSeparator{&settingsMenu};
|
MenuSeparator settingsSeparatorB{&settingsMenu};
|
||||||
MenuItem videoSettings{&settingsMenu};
|
MenuItem videoSettings{&settingsMenu};
|
||||||
MenuItem audioSettings{&settingsMenu};
|
MenuItem audioSettings{&settingsMenu};
|
||||||
MenuItem inputSettings{&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());
|
Emulator::audio.reset(2, audio->frequency());
|
||||||
if(emulator->load(media.id)) {
|
if(emulator->load(media.id)) {
|
||||||
gameQueue = {};
|
gameQueue = {};
|
||||||
connectDevices();
|
updateInputDevices();
|
||||||
applyHacks();
|
applyHacks();
|
||||||
emulator->power();
|
emulator->power();
|
||||||
|
updateVideoPalette();
|
||||||
|
updateAudioEffects();
|
||||||
showMessage(!appliedPatch() ? "Game loaded" : "Game loaded and patch applied");
|
showMessage(!appliedPatch() ? "Game loaded" : "Game loaded and patch applied");
|
||||||
presentation->setTitle(emulator->title());
|
presentation->setTitle(emulator->title());
|
||||||
presentation->resetSystem.setEnabled(true);
|
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 {
|
auto Program::audioSample(const double* samples, uint channels) -> void {
|
||||||
if(presentation->muteAudio.checked()) {
|
audio->output(samples);
|
||||||
static const double mutedSamples[] = {0.0, 0.0};
|
|
||||||
audio->output(mutedSamples);
|
|
||||||
} else {
|
|
||||||
audio->output(samples);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
auto Program::inputPoll(uint port, uint device, uint input) -> int16 {
|
||||||
|
|
|
@ -5,6 +5,9 @@
|
||||||
#include "game-rom.cpp"
|
#include "game-rom.cpp"
|
||||||
#include "paths.cpp"
|
#include "paths.cpp"
|
||||||
#include "states.cpp"
|
#include "states.cpp"
|
||||||
|
#include "video.cpp"
|
||||||
|
#include "audio.cpp"
|
||||||
|
#include "input.cpp"
|
||||||
#include "utility.cpp"
|
#include "utility.cpp"
|
||||||
#include "patch.cpp"
|
#include "patch.cpp"
|
||||||
#include "hacks.cpp"
|
#include "hacks.cpp"
|
||||||
|
@ -17,6 +20,14 @@ Program::Program(string_vector arguments) {
|
||||||
new Presentation;
|
new Presentation;
|
||||||
presentation->setVisible();
|
presentation->setVisible();
|
||||||
|
|
||||||
|
new InputManager;
|
||||||
|
new SettingsWindow;
|
||||||
|
new CheatDatabase;
|
||||||
|
new CheatWindow;
|
||||||
|
new StateWindow;
|
||||||
|
new ToolsWindow;
|
||||||
|
new AboutWindow;
|
||||||
|
|
||||||
if(settings["Crashed"].boolean()) {
|
if(settings["Crashed"].boolean()) {
|
||||||
MessageDialog(
|
MessageDialog(
|
||||||
"Driver crash detected. Hardware drivers have been disabled.\n"
|
"Driver crash detected. Hardware drivers have been disabled.\n"
|
||||||
|
@ -29,43 +40,12 @@ Program::Program(string_vector arguments) {
|
||||||
|
|
||||||
settings["Crashed"].setValue(true);
|
settings["Crashed"].setValue(true);
|
||||||
settings.save();
|
settings.save();
|
||||||
|
updateVideoDriver();
|
||||||
initializeVideoDriver();
|
updateAudioDriver();
|
||||||
if(!video->ready()) {
|
updateInputDriver();
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
settings["Crashed"].setValue(false);
|
settings["Crashed"].setValue(false);
|
||||||
settings.save();
|
settings.save();
|
||||||
|
|
||||||
new InputManager;
|
|
||||||
new SettingsWindow;
|
|
||||||
new CheatDatabase;
|
|
||||||
new CheatWindow;
|
|
||||||
new StateWindow;
|
|
||||||
new ToolsWindow;
|
|
||||||
new AboutWindow;
|
|
||||||
|
|
||||||
arguments.takeLeft(); //ignore program location in argument parsing
|
arguments.takeLeft(); //ignore program location in argument parsing
|
||||||
for(auto& argument : arguments) {
|
for(auto& argument : arguments) {
|
||||||
if(argument == "--fullscreen") {
|
if(argument == "--fullscreen") {
|
||||||
|
|
|
@ -45,16 +45,33 @@ struct Program : Emulator::Platform {
|
||||||
auto statePath() -> string;
|
auto statePath() -> string;
|
||||||
|
|
||||||
//states.cpp
|
//states.cpp
|
||||||
|
auto managedStates() -> string_vector;
|
||||||
auto loadState(string filename) -> bool;
|
auto loadState(string filename) -> bool;
|
||||||
auto saveState(string filename) -> bool;
|
auto saveState(string filename) -> bool;
|
||||||
auto saveRecoveryState() -> 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
|
//utility.cpp
|
||||||
auto initializeVideoDriver() -> void;
|
|
||||||
auto initializeAudioDriver() -> void;
|
|
||||||
auto initializeInputDriver() -> void;
|
|
||||||
auto updateVideoShader() -> void;
|
|
||||||
auto connectDevices() -> void;
|
|
||||||
auto showMessage(string text) -> void;
|
auto showMessage(string text) -> void;
|
||||||
auto showFrameRate(string text) -> void;
|
auto showFrameRate(string text) -> void;
|
||||||
auto updateStatus() -> 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 {
|
auto Program::loadState(string filename) -> bool {
|
||||||
if(!emulator->loaded()) return false;
|
if(!emulator->loaded()) return false;
|
||||||
|
|
||||||
|
@ -44,10 +64,7 @@ auto Program::saveState(string filename) -> bool {
|
||||||
} else {
|
} else {
|
||||||
string location = {filename, ".bst"};
|
string location = {filename, ".bst"};
|
||||||
|
|
||||||
struct State {
|
struct State { string name; vector<uint8_t> memory; };
|
||||||
string name;
|
|
||||||
vector<uint8_t> memory;
|
|
||||||
};
|
|
||||||
vector<State> states;
|
vector<State> states;
|
||||||
|
|
||||||
Decode::ZIP input;
|
Decode::ZIP input;
|
||||||
|
@ -76,3 +93,70 @@ auto Program::saveRecoveryState() -> bool {
|
||||||
this->statusTime = statusTime;
|
this->statusTime = statusTime;
|
||||||
this->statusMessage = statusMessage;
|
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 {
|
auto Program::showMessage(string text) -> void {
|
||||||
statusTime = chrono::timestamp();
|
statusTime = chrono::timestamp();
|
||||||
statusMessage = text;
|
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());
|
driversLabel.setText("Drivers").setFont(Font().setBold());
|
||||||
|
|
||||||
videoDriverLabel.setText("Video:");
|
videoDriverLabel.setText("Video:");
|
||||||
for(auto& driver : Video::availableDrivers()) {
|
|
||||||
ComboButtonItem item;
|
|
||||||
item.setText(driver);
|
|
||||||
videoDriverOption.append(item);
|
|
||||||
if(video->driver() == driver) item.setSelected();
|
|
||||||
}
|
|
||||||
videoDriverOption.onChange([&] {
|
videoDriverOption.onChange([&] {
|
||||||
auto item = videoDriverOption.selected();
|
auto item = videoDriverOption.selected();
|
||||||
settings["Video/Driver"].setValue(item.text());
|
settings["Video/Driver"].setValue(item.text());
|
||||||
|
@ -24,29 +18,13 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
program->saveRecoveryState();
|
program->saveRecoveryState();
|
||||||
settings["Crashed"].setValue(true);
|
settings["Crashed"].setValue(true);
|
||||||
settings.save();
|
settings.save();
|
||||||
program->initializeVideoDriver();
|
program->updateVideoDriver();
|
||||||
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["Crashed"].setValue(false);
|
||||||
settings.save();
|
settings.save();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
audioDriverLabel.setText("Audio:");
|
audioDriverLabel.setText("Audio:");
|
||||||
for(auto& driver : Audio::availableDrivers()) {
|
|
||||||
ComboButtonItem item;
|
|
||||||
item.setText(driver);
|
|
||||||
audioDriverOption.append(item);
|
|
||||||
if(audio->driver() == driver) item.setSelected();
|
|
||||||
}
|
|
||||||
audioDriverOption.onChange([&] {
|
audioDriverOption.onChange([&] {
|
||||||
auto item = audioDriverOption.selected();
|
auto item = audioDriverOption.selected();
|
||||||
settings["Audio/Driver"].setValue(item.text());
|
settings["Audio/Driver"].setValue(item.text());
|
||||||
|
@ -59,29 +37,13 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
program->saveRecoveryState();
|
program->saveRecoveryState();
|
||||||
settings["Crashed"].setValue(true);
|
settings["Crashed"].setValue(true);
|
||||||
settings.save();
|
settings.save();
|
||||||
program->initializeAudioDriver();
|
program->updateAudioDriver();
|
||||||
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["Crashed"].setValue(false);
|
||||||
settings.save();
|
settings.save();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
inputDriverLabel.setText("Input:");
|
inputDriverLabel.setText("Input:");
|
||||||
for(auto& driver : Input::availableDrivers()) {
|
|
||||||
ComboButtonItem item;
|
|
||||||
item.setText(driver);
|
|
||||||
inputDriverOption.append(item);
|
|
||||||
if(input->driver() == driver) item.setSelected();
|
|
||||||
}
|
|
||||||
inputDriverOption.onChange([&] {
|
inputDriverOption.onChange([&] {
|
||||||
auto item = inputDriverOption.selected();
|
auto item = inputDriverOption.selected();
|
||||||
settings["Input/Driver"].setValue(item.text());
|
settings["Input/Driver"].setValue(item.text());
|
||||||
|
@ -94,17 +56,7 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
program->saveRecoveryState();
|
program->saveRecoveryState();
|
||||||
settings["Crashed"].setValue(true);
|
settings["Crashed"].setValue(true);
|
||||||
settings.save();
|
settings.save();
|
||||||
program->initializeInputDriver();
|
program->updateInputDriver();
|
||||||
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["Crashed"].setValue(false);
|
||||||
settings.save();
|
settings.save();
|
||||||
}
|
}
|
||||||
|
@ -123,5 +75,35 @@ AdvancedSettings::AdvancedSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
settings["Emulator/Hack/FastSuperFX"].setValue({superFXClock.position() * 10 + 100, "%"});
|
settings["Emulator/Hack/FastSuperFX"].setValue({superFXClock.position() * 10 + 100, "%"});
|
||||||
superFXValue.setText(settings["Emulator/Hack/FastSuperFX"].text());
|
superFXValue.setText(settings["Emulator/Hack/FastSuperFX"].text());
|
||||||
}).doChange();
|
}).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) {
|
AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
setIcon(Icon::Device::Speaker);
|
setIcon(Icon::Device::Speaker);
|
||||||
setText("Audio");
|
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();
|
refreshMappings();
|
||||||
});
|
});
|
||||||
|
|
||||||
reloadMappings();
|
|
||||||
refreshMappings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HotkeySettings::reloadMappings() -> void {
|
auto HotkeySettings::reloadMappings() -> void {
|
||||||
|
@ -38,7 +35,8 @@ auto HotkeySettings::reloadMappings() -> void {
|
||||||
.append(TableViewCell())
|
.append(TableViewCell())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
mappingList.resizeColumns();
|
refreshMappings();
|
||||||
|
mappingList.doChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto HotkeySettings::refreshMappings() -> void {
|
auto HotkeySettings::refreshMappings() -> void {
|
||||||
|
|
|
@ -35,8 +35,6 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
}
|
}
|
||||||
refreshMappings();
|
refreshMappings();
|
||||||
});
|
});
|
||||||
|
|
||||||
reloadPorts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto InputSettings::updateControls() -> void {
|
auto InputSettings::updateControls() -> void {
|
||||||
|
|
|
@ -20,6 +20,9 @@ Settings::Settings() {
|
||||||
set("Video/Exclusive", false);
|
set("Video/Exclusive", false);
|
||||||
set("Video/Blocking", false);
|
set("Video/Blocking", false);
|
||||||
set("Video/Shader", "Blur");
|
set("Video/Shader", "Blur");
|
||||||
|
set("Video/Luminance", "100%");
|
||||||
|
set("Video/Saturation", "100%");
|
||||||
|
set("Video/Gamma", "150%");
|
||||||
|
|
||||||
set("Audio/Driver", Audio::safestDriver());
|
set("Audio/Driver", Audio::safestDriver());
|
||||||
set("Audio/Exclusive", false);
|
set("Audio/Exclusive", false);
|
||||||
|
@ -28,6 +31,10 @@ Settings::Settings() {
|
||||||
set("Audio/Frequency", 48000.0);
|
set("Audio/Frequency", 48000.0);
|
||||||
set("Audio/Latency", 0);
|
set("Audio/Latency", 0);
|
||||||
set("Audio/Mute", false);
|
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/Driver", Input::safestDriver());
|
||||||
set("Input/Frequency", 5);
|
set("Input/Frequency", 5);
|
||||||
|
@ -38,7 +45,6 @@ Settings::Settings() {
|
||||||
set("View/OverscanCropping", true);
|
set("View/OverscanCropping", true);
|
||||||
set("View/IntegralScaling", true);
|
set("View/IntegralScaling", true);
|
||||||
set("View/BlurEmulation", true);
|
set("View/BlurEmulation", true);
|
||||||
set("View/ColorEmulation", true);
|
|
||||||
|
|
||||||
set("Path/Games", "");
|
set("Path/Games", "");
|
||||||
set("Path/Patches", "");
|
set("Path/Patches", "");
|
||||||
|
|
|
@ -5,10 +5,57 @@ struct Settings : Markup::Node {
|
||||||
|
|
||||||
struct VideoSettings : TabFrameItem {
|
struct VideoSettings : TabFrameItem {
|
||||||
VideoSettings(TabFrame*);
|
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 {
|
struct AudioSettings : TabFrameItem {
|
||||||
AudioSettings(TabFrame*);
|
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 {
|
struct InputSettings : TabFrameItem {
|
||||||
|
@ -104,6 +151,9 @@ public:
|
||||||
|
|
||||||
struct AdvancedSettings : TabFrameItem {
|
struct AdvancedSettings : TabFrameItem {
|
||||||
AdvancedSettings(TabFrame*);
|
AdvancedSettings(TabFrame*);
|
||||||
|
auto updateVideoDriver() -> void;
|
||||||
|
auto updateAudioDriver() -> void;
|
||||||
|
auto updateInputDriver() -> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VerticalLayout layout{this};
|
VerticalLayout layout{this};
|
||||||
|
|
|
@ -1,4 +1,37 @@
|
||||||
VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
|
VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) {
|
||||||
setIcon(Icon::Device::Display);
|
setIcon(Icon::Device::Display);
|
||||||
setText("Video");
|
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)
|
stateList.append(TableViewHeader().setVisible(false)
|
||||||
.append(TableViewColumn().setExpandable())
|
.append(TableViewColumn().setExpandable())
|
||||||
);
|
);
|
||||||
if(program->gamePath().endsWith("/")) {
|
for(auto filename : program->managedStates()) {
|
||||||
for(auto filename : directory::ifiles({program->statePath(), "managed/"}, "*.bst")) {
|
stateList.append(TableViewItem()
|
||||||
stateList.append(TableViewItem()
|
.append(TableViewCell().setText(filename.trimRight(".bst", 1L)))
|
||||||
.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))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
stateList.resizeColumns().doChange();
|
stateList.resizeColumns().doChange();
|
||||||
}
|
}
|
||||||
|
@ -143,10 +126,10 @@ auto StateManager::createState(string name) -> void {
|
||||||
|
|
||||||
auto StateManager::modifyState(string name) -> void {
|
auto StateManager::modifyState(string name) -> void {
|
||||||
if(auto item = stateList.selected()) {
|
if(auto item = stateList.selected()) {
|
||||||
string from = {program->statePath(), "managed/", item.cell(0).text(), ".bst"};
|
string from = {"managed/", item.cell(0).text()};
|
||||||
string to = {program->statePath(), "managed/", name, ".bst"};
|
string to = {"managed/", name};
|
||||||
if(from != to) {
|
if(from != to) {
|
||||||
file::rename(from, to);
|
program->renameState(from, to);
|
||||||
loadStates();
|
loadStates();
|
||||||
for(auto item : stateList.items()) {
|
for(auto item : stateList.items()) {
|
||||||
if(item.cell(0).text() == name) item.setSelected();
|
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)?")
|
if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?")
|
||||||
.setParent(*toolsWindow).question() == "Yes") {
|
.setParent(*toolsWindow).question() == "Yes") {
|
||||||
for(auto item : batched) {
|
for(auto item : batched) {
|
||||||
string location = {program->statePath(), "managed/", item.cell(0).text(), ".bst"};
|
program->removeState({"managed/", item.cell(0).text()});
|
||||||
file::remove(location);
|
|
||||||
}
|
}
|
||||||
loadStates();
|
loadStates();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue