mirror of https://github.com/bsnes-emu/bsnes.git
v108.16
Added compatibility option to disable accurate CPU ALU emulation Refactored settings panels Added dialog to choose whether IPS patches are for headered ROMs Disabled extended SNES header decoding thanks to ROM hacks ignoring them
This commit is contained in:
parent
08e5e81609
commit
2bb1606552
|
@ -29,7 +29,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "bsnes";
|
||||
static const string Version = "108.15";
|
||||
static const string Version = "108.16";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org";
|
||||
|
|
|
@ -140,6 +140,11 @@ auto SuperFamicom::manifest() const -> string {
|
|||
}
|
||||
|
||||
auto SuperFamicom::region() const -> string {
|
||||
//Unlicensed software (homebrew, ROM hacks, etc) often change the standard region code,
|
||||
//and then neglect to change the extended header region code. Thanks to that, we can't
|
||||
//decode and display the full game serial + region code.
|
||||
return videoRegion();
|
||||
|
||||
string region;
|
||||
|
||||
char A = data[headerAddress + 0x02]; //game type
|
||||
|
|
|
@ -96,11 +96,13 @@ auto CPU::power(bool reset) -> void {
|
|||
|
||||
if(!reset) random.array(wram, sizeof(wram));
|
||||
|
||||
//Dirt Racer (Europe) relies on uninitialized memory containing certain values to boot without freezing.
|
||||
//the game itself is broken and will fail to run sometimes on real hardware, but for the sake of expedience,
|
||||
//WRAM is initialized to a constant value that will allow this game to always boot in successfully.
|
||||
if(cartridge.headerTitle() == "DIRT RACER") {
|
||||
for(auto& byte : wram) byte = 0xff;
|
||||
if(configuration.hacks.hotfixes) {
|
||||
//Dirt Racer (Europe) relies on uninitialized memory containing certain values to boot without freezing.
|
||||
//the game itself is broken and will fail to run sometimes on real hardware, but for the sake of expedience,
|
||||
//WRAM is initialized to a constant value that will allow this game to always boot in successfully.
|
||||
if(cartridge.headerTitle() == "DIRT RACER") {
|
||||
for(auto& byte : wram) byte = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
for(uint n : range(8)) {
|
||||
|
|
|
@ -151,8 +151,12 @@ auto CPU::writeCPU(uint addr, uint8 data) -> void {
|
|||
io.wrmpyb = data;
|
||||
io.rddiv = io.wrmpyb << 8 | io.wrmpya;
|
||||
|
||||
alu.mpyctr = 8; //perform multiplication over the next eight cycles
|
||||
alu.shift = io.wrmpyb;
|
||||
if(!configuration.hacks.cpu.fastMath) {
|
||||
alu.mpyctr = 8; //perform multiplication over the next eight cycles
|
||||
alu.shift = io.wrmpyb;
|
||||
} else {
|
||||
io.rdmpy = io.wrmpya * io.wrmpyb;
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x4204: //WRDIVL
|
||||
|
@ -169,8 +173,18 @@ auto CPU::writeCPU(uint addr, uint8 data) -> void {
|
|||
|
||||
io.wrdivb = data;
|
||||
|
||||
alu.divctr = 16; //perform division over the next sixteen cycles
|
||||
alu.shift = io.wrdivb << 16;
|
||||
if(!configuration.hacks.cpu.fastMath) {
|
||||
alu.divctr = 16; //perform division over the next sixteen cycles
|
||||
alu.shift = io.wrdivb << 16;
|
||||
} else {
|
||||
if(io.wrdivb) {
|
||||
io.rddiv = io.wrdiva / io.wrdivb;
|
||||
io.rdmpy = io.wrdiva % io.wrdivb;
|
||||
} else {
|
||||
io.rddiv = 0xffff;
|
||||
io.rdmpy = io.wrdiva;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x4207: //HTIMEL
|
||||
|
|
|
@ -838,7 +838,7 @@ void SPC_DSP::run( int clocks_remain )
|
|||
void SPC_DSP::init( void* ram_64k, void* echo_64k )
|
||||
{
|
||||
m.ram = (uint8_t*) ram_64k;
|
||||
m.echo = (uint8_t*) echo_64k;
|
||||
m.echo = (uint8_t*) echo_64k;
|
||||
mute_voices( 0 );
|
||||
disable_surround( false );
|
||||
set_output( 0, 0 );
|
||||
|
|
|
@ -16,8 +16,10 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
|
|||
bind(boolean, "Video/BlurEmulation", video.blurEmulation);
|
||||
bind(boolean, "Video/ColorEmulation", video.colorEmulation);
|
||||
|
||||
bind(boolean, "Hacks/Hotfixes", hacks.hotfixes);
|
||||
bind(text, "Hacks/Entropy", hacks.entropy);
|
||||
bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
|
||||
bind(boolean, "Hacks/CPU/FastMath", hacks.cpu.fastMath);
|
||||
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast);
|
||||
bind(boolean, "Hacks/PPU/Deinterlace", hacks.ppu.deinterlace);
|
||||
bind(natural, "Hacks/PPU/RenderCycle", hacks.ppu.renderCycle);
|
||||
|
|
|
@ -25,9 +25,11 @@ struct Configuration {
|
|||
} video;
|
||||
|
||||
struct Hacks {
|
||||
bool hotfixes = true;
|
||||
string entropy = "Low";
|
||||
struct CPU {
|
||||
uint overclock = 100;
|
||||
bool fastMath = false;
|
||||
} cpu;
|
||||
struct PPU {
|
||||
bool fast = true;
|
||||
|
|
|
@ -106,9 +106,10 @@ auto Presentation::create() -> void {
|
|||
inputSettings.setIcon(Icon::Device::Joypad).setText("Input ...").onActivate([&] { settingsWindow.show(2); });
|
||||
hotkeySettings.setIcon(Icon::Device::Keyboard).setText("Hotkeys ...").onActivate([&] { settingsWindow.show(3); });
|
||||
pathSettings.setIcon(Icon::Emblem::Folder).setText("Paths ...").onActivate([&] { settingsWindow.show(4); });
|
||||
speedSettings.setIcon(Icon::Device::Clock).setText("Speed ...").onActivate([&] { settingsWindow.show(5); });
|
||||
emulatorSettings.setIcon(Icon::Action::Settings).setText("Emulator ...").onActivate([&] { settingsWindow.show(6); });
|
||||
driverSettings.setIcon(Icon::Place::Settings).setText("Drivers ...").onActivate([&] { settingsWindow.show(7); });
|
||||
emulatorSettings.setIcon(Icon::Action::Settings).setText("Emulator ...").onActivate([&] { settingsWindow.show(5); });
|
||||
enhancementSettings.setIcon(Icon::Action::Add).setText("Enhancements ...").onActivate([&] { settingsWindow.show(6); });
|
||||
compatibilitySettings.setIcon(Icon::Action::Remove).setText("Compatibility ...").onActivate([&] { settingsWindow.show(7); });
|
||||
driverSettings.setIcon(Icon::Place::Settings).setText("Drivers ...").onActivate([&] { settingsWindow.show(8); });
|
||||
|
||||
toolsMenu.setText(tr("Tools")).setVisible(false);
|
||||
saveState.setIcon(Icon::Media::Record).setText("Save State");
|
||||
|
@ -180,18 +181,6 @@ auto Presentation::create() -> void {
|
|||
documentation.setIcon(Icon::Application::Browser).setText({tr("Documentation"), " ..."}).onActivate([&] {
|
||||
invoke("https://doc.byuu.org/bsnes");
|
||||
});
|
||||
about.setIcon(Icon::Prompt::Question).setText({tr("About bsnes"), " ..."}).onActivate([&] {
|
||||
AboutDialog()
|
||||
.setName(Emulator::Name)
|
||||
.setLogo(Resource::Logo)
|
||||
.setDescription("Super Nintendo emulator")
|
||||
.setVersion(Emulator::Version)
|
||||
.setAuthor("byuu")
|
||||
.setLicense("GPLv3")
|
||||
.setWebsite("https://byuu.org")
|
||||
.setAlignment(*this)
|
||||
.show();
|
||||
});
|
||||
aboutSameBoy.setIcon(Icon::Prompt::Question).setText({tr("About SameBoy"), " ..."}).onActivate([&] {
|
||||
AboutDialog()
|
||||
.setName("SameBoy")
|
||||
|
@ -204,6 +193,18 @@ auto Presentation::create() -> void {
|
|||
.setAlignment(*this)
|
||||
.show();
|
||||
});
|
||||
about.setIcon(Icon::Prompt::Question).setText({tr("About bsnes"), " ..."}).onActivate([&] {
|
||||
AboutDialog()
|
||||
.setName(Emulator::Name)
|
||||
.setLogo(Resource::Logo)
|
||||
.setDescription("Super Nintendo emulator")
|
||||
.setVersion(Emulator::Version)
|
||||
.setAuthor("byuu")
|
||||
.setLicense("GPLv3")
|
||||
.setWebsite("https://byuu.org")
|
||||
.setAlignment(*this)
|
||||
.show();
|
||||
});
|
||||
|
||||
viewport.setFocusable();
|
||||
viewport.setDroppable();
|
||||
|
|
|
@ -85,8 +85,9 @@ struct Presentation : Window {
|
|||
MenuItem inputSettings{&settingsMenu};
|
||||
MenuItem hotkeySettings{&settingsMenu};
|
||||
MenuItem pathSettings{&settingsMenu};
|
||||
MenuItem speedSettings{&settingsMenu};
|
||||
MenuItem emulatorSettings{&settingsMenu};
|
||||
MenuItem enhancementSettings{&settingsMenu};
|
||||
MenuItem compatibilitySettings{&settingsMenu};
|
||||
MenuItem driverSettings{&settingsMenu};
|
||||
Menu toolsMenu{&menuBar};
|
||||
Menu saveState{&toolsMenu};
|
||||
|
@ -118,8 +119,8 @@ struct Presentation : Window {
|
|||
Menu helpMenu{&menuBar};
|
||||
MenuItem documentation{&helpMenu};
|
||||
MenuSeparator helpSeparator{&helpMenu};
|
||||
MenuItem about{&helpMenu};
|
||||
MenuItem aboutSameBoy{&helpMenu};
|
||||
MenuItem about{&helpMenu};
|
||||
|
||||
VerticalLayout layout{this};
|
||||
HorizontalLayout viewportLayout{&layout, Size{~0, ~0}, 0};
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
auto Program::load() -> void {
|
||||
unload();
|
||||
|
||||
emulator->configure("Hacks/Hotfixes", settings.emulator.hack.hotfixes);
|
||||
emulator->configure("Hacks/Entropy", settings.emulator.hack.entropy);
|
||||
emulator->configure("Hacks/CPU/Overclock", settings.emulator.hack.cpu.overclock);
|
||||
emulator->configure("Hacks/CPU/FastMath", settings.emulator.hack.cpu.fastMath);
|
||||
emulator->configure("Hacks/PPU/Fast", settings.emulator.hack.ppu.fast);
|
||||
emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace);
|
||||
emulator->configure("Hacks/PPU/NoSpriteLimit", settings.emulator.hack.ppu.noSpriteLimit);
|
||||
|
@ -115,14 +117,13 @@ auto Program::loadSuperFamicom(string location) -> bool {
|
|||
}
|
||||
if(rom.size() < 0x8000) return false;
|
||||
|
||||
//assume ROM and IPS agree on whether a copier header is present
|
||||
superFamicom.patched = applyPatchIPS(rom, location);
|
||||
if((rom.size() & 0x7fff) == 512) {
|
||||
//remove copier header
|
||||
memory::move(&rom[0], &rom[512], rom.size() - 512);
|
||||
rom.resize(rom.size() - 512);
|
||||
}
|
||||
//assume BPS is made against a ROM without a copier header
|
||||
|
||||
if(!superFamicom.patched) superFamicom.patched = applyPatchIPS(rom, location);
|
||||
if(!superFamicom.patched) superFamicom.patched = applyPatchBPS(rom, location);
|
||||
auto heuristics = Heuristics::SuperFamicom(rom, location);
|
||||
auto sha256 = Hash::SHA256(rom).digest();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
auto Program::hackCompatibility() -> void {
|
||||
bool fastPPU = emulatorSettings.fastPPU.checked();
|
||||
bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked();
|
||||
bool fastDSP = emulatorSettings.fastDSP.checked();
|
||||
bool coprocessorDelayedSync = emulatorSettings.coprocessorDelayedSyncOption.checked();
|
||||
bool fastPPU = settings.emulator.hack.ppu.fast;
|
||||
bool fastPPUNoSpriteLimit = settings.emulator.hack.ppu.noSpriteLimit;
|
||||
bool fastDSP = settings.emulator.hack.dsp.fast;
|
||||
bool coprocessorDelayedSync = settings.emulator.hack.coprocessor.delayedSync;
|
||||
uint renderCycle = 512;
|
||||
|
||||
auto title = superFamicom.title;
|
||||
|
|
|
@ -29,6 +29,15 @@ auto Program::applyPatchIPS(vector<uint8_t>& data, string location) -> bool {
|
|||
}
|
||||
if(!patch) return false;
|
||||
|
||||
bool headered = false;
|
||||
if(MessageDialog().setAlignment(*presentation).setTitle({Location::prefix(location), ".ips"}).setText({
|
||||
"(You're seeing this prompt because IPS is a terrible patch file format,\n"
|
||||
" and nobody can agree on whether SNES ROMs should be headered or not.\n"
|
||||
" Please consider asking the patch author to use BPS patches instead.)\n\n"
|
||||
"Does this IPS patch expect to be applied to a headered ROM?\n"
|
||||
"If you're not sure, try 'No', and if it fails to work, try again with 'Yes'."
|
||||
}).question() == "Yes") headered = true;
|
||||
|
||||
//sanity checks
|
||||
if(patch.size() < 8) return false;
|
||||
if(patch[0] != 'P') return false;
|
||||
|
@ -57,10 +66,12 @@ auto Program::applyPatchIPS(vector<uint8_t>& data, string location) -> bool {
|
|||
|
||||
if(index >= patch.size()) break;
|
||||
|
||||
uint32_t offset = 0;
|
||||
int32_t offset = 0;
|
||||
offset |= patch(index++, 0) << 16;
|
||||
offset |= patch(index++, 0) << 8;
|
||||
offset |= patch(index++, 0) << 0;
|
||||
if(headered) offset -= 512;
|
||||
if(offset < 0 || offset > 16_MiB) return false; //sanity check
|
||||
|
||||
uint16_t length = 0;
|
||||
length |= patch(index++, 0) << 8;
|
||||
|
|
|
@ -30,8 +30,9 @@ auto Program::create() -> void {
|
|||
inputSettings.create();
|
||||
hotkeySettings.create();
|
||||
pathSettings.create();
|
||||
speedSettings.create();
|
||||
emulatorSettings.create();
|
||||
enhancementSettings.create();
|
||||
compatibilitySettings.create();
|
||||
driverSettings.create();
|
||||
|
||||
toolsWindow.create();
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
auto CompatibilitySettings::create() -> void {
|
||||
setCollapsible();
|
||||
setVisible(false);
|
||||
|
||||
entropyLabel.setText("Entropy (randomization)").setFont(Font().setBold());
|
||||
entropyNone.setText("None").setToolTip(
|
||||
"All memory and registers are initialized to constant values at startup.\n"
|
||||
"Use this for compatibility with very old demoscene homebrew games."
|
||||
).onActivate([&] {
|
||||
settings.emulator.hack.entropy = "None";
|
||||
});
|
||||
entropyLow.setText("Low").setToolTip(
|
||||
"All memory is randomized with repeating patterns, all registers are randomized at startup.\n"
|
||||
"Use this for the most accurate representation of a real SNES."
|
||||
).onActivate([&] {
|
||||
settings.emulator.hack.entropy = "Low";
|
||||
});
|
||||
entropyHigh.setText("High").setToolTip(
|
||||
"All memory and registers are randomized as much as possible.\n"
|
||||
"Use this when developing new SNES software to ensure maximum compatibility with real hardware."
|
||||
).onActivate([&] {
|
||||
settings.emulator.hack.entropy = "High";
|
||||
});
|
||||
if(settings.emulator.hack.entropy == "None") entropyNone.setChecked();
|
||||
if(settings.emulator.hack.entropy == "Low" ) entropyLow.setChecked();
|
||||
if(settings.emulator.hack.entropy == "High") entropyHigh.setChecked();
|
||||
|
||||
cpuLabel.setFont(Font().setBold()).setText("CPU (processor)");
|
||||
fastMath.setText("Fast math").setToolTip(
|
||||
"CPU multiplication and division take time to complete on a real SNES.\n"
|
||||
"Older emulators did not simulate these delays, and provided results immediately.\n"
|
||||
"Some older ROM hacks do not wait for math operations to complete and need this hack."
|
||||
).setChecked(settings.emulator.hack.cpu.fastMath).onToggle([&] {
|
||||
settings.emulator.hack.cpu.fastMath = fastMath.checked();
|
||||
emulator->configure("Hacks/CPU/FastMath", settings.emulator.hack.cpu.fastMath);
|
||||
});
|
||||
|
||||
ppuLabel.setFont(Font().setBold()).setText("PPU (video)");
|
||||
noVRAMBlocking.setText("No VRAM blocking").setToolTip(
|
||||
"This option emulates a bug in older releases of ZSNES and Snes9X where VRAM blocking was not emulated.\n"
|
||||
"A few older ROM hacks relied on this behavior, and will render graphics incorrectly if not enabled.\n"
|
||||
"Not only is this extremely inaccurate to real hardware, it also hurts the speed of the fast PPU.\n"
|
||||
"Do not enable this option unless you need to play a game that is incompatible with bsnes otherwise."
|
||||
).setChecked(settings.emulator.hack.ppu.noVRAMBlocking).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noVRAMBlocking = noVRAMBlocking.checked();
|
||||
emulator->configure("Hacks/PPU/NoVRAMBlocking", settings.emulator.hack.ppu.noVRAMBlocking);
|
||||
});
|
||||
|
||||
dspLabel.setFont(Font().setBold()).setText("DSP (audio)");
|
||||
echoShadow.setText("Echo shadow RAM").setToolTip(
|
||||
"This option emulates a bug in ZSNES where echo RAM was treated as separate from APU RAM.\n"
|
||||
"Many older ROM hacks for Super Mario World relied on this behavior, and will crash without enabling this.\n"
|
||||
"It is, however, extremely inaccurate to real hardware and should not be enabled unless required."
|
||||
).setChecked(settings.emulator.hack.dsp.echoShadow).onToggle([&] {
|
||||
settings.emulator.hack.dsp.echoShadow = echoShadow.checked();
|
||||
//not a run-time setting: do not call emulator->configure() here.
|
||||
});
|
||||
|
||||
note.setText("Note: some settings do not take effect until after reloading games.");
|
||||
}
|
|
@ -22,114 +22,107 @@ auto EmulatorSettings::create() -> void {
|
|||
});
|
||||
optionsSpacer.setColor({192, 192, 192});
|
||||
|
||||
entropyLabel.setText("Entropy (randomness)").setFont(Font().setBold());
|
||||
entropyNone.setText("None").setToolTip(
|
||||
"All memory and registers are initialized to constant values at startup.\n"
|
||||
"Use this for compatibility with very old demoscene homebrew games."
|
||||
).onActivate([&] {
|
||||
settings.emulator.hack.entropy = "None";
|
||||
});
|
||||
entropyLow.setText("Low").setToolTip(
|
||||
"All memory is randomized with repeating patterns, all registers are randomized at startup.\n"
|
||||
"Use this for the most accurate representation of a real SNES."
|
||||
).onActivate([&] {
|
||||
settings.emulator.hack.entropy = "Low";
|
||||
});
|
||||
entropyHigh.setText("High").setToolTip(
|
||||
"All memory and registers are randomized as much as possible.\n"
|
||||
"Use this when developing new SNES software to ensure maximum compatibility with real hardware."
|
||||
).onActivate([&] {
|
||||
settings.emulator.hack.entropy = "High";
|
||||
});
|
||||
if(settings.emulator.hack.entropy == "None") entropyNone.setChecked();
|
||||
if(settings.emulator.hack.entropy == "Low") entropyLow.setChecked();
|
||||
if(settings.emulator.hack.entropy == "High") entropyHigh.setChecked();
|
||||
fastForwardLabel.setText("Fast Forward").setFont(Font().setBold());
|
||||
|
||||
ppuLabel.setText("PPU (video)").setFont(Font().setBold());
|
||||
fastPPU.setText("Fast mode").setChecked(settings.emulator.hack.ppu.fast).onToggle([&] {
|
||||
settings.emulator.hack.ppu.fast = fastPPU.checked();
|
||||
if(!fastPPU.checked()) {
|
||||
noSpriteLimit.setEnabled(false);
|
||||
deinterlace.setEnabled(false);
|
||||
mode7Layout.setEnabled(false);
|
||||
} else {
|
||||
noSpriteLimit.setEnabled(true);
|
||||
deinterlace.setEnabled(true);
|
||||
mode7Layout.setEnabled(true);
|
||||
}
|
||||
}).doToggle();
|
||||
deinterlace.setText("Deinterlace").setChecked(settings.emulator.hack.ppu.deinterlace).onToggle([&] {
|
||||
settings.emulator.hack.ppu.deinterlace = deinterlace.checked();
|
||||
emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace);
|
||||
frameSkipLabel.setText("Frame skip:").setToolTip({
|
||||
"Set how many frames to skip while fast forwarding.\n"
|
||||
"Frame skipping allows a higher maximum fast forwarding frame rate."
|
||||
});
|
||||
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked();
|
||||
|
||||
frameSkipAmount.append(ComboButtonItem().setText("None"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("1 frame"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("2 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("3 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("4 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("5 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("6 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("7 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("8 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("9 frames"));
|
||||
frameSkipAmount.item(settings.fastForward.frameSkip).setSelected();
|
||||
frameSkipAmount.onChange([&] {
|
||||
settings.fastForward.frameSkip = frameSkipAmount.selected().offset();
|
||||
});
|
||||
noVRAMBlocking.setText("No VRAM blocking").setToolTip(
|
||||
"This option emulates a bug in older releases of ZSNES and Snes9X where VRAM blocking was not emulated.\n"
|
||||
"A few older ROM hacks relied on this behavior, and will render graphics incorrectly if not enabled.\n"
|
||||
"Not only is this extremely inaccurate to real hardware, it also hurts the speed of the fast PPU.\n"
|
||||
"Do not enable this option unless you need to play a game that is incompatible with bsnes otherwise."
|
||||
).setChecked(settings.emulator.hack.ppu.noVRAMBlocking).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noVRAMBlocking = noVRAMBlocking.checked();
|
||||
emulator->configure("Hacks/PPU/NoVRAMBlocking", settings.emulator.hack.ppu.noVRAMBlocking);
|
||||
|
||||
limiterLabel.setText("Limiter:").setToolTip({
|
||||
"Set the maximum speed when fast forwarding."
|
||||
});
|
||||
mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold());
|
||||
mode7ScaleLabel.setText("Scale:");
|
||||
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1));
|
||||
mode7Scale.append(ComboButtonItem().setText( "480p").setProperty("multiplier", 2));
|
||||
mode7Scale.append(ComboButtonItem().setText( "720p").setProperty("multiplier", 3));
|
||||
mode7Scale.append(ComboButtonItem().setText( "960p").setProperty("multiplier", 4));
|
||||
mode7Scale.append(ComboButtonItem().setText("1200p").setProperty("multiplier", 5));
|
||||
mode7Scale.append(ComboButtonItem().setText("1440p").setProperty("multiplier", 6));
|
||||
mode7Scale.append(ComboButtonItem().setText("1680p").setProperty("multiplier", 7));
|
||||
mode7Scale.append(ComboButtonItem().setText("1920p").setProperty("multiplier", 8));
|
||||
mode7Scale.append(ComboButtonItem().setText("2160p").setProperty("multiplier", 9));
|
||||
for(uint n = 1; n <= 9; n++) {
|
||||
if(settings.emulator.hack.ppu.mode7.scale == n) mode7Scale.item(n - 1).setSelected();
|
||||
}
|
||||
mode7Scale.onChange([&] {
|
||||
settings.emulator.hack.ppu.mode7.scale = mode7Scale.selected().property("multiplier").natural();
|
||||
emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale);
|
||||
|
||||
limiterAmount.append(ComboButtonItem().setText("None"));
|
||||
limiterAmount.append(ComboButtonItem().setText("200%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("300%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("400%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("500%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("600%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("700%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("800%"));
|
||||
if(settings.fastForward.limiter == 0) limiterAmount.item(0).setSelected();
|
||||
if(settings.fastForward.limiter == 2) limiterAmount.item(1).setSelected();
|
||||
if(settings.fastForward.limiter == 3) limiterAmount.item(2).setSelected();
|
||||
if(settings.fastForward.limiter == 4) limiterAmount.item(3).setSelected();
|
||||
if(settings.fastForward.limiter == 5) limiterAmount.item(4).setSelected();
|
||||
if(settings.fastForward.limiter == 6) limiterAmount.item(5).setSelected();
|
||||
if(settings.fastForward.limiter == 7) limiterAmount.item(6).setSelected();
|
||||
if(settings.fastForward.limiter == 8) limiterAmount.item(7).setSelected();
|
||||
limiterAmount.onChange([&] {
|
||||
auto index = limiterAmount.selected().offset();
|
||||
if(index == 0) settings.fastForward.limiter = 0;
|
||||
if(index == 1) settings.fastForward.limiter = 2;
|
||||
if(index == 2) settings.fastForward.limiter = 3;
|
||||
if(index == 3) settings.fastForward.limiter = 4;
|
||||
if(index == 4) settings.fastForward.limiter = 5;
|
||||
if(index == 5) settings.fastForward.limiter = 6;
|
||||
if(index == 6) settings.fastForward.limiter = 7;
|
||||
if(index == 7) settings.fastForward.limiter = 8;
|
||||
});
|
||||
mode7Perspective.setText("Perspective correction").setChecked(settings.emulator.hack.ppu.mode7.perspective).onToggle([&] {
|
||||
settings.emulator.hack.ppu.mode7.perspective = mode7Perspective.checked();
|
||||
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
|
||||
|
||||
fastForwardMute.setText("Mute while fast forwarding").setChecked(settings.fastForward.mute).onToggle([&] {
|
||||
settings.fastForward.mute = fastForwardMute.checked();
|
||||
});
|
||||
mode7Supersample.setText("Supersampling").setChecked(settings.emulator.hack.ppu.mode7.supersample).onToggle([&] {
|
||||
settings.emulator.hack.ppu.mode7.supersample = mode7Supersample.checked();
|
||||
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
|
||||
|
||||
fastForwardSpacer.setColor({192, 192, 192});
|
||||
|
||||
rewindLabel.setText("Rewind").setFont(Font().setBold());
|
||||
|
||||
rewindFrequencyLabel.setText("Frequency:");
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Disabled"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 10 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 20 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 30 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 40 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 50 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 60 frames"));
|
||||
if(settings.rewind.frequency == 0) rewindFrequencyOption.item(0).setSelected();
|
||||
if(settings.rewind.frequency == 10) rewindFrequencyOption.item(1).setSelected();
|
||||
if(settings.rewind.frequency == 20) rewindFrequencyOption.item(2).setSelected();
|
||||
if(settings.rewind.frequency == 30) rewindFrequencyOption.item(3).setSelected();
|
||||
if(settings.rewind.frequency == 40) rewindFrequencyOption.item(4).setSelected();
|
||||
if(settings.rewind.frequency == 50) rewindFrequencyOption.item(5).setSelected();
|
||||
if(settings.rewind.frequency == 60) rewindFrequencyOption.item(6).setSelected();
|
||||
rewindFrequencyOption.onChange([&] {
|
||||
settings.rewind.frequency = rewindFrequencyOption.selected().offset() * 10;
|
||||
program.rewindReset();
|
||||
});
|
||||
mode7Mosaic.setText("HD->SD Mosaic").setChecked(settings.emulator.hack.ppu.mode7.mosaic).onToggle([&] {
|
||||
settings.emulator.hack.ppu.mode7.mosaic = mode7Mosaic.checked();
|
||||
emulator->configure("Hacks/PPU/Mode7/Mosaic", settings.emulator.hack.ppu.mode7.mosaic);
|
||||
|
||||
rewindLengthLabel.setText("Length:");
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "10 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "20 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "40 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "80 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText("160 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText("320 states"));
|
||||
if(settings.rewind.length == 10) rewindLengthOption.item(0).setSelected();
|
||||
if(settings.rewind.length == 20) rewindLengthOption.item(1).setSelected();
|
||||
if(settings.rewind.length == 40) rewindLengthOption.item(2).setSelected();
|
||||
if(settings.rewind.length == 80) rewindLengthOption.item(3).setSelected();
|
||||
if(settings.rewind.length == 160) rewindLengthOption.item(4).setSelected();
|
||||
if(settings.rewind.length == 320) rewindLengthOption.item(5).setSelected();
|
||||
rewindLengthOption.onChange([&] {
|
||||
settings.rewind.length = 10 << rewindLengthOption.selected().offset();
|
||||
program.rewindReset();
|
||||
});
|
||||
dspLabel.setText("DSP (audio)").setFont(Font().setBold());
|
||||
fastDSP.setText("Fast mode").setChecked(settings.emulator.hack.dsp.fast).onToggle([&] {
|
||||
settings.emulator.hack.dsp.fast = fastDSP.checked();
|
||||
emulator->configure("Hacks/DSP/Fast", settings.emulator.hack.dsp.fast);
|
||||
|
||||
rewindMute.setText("Mute while rewinding").setChecked(settings.rewind.mute).onToggle([&] {
|
||||
settings.rewind.mute = rewindMute.checked();
|
||||
});
|
||||
cubicInterpolation.setText("Cubic interpolation").setChecked(settings.emulator.hack.dsp.cubic).onToggle([&] {
|
||||
settings.emulator.hack.dsp.cubic = cubicInterpolation.checked();
|
||||
emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic);
|
||||
});
|
||||
echoShadow.setText("Echo shadow RAM").setToolTip(
|
||||
"This option emulates a bug in ZSNES where echo RAM was treated as separate from APU RAM.\n"
|
||||
"Many older ROM hacks for Super Mario World relied on this behavior, and will crash without enabling this.\n"
|
||||
"It is, however, extremely inaccurate to real hardware and should not be enabled unless required."
|
||||
).setChecked(settings.emulator.hack.dsp.echoShadow).onToggle([&] {
|
||||
settings.emulator.hack.dsp.echoShadow = echoShadow.checked();
|
||||
//not a run-time setting: do not call emulator->configure() here.
|
||||
});
|
||||
coprocessorLabel.setText("Coprocessors").setFont(Font().setBold());
|
||||
coprocessorDelayedSyncOption.setText("Fast mode").setChecked(settings.emulator.hack.coprocessor.delayedSync).onToggle([&] {
|
||||
settings.emulator.hack.coprocessor.delayedSync = coprocessorDelayedSyncOption.checked();
|
||||
});
|
||||
coprocessorPreferHLEOption.setText("Prefer HLE").setChecked(settings.emulator.hack.coprocessor.preferHLE).setToolTip(
|
||||
"When checked, less accurate HLE emulation will always be used when available.\n"
|
||||
"When unchecked, HLE will only be used when LLE firmware is missing."
|
||||
).onToggle([&] {
|
||||
settings.emulator.hack.coprocessor.preferHLE = coprocessorPreferHLEOption.checked();
|
||||
});
|
||||
hacksNote.setText("Note: some hack setting changes do not take effect until after reloading games.");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
auto EnhancementSettings::create() -> void {
|
||||
setCollapsible();
|
||||
setVisible(false);
|
||||
|
||||
overclockingLabel.setText("Overclocking").setFont(Font().setBold());
|
||||
|
||||
overclockingLayout.setSize({3, 3});
|
||||
overclockingLayout.column(0).setAlignment(1.0);
|
||||
overclockingLayout.column(1).setAlignment(0.5);
|
||||
|
||||
cpuLabel.setText("CPU:");
|
||||
cpuClock.setLength(301).setPosition((settings.emulator.hack.cpu.overclock - 100)).onChange([&] {
|
||||
settings.emulator.hack.cpu.overclock = cpuClock.position() + 100;
|
||||
emulator->configure("Hacks/CPU/Overclock", settings.emulator.hack.cpu.overclock);
|
||||
cpuValue.setText({settings.emulator.hack.cpu.overclock, "%"});
|
||||
}).doChange();
|
||||
|
||||
sa1Label.setText("SA-1:");
|
||||
sa1Clock.setLength(301).setPosition((settings.emulator.hack.sa1.overclock - 100)).onChange([&] {
|
||||
settings.emulator.hack.sa1.overclock = sa1Clock.position() + 100;
|
||||
emulator->configure("Hacks/SA1/Overclock", settings.emulator.hack.sa1.overclock);
|
||||
sa1Value.setText({settings.emulator.hack.sa1.overclock, "%"});
|
||||
}).doChange();
|
||||
|
||||
sfxLabel.setText("SuperFX:");
|
||||
sfxClock.setLength(141).setPosition((settings.emulator.hack.superfx.overclock - 100) / 5).onChange([&] {
|
||||
settings.emulator.hack.superfx.overclock = sfxClock.position() * 5 + 100;
|
||||
emulator->configure("Hacks/SuperFX/Overclock", settings.emulator.hack.superfx.overclock);
|
||||
sfxValue.setText({settings.emulator.hack.superfx.overclock, "%"});
|
||||
}).doChange();
|
||||
|
||||
overclockingSpacer.setColor({192, 192, 192});
|
||||
|
||||
ppuLabel.setText("PPU (video)").setFont(Font().setBold());
|
||||
fastPPU.setText("Fast mode").setChecked(settings.emulator.hack.ppu.fast).onToggle([&] {
|
||||
settings.emulator.hack.ppu.fast = fastPPU.checked();
|
||||
if(!fastPPU.checked()) {
|
||||
noSpriteLimit.setEnabled(false);
|
||||
deinterlace.setEnabled(false);
|
||||
mode7Layout.setEnabled(false);
|
||||
} else {
|
||||
noSpriteLimit.setEnabled(true);
|
||||
deinterlace.setEnabled(true);
|
||||
mode7Layout.setEnabled(true);
|
||||
}
|
||||
}).doToggle();
|
||||
deinterlace.setText("Deinterlace").setChecked(settings.emulator.hack.ppu.deinterlace).onToggle([&] {
|
||||
settings.emulator.hack.ppu.deinterlace = deinterlace.checked();
|
||||
emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace);
|
||||
});
|
||||
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked();
|
||||
});
|
||||
|
||||
mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold());
|
||||
mode7ScaleLabel.setText("Scale:");
|
||||
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1));
|
||||
mode7Scale.append(ComboButtonItem().setText( "480p").setProperty("multiplier", 2));
|
||||
mode7Scale.append(ComboButtonItem().setText( "720p").setProperty("multiplier", 3));
|
||||
mode7Scale.append(ComboButtonItem().setText( "960p").setProperty("multiplier", 4));
|
||||
mode7Scale.append(ComboButtonItem().setText("1200p").setProperty("multiplier", 5));
|
||||
mode7Scale.append(ComboButtonItem().setText("1440p").setProperty("multiplier", 6));
|
||||
mode7Scale.append(ComboButtonItem().setText("1680p").setProperty("multiplier", 7));
|
||||
mode7Scale.append(ComboButtonItem().setText("1920p").setProperty("multiplier", 8));
|
||||
mode7Scale.append(ComboButtonItem().setText("2160p").setProperty("multiplier", 9));
|
||||
for(uint n = 1; n <= 9; n++) {
|
||||
if(settings.emulator.hack.ppu.mode7.scale == n) mode7Scale.item(n - 1).setSelected();
|
||||
}
|
||||
mode7Scale.onChange([&] {
|
||||
settings.emulator.hack.ppu.mode7.scale = mode7Scale.selected().property("multiplier").natural();
|
||||
emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale);
|
||||
});
|
||||
mode7Perspective.setText("Perspective correction").setChecked(settings.emulator.hack.ppu.mode7.perspective).onToggle([&] {
|
||||
settings.emulator.hack.ppu.mode7.perspective = mode7Perspective.checked();
|
||||
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
|
||||
});
|
||||
mode7Supersample.setText("Supersampling").setChecked(settings.emulator.hack.ppu.mode7.supersample).onToggle([&] {
|
||||
settings.emulator.hack.ppu.mode7.supersample = mode7Supersample.checked();
|
||||
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
|
||||
});
|
||||
mode7Mosaic.setText("HD->SD Mosaic").setChecked(settings.emulator.hack.ppu.mode7.mosaic).onToggle([&] {
|
||||
settings.emulator.hack.ppu.mode7.mosaic = mode7Mosaic.checked();
|
||||
emulator->configure("Hacks/PPU/Mode7/Mosaic", settings.emulator.hack.ppu.mode7.mosaic);
|
||||
});
|
||||
|
||||
dspLabel.setText("DSP (audio)").setFont(Font().setBold());
|
||||
fastDSP.setText("Fast mode").setChecked(settings.emulator.hack.dsp.fast).onToggle([&] {
|
||||
settings.emulator.hack.dsp.fast = fastDSP.checked();
|
||||
emulator->configure("Hacks/DSP/Fast", settings.emulator.hack.dsp.fast);
|
||||
});
|
||||
cubicInterpolation.setText("Cubic interpolation").setChecked(settings.emulator.hack.dsp.cubic).onToggle([&] {
|
||||
settings.emulator.hack.dsp.cubic = cubicInterpolation.checked();
|
||||
emulator->configure("Hacks/DSP/Cubic", settings.emulator.hack.dsp.cubic);
|
||||
});
|
||||
|
||||
coprocessorLabel.setText("Coprocessors").setFont(Font().setBold());
|
||||
coprocessorDelayedSyncOption.setText("Fast mode").setChecked(settings.emulator.hack.coprocessor.delayedSync).onToggle([&] {
|
||||
settings.emulator.hack.coprocessor.delayedSync = coprocessorDelayedSyncOption.checked();
|
||||
});
|
||||
coprocessorPreferHLEOption.setText("Prefer HLE").setChecked(settings.emulator.hack.coprocessor.preferHLE).setToolTip(
|
||||
"When checked, less accurate HLE emulation will always be used when available.\n"
|
||||
"When unchecked, HLE will only be used when LLE firmware is missing."
|
||||
).onToggle([&] {
|
||||
settings.emulator.hack.coprocessor.preferHLE = coprocessorPreferHLEOption.checked();
|
||||
});
|
||||
coprocessorSpacer.setColor({192, 192, 192});
|
||||
|
||||
gameLabel.setText("Game Enhancements").setFont(Font().setBold());
|
||||
hotfixes.setText("Hotfixes").setToolTip({
|
||||
"Even commercially licensed and officially released software sometimes shipped with bugs.\n"
|
||||
"This option will correct certain issues that occurred even on real hardware."
|
||||
}).setChecked(settings.emulator.hack.hotfixes).onToggle([&] {
|
||||
settings.emulator.hack.hotfixes = hotfixes.checked();
|
||||
});
|
||||
|
||||
note.setText("Note: some settings do not take effect until after reloading games.");
|
||||
}
|
|
@ -4,8 +4,9 @@
|
|||
#include "input.cpp"
|
||||
#include "hotkeys.cpp"
|
||||
#include "paths.cpp"
|
||||
#include "speed.cpp"
|
||||
#include "emulator.cpp"
|
||||
#include "enhancements.cpp"
|
||||
#include "compatibility.cpp"
|
||||
#include "drivers.cpp"
|
||||
Settings settings;
|
||||
VideoSettings videoSettings;
|
||||
|
@ -13,8 +14,9 @@ AudioSettings audioSettings;
|
|||
InputSettings inputSettings;
|
||||
HotkeySettings hotkeySettings;
|
||||
PathSettings pathSettings;
|
||||
SpeedSettings speedSettings;
|
||||
EmulatorSettings emulatorSettings;
|
||||
EnhancementSettings enhancementSettings;
|
||||
CompatibilitySettings compatibilitySettings;
|
||||
DriverSettings driverSettings;
|
||||
namespace Instances { Instance<SettingsWindow> settingsWindow; }
|
||||
SettingsWindow& settingsWindow = Instances::settingsWindow();
|
||||
|
@ -112,8 +114,10 @@ auto Settings::process(bool load) -> void {
|
|||
bind(natural, "Emulator/AutoSaveMemory/Interval", emulator.autoSaveMemory.interval);
|
||||
bind(boolean, "Emulator/AutoSaveStateOnUnload", emulator.autoSaveStateOnUnload);
|
||||
bind(boolean, "Emulator/AutoLoadStateOnLoad", emulator.autoLoadStateOnLoad);
|
||||
bind(boolean, "Emulator/Hack/Hotfixes", emulator.hack.hotfixes);
|
||||
bind(text, "Emulator/Hack/Entropy", emulator.hack.entropy);
|
||||
bind(natural, "Emulator/Hack/CPU/Overclock", emulator.hack.cpu.overclock);
|
||||
bind(boolean, "Emulator/Hack/CPU/FastMath", emulator.hack.cpu.fastMath);
|
||||
bind(boolean, "Emulator/Hack/PPU/Fast", emulator.hack.ppu.fast);
|
||||
bind(boolean, "Emulator/Hack/PPU/Deinterlace", emulator.hack.ppu.deinterlace);
|
||||
bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit);
|
||||
|
@ -172,8 +176,9 @@ auto SettingsWindow::create() -> void {
|
|||
panelList.append(ListViewItem().setText("Input").setIcon(Icon::Device::Joypad));
|
||||
panelList.append(ListViewItem().setText("Hotkeys").setIcon(Icon::Device::Keyboard));
|
||||
panelList.append(ListViewItem().setText("Paths").setIcon(Icon::Emblem::Folder));
|
||||
panelList.append(ListViewItem().setText("Speed").setIcon(Icon::Device::Clock));
|
||||
panelList.append(ListViewItem().setText("Emulator").setIcon(Icon::Action::Settings));
|
||||
panelList.append(ListViewItem().setText("Enhancements").setIcon(Icon::Action::Add));
|
||||
panelList.append(ListViewItem().setText("Compatibility").setIcon(Icon::Action::Remove));
|
||||
panelList.append(ListViewItem().setText("Drivers").setIcon(Icon::Place::Settings));
|
||||
panelList.onChange([&] {
|
||||
if(auto item = panelList.selected()) {
|
||||
|
@ -188,13 +193,14 @@ auto SettingsWindow::create() -> void {
|
|||
panelContainer.append(inputSettings, Size{~0, ~0});
|
||||
panelContainer.append(hotkeySettings, Size{~0, ~0});
|
||||
panelContainer.append(pathSettings, Size{~0, ~0});
|
||||
panelContainer.append(speedSettings, Size{~0, ~0});
|
||||
panelContainer.append(emulatorSettings, Size{~0, ~0});
|
||||
panelContainer.append(enhancementSettings, Size{~0, ~0});
|
||||
panelContainer.append(compatibilitySettings, Size{~0, ~0});
|
||||
panelContainer.append(driverSettings, Size{~0, ~0});
|
||||
statusBar.setFont(Font().setBold());
|
||||
|
||||
setTitle("Settings");
|
||||
setSize({680_sx, 400_sx});
|
||||
setSize({680_sx, 400_sy});
|
||||
setAlignment({0.0, 1.0});
|
||||
setDismissable();
|
||||
|
||||
|
@ -221,8 +227,9 @@ auto SettingsWindow::show(int index) -> void {
|
|||
inputSettings.setVisible(false);
|
||||
hotkeySettings.setVisible(false);
|
||||
pathSettings.setVisible(false);
|
||||
speedSettings.setVisible(false);
|
||||
emulatorSettings.setVisible(false);
|
||||
enhancementSettings.setVisible(false);
|
||||
compatibilitySettings.setVisible(false);
|
||||
driverSettings.setVisible(false);
|
||||
panelList.item(index).setSelected();
|
||||
if(index ==-1) settingsHome.setVisible(true);
|
||||
|
@ -231,9 +238,10 @@ auto SettingsWindow::show(int index) -> void {
|
|||
if(index == 2) inputSettings.setVisible(true);
|
||||
if(index == 3) hotkeySettings.setVisible(true);
|
||||
if(index == 4) pathSettings.setVisible(true);
|
||||
if(index == 5) speedSettings.setVisible(true);
|
||||
if(index == 6) emulatorSettings.setVisible(true);
|
||||
if(index == 7) driverSettings.setVisible(true);
|
||||
if(index == 5) emulatorSettings.setVisible(true);
|
||||
if(index == 6) enhancementSettings.setVisible(true);
|
||||
if(index == 7) compatibilitySettings.setVisible(true);
|
||||
if(index == 8) driverSettings.setVisible(true);
|
||||
panelContainer.resize();
|
||||
setVisible();
|
||||
setFocused();
|
||||
|
|
|
@ -95,9 +95,11 @@ struct Settings : Markup::Node {
|
|||
bool autoSaveStateOnUnload = false;
|
||||
bool autoLoadStateOnLoad = false;
|
||||
struct Hack {
|
||||
bool hotfixes = true;
|
||||
string entropy = "Low";
|
||||
struct CPU {
|
||||
uint overclock = 100;
|
||||
bool fastMath = false;
|
||||
} cpu;
|
||||
struct PPU {
|
||||
bool fast = true;
|
||||
|
@ -290,39 +292,6 @@ public:
|
|||
Button screenshotsReset{&layout, Size{80_sx, 0}};
|
||||
};
|
||||
|
||||
struct SpeedSettings : VerticalLayout {
|
||||
auto create() -> void;
|
||||
|
||||
public:
|
||||
Label overclockingLabel{this, Size{~0, 0}, 2};
|
||||
TableLayout overclockingLayout{this, Size{~0, 0}};
|
||||
Label cpuLabel{&overclockingLayout, Size{0, 0}};
|
||||
Label cpuValue{&overclockingLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider cpuClock{&overclockingLayout, Size{~0, 0}};
|
||||
//
|
||||
Label sa1Label{&overclockingLayout, Size{0, 0}};
|
||||
Label sa1Value{&overclockingLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider sa1Clock{&overclockingLayout, Size{~0, 0}};
|
||||
//
|
||||
Label sfxLabel{&overclockingLayout, Size{0, 0}};
|
||||
Label sfxValue{&overclockingLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider sfxClock{&overclockingLayout, Size{~0, 0}};
|
||||
Label fastForwardLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout fastForwardLayout{this, Size{~0, 0}};
|
||||
Label frameSkipLabel{&fastForwardLayout, Size{0, 0}};
|
||||
ComboButton frameSkipAmount{&fastForwardLayout, Size{0, 0}};
|
||||
Label limiterLabel{&fastForwardLayout, Size{0, 0}};
|
||||
ComboButton limiterAmount{&fastForwardLayout, Size{0, 0}};
|
||||
CheckLabel fastForwardMute{this, Size{0, 0}};
|
||||
Label rewindLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout rewindLayout{this, Size{~0, 0}};
|
||||
Label rewindFrequencyLabel{&rewindLayout, Size{0, 0}};
|
||||
ComboButton rewindFrequencyOption{&rewindLayout, Size{0, 0}};
|
||||
Label rewindLengthLabel{&rewindLayout, Size{0, 0}};
|
||||
ComboButton rewindLengthOption{&rewindLayout, Size{0, 0}};
|
||||
CheckLabel rewindMute{this, Size{0, 0}};
|
||||
};
|
||||
|
||||
struct EmulatorSettings : VerticalLayout {
|
||||
auto create() -> void;
|
||||
|
||||
|
@ -334,18 +303,50 @@ public:
|
|||
CheckLabel autoSaveStateOnUnload{&autoStateLayout, Size{0, 0}};
|
||||
CheckLabel autoLoadStateOnLoad{&autoStateLayout, Size{0, 0}};
|
||||
Canvas optionsSpacer{this, Size{~0, 1}};
|
||||
Label entropyLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout entropyLayout{this, Size{~0, 0}};
|
||||
RadioLabel entropyNone{&entropyLayout, Size{0, 0}};
|
||||
RadioLabel entropyLow{&entropyLayout, Size{0, 0}};
|
||||
RadioLabel entropyHigh{&entropyLayout, Size{0, 0}};
|
||||
Group entropyGroup{&entropyNone, &entropyLow, &entropyHigh};
|
||||
//
|
||||
Label fastForwardLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout fastForwardLayout{this, Size{~0, 0}};
|
||||
Label frameSkipLabel{&fastForwardLayout, Size{0, 0}};
|
||||
ComboButton frameSkipAmount{&fastForwardLayout, Size{0, 0}};
|
||||
Label limiterLabel{&fastForwardLayout, Size{0, 0}};
|
||||
ComboButton limiterAmount{&fastForwardLayout, Size{0, 0}};
|
||||
CheckLabel fastForwardMute{this, Size{0, 0}};
|
||||
Canvas fastForwardSpacer{this, Size{~0, 1}};
|
||||
//
|
||||
Label rewindLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout rewindLayout{this, Size{~0, 0}};
|
||||
Label rewindFrequencyLabel{&rewindLayout, Size{0, 0}};
|
||||
ComboButton rewindFrequencyOption{&rewindLayout, Size{0, 0}};
|
||||
Label rewindLengthLabel{&rewindLayout, Size{0, 0}};
|
||||
ComboButton rewindLengthOption{&rewindLayout, Size{0, 0}};
|
||||
CheckLabel rewindMute{this, Size{0, 0}};
|
||||
};
|
||||
|
||||
struct EnhancementSettings : VerticalLayout {
|
||||
auto create() -> void;
|
||||
|
||||
private:
|
||||
Label overclockingLabel{this, Size{~0, 0}, 2};
|
||||
TableLayout overclockingLayout{this, Size{~0, 0}};
|
||||
Label cpuLabel{&overclockingLayout, Size{0, 0}};
|
||||
Label cpuValue{&overclockingLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider cpuClock{&overclockingLayout, Size{~0, 0}};
|
||||
Canvas overclockingSpacer{this, Size{~0, 1}};
|
||||
//
|
||||
Label sa1Label{&overclockingLayout, Size{0, 0}};
|
||||
Label sa1Value{&overclockingLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider sa1Clock{&overclockingLayout, Size{~0, 0}};
|
||||
//
|
||||
Label sfxLabel{&overclockingLayout, Size{0, 0}};
|
||||
Label sfxValue{&overclockingLayout, Size{50_sx, 0}};
|
||||
HorizontalSlider sfxClock{&overclockingLayout, Size{~0, 0}};
|
||||
//
|
||||
Label ppuLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout ppuLayout{this, Size{~0, 0}};
|
||||
CheckLabel fastPPU{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel deinterlace{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel noVRAMBlocking{&ppuLayout, Size{0, 0}};
|
||||
//
|
||||
Label mode7Label{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout mode7Layout{this, Size{~0, 0}};
|
||||
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
|
||||
|
@ -353,16 +354,47 @@ public:
|
|||
CheckLabel mode7Perspective{&mode7Layout, Size{0, 0}};
|
||||
CheckLabel mode7Supersample{&mode7Layout, Size{0, 0}};
|
||||
CheckLabel mode7Mosaic{&mode7Layout, Size{0, 0}};
|
||||
//
|
||||
Label dspLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout dspLayout{this, Size{~0, 0}};
|
||||
CheckLabel fastDSP{&dspLayout, Size{0, 0}};
|
||||
CheckLabel cubicInterpolation{&dspLayout, Size{0, 0}};
|
||||
CheckLabel echoShadow{&dspLayout, Size{0, 0}};
|
||||
//
|
||||
Label coprocessorLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout coprocessorLayout{this, Size{~0, 0}};
|
||||
CheckLabel coprocessorDelayedSyncOption{&coprocessorLayout, Size{0, 0}};
|
||||
CheckLabel coprocessorPreferHLEOption{&coprocessorLayout, Size{0, 0}};
|
||||
Label hacksNote{this, Size{~0, 0}};
|
||||
Canvas coprocessorSpacer{this, Size{~0, 1}};
|
||||
//
|
||||
Label gameLabel{this, Size{~0, 0}, 2};
|
||||
CheckLabel hotfixes{this, Size{0, 0}};
|
||||
//
|
||||
Widget spacer{this, Size{~0, ~0}};
|
||||
Label note{this, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct CompatibilitySettings : VerticalLayout {
|
||||
auto create() -> void;
|
||||
|
||||
private:
|
||||
Label entropyLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout entropyLayout{this, Size{~0, 0}};
|
||||
RadioLabel entropyNone{&entropyLayout, Size{0, 0}};
|
||||
RadioLabel entropyLow{&entropyLayout, Size{0, 0}};
|
||||
RadioLabel entropyHigh{&entropyLayout, Size{0, 0}};
|
||||
Group entropyGroup{&entropyNone, &entropyLow, &entropyHigh};
|
||||
//
|
||||
Label cpuLabel{this, Size{~0, 0}, 2};
|
||||
CheckLabel fastMath{this, Size{0, 0}};
|
||||
//
|
||||
Label ppuLabel{this, Size{~0, 0}, 2};
|
||||
CheckLabel noVRAMBlocking{this, Size{0, 0}};
|
||||
//
|
||||
Label dspLabel{this, Size{~0, 0}, 2};
|
||||
CheckLabel echoShadow{this, Size{0, 0}};
|
||||
//
|
||||
Widget spacer{this, Size{~0, ~0}};
|
||||
Label note{this, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct DriverSettings : VerticalLayout {
|
||||
|
@ -402,6 +434,7 @@ public:
|
|||
CheckLabel videoBlockingToggle{&videoToggleLayout, Size{0, 0}};
|
||||
CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}};
|
||||
Canvas videoSpacer{this, Size{~0, 1}};
|
||||
//
|
||||
Label audioLabel{this, Size{~0, 0}, 2};
|
||||
VerticalLayout audioLayout{this, Size{~0, 0}};
|
||||
HorizontalLayout audioDriverLayout{&audioLayout, Size{~0, 0}};
|
||||
|
@ -421,6 +454,7 @@ public:
|
|||
CheckLabel audioBlockingToggle{&audioToggleLayout, Size{0, 0}};
|
||||
CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}};
|
||||
Canvas audioSpacer{this, Size{~0, 1}};
|
||||
//
|
||||
Label inputLabel{this, Size{~0, 0}, 2};
|
||||
VerticalLayout inputLayout{this, Size{~0, 0}};
|
||||
HorizontalLayout inputDriverLayout{&inputLayout, Size{~0, 0}};
|
||||
|
@ -438,7 +472,7 @@ struct SettingsWindow : Window, Lock {
|
|||
public:
|
||||
VerticalLayout layout{this};
|
||||
HorizontalLayout panelLayout{&layout, Size{~0, ~0}};
|
||||
ListView panelList{&panelLayout, Size{120_sx, ~0}};
|
||||
ListView panelList{&panelLayout, Size{125_sx, ~0}};
|
||||
VerticalLayout panelContainer{&panelLayout, Size{~0, ~0}};
|
||||
StatusBar statusBar{this};
|
||||
};
|
||||
|
@ -449,8 +483,9 @@ extern AudioSettings audioSettings;
|
|||
extern InputSettings inputSettings;
|
||||
extern HotkeySettings hotkeySettings;
|
||||
extern PathSettings pathSettings;
|
||||
extern SpeedSettings speedSettings;
|
||||
extern EmulatorSettings emulatorSettings;
|
||||
extern EnhancementSettings enhancementSettings;
|
||||
extern CompatibilitySettings compatibilitySettings;
|
||||
extern DriverSettings driverSettings;
|
||||
namespace Instances { extern Instance<SettingsWindow> settingsWindow; }
|
||||
extern SettingsWindow& settingsWindow;
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
auto SpeedSettings::create() -> void {
|
||||
setCollapsible();
|
||||
setVisible(false);
|
||||
|
||||
overclockingLabel.setText("Overclocking").setFont(Font().setBold());
|
||||
|
||||
overclockingLayout.setSize({3, 3});
|
||||
overclockingLayout.column(0).setAlignment(1.0);
|
||||
overclockingLayout.column(1).setAlignment(0.5);
|
||||
|
||||
cpuLabel.setText("CPU:");
|
||||
cpuClock.setLength(301).setPosition((settings.emulator.hack.cpu.overclock - 100)).onChange([&] {
|
||||
settings.emulator.hack.cpu.overclock = cpuClock.position() + 100;
|
||||
emulator->configure("Hacks/CPU/Overclock", settings.emulator.hack.cpu.overclock);
|
||||
cpuValue.setText({settings.emulator.hack.cpu.overclock, "%"});
|
||||
}).doChange();
|
||||
|
||||
sa1Label.setText("SA-1:");
|
||||
sa1Clock.setLength(301).setPosition((settings.emulator.hack.sa1.overclock - 100)).onChange([&] {
|
||||
settings.emulator.hack.sa1.overclock = sa1Clock.position() + 100;
|
||||
emulator->configure("Hacks/SA1/Overclock", settings.emulator.hack.sa1.overclock);
|
||||
sa1Value.setText({settings.emulator.hack.sa1.overclock, "%"});
|
||||
}).doChange();
|
||||
|
||||
sfxLabel.setText("SuperFX:");
|
||||
sfxClock.setLength(141).setPosition((settings.emulator.hack.superfx.overclock - 100) / 5).onChange([&] {
|
||||
settings.emulator.hack.superfx.overclock = sfxClock.position() * 5 + 100;
|
||||
emulator->configure("Hacks/SuperFX/Overclock", settings.emulator.hack.superfx.overclock);
|
||||
sfxValue.setText({settings.emulator.hack.superfx.overclock, "%"});
|
||||
}).doChange();
|
||||
|
||||
fastForwardLabel.setText("Fast Forward").setFont(Font().setBold());
|
||||
|
||||
frameSkipLabel.setText("Frame skip:").setToolTip({
|
||||
"Set how many frames to skip while fast forwarding.\n"
|
||||
"Frame skipping allows a higher maximum fast forwarding frame rate."
|
||||
});
|
||||
|
||||
frameSkipAmount.append(ComboButtonItem().setText("None"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("1 frame"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("2 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("3 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("4 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("5 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("6 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("7 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("8 frames"));
|
||||
frameSkipAmount.append(ComboButtonItem().setText("9 frames"));
|
||||
frameSkipAmount.item(settings.fastForward.frameSkip).setSelected();
|
||||
frameSkipAmount.onChange([&] {
|
||||
settings.fastForward.frameSkip = frameSkipAmount.selected().offset();
|
||||
});
|
||||
|
||||
limiterLabel.setText("Limiter:").setToolTip({
|
||||
"Set the maximum speed when fast forwarding."
|
||||
});
|
||||
|
||||
limiterAmount.append(ComboButtonItem().setText("None"));
|
||||
limiterAmount.append(ComboButtonItem().setText("200%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("300%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("400%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("500%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("600%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("700%"));
|
||||
limiterAmount.append(ComboButtonItem().setText("800%"));
|
||||
if(settings.fastForward.limiter == 0) limiterAmount.item(0).setSelected();
|
||||
if(settings.fastForward.limiter == 2) limiterAmount.item(1).setSelected();
|
||||
if(settings.fastForward.limiter == 3) limiterAmount.item(2).setSelected();
|
||||
if(settings.fastForward.limiter == 4) limiterAmount.item(3).setSelected();
|
||||
if(settings.fastForward.limiter == 5) limiterAmount.item(4).setSelected();
|
||||
if(settings.fastForward.limiter == 6) limiterAmount.item(5).setSelected();
|
||||
if(settings.fastForward.limiter == 7) limiterAmount.item(6).setSelected();
|
||||
if(settings.fastForward.limiter == 8) limiterAmount.item(7).setSelected();
|
||||
limiterAmount.onChange([&] {
|
||||
auto index = limiterAmount.selected().offset();
|
||||
if(index == 0) settings.fastForward.limiter = 0;
|
||||
if(index == 1) settings.fastForward.limiter = 2;
|
||||
if(index == 2) settings.fastForward.limiter = 3;
|
||||
if(index == 3) settings.fastForward.limiter = 4;
|
||||
if(index == 4) settings.fastForward.limiter = 5;
|
||||
if(index == 5) settings.fastForward.limiter = 6;
|
||||
if(index == 6) settings.fastForward.limiter = 7;
|
||||
if(index == 7) settings.fastForward.limiter = 8;
|
||||
});
|
||||
|
||||
fastForwardMute.setText("Mute while fast forwarding").setChecked(settings.fastForward.mute).onToggle([&] {
|
||||
settings.fastForward.mute = fastForwardMute.checked();
|
||||
});
|
||||
|
||||
rewindLabel.setText("Rewind").setFont(Font().setBold());
|
||||
|
||||
rewindFrequencyLabel.setText("Frequency:");
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Disabled"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 10 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 20 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 30 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 40 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 50 frames"));
|
||||
rewindFrequencyOption.append(ComboButtonItem().setText("Every 60 frames"));
|
||||
if(settings.rewind.frequency == 0) rewindFrequencyOption.item(0).setSelected();
|
||||
if(settings.rewind.frequency == 10) rewindFrequencyOption.item(1).setSelected();
|
||||
if(settings.rewind.frequency == 20) rewindFrequencyOption.item(2).setSelected();
|
||||
if(settings.rewind.frequency == 30) rewindFrequencyOption.item(3).setSelected();
|
||||
if(settings.rewind.frequency == 40) rewindFrequencyOption.item(4).setSelected();
|
||||
if(settings.rewind.frequency == 50) rewindFrequencyOption.item(5).setSelected();
|
||||
if(settings.rewind.frequency == 60) rewindFrequencyOption.item(6).setSelected();
|
||||
rewindFrequencyOption.onChange([&] {
|
||||
settings.rewind.frequency = rewindFrequencyOption.selected().offset() * 10;
|
||||
program.rewindReset();
|
||||
});
|
||||
|
||||
rewindLengthLabel.setText("Length:");
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "10 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "20 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "40 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText( "80 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText("160 states"));
|
||||
rewindLengthOption.append(ComboButtonItem().setText("320 states"));
|
||||
if(settings.rewind.length == 10) rewindLengthOption.item(0).setSelected();
|
||||
if(settings.rewind.length == 20) rewindLengthOption.item(1).setSelected();
|
||||
if(settings.rewind.length == 40) rewindLengthOption.item(2).setSelected();
|
||||
if(settings.rewind.length == 80) rewindLengthOption.item(3).setSelected();
|
||||
if(settings.rewind.length == 160) rewindLengthOption.item(4).setSelected();
|
||||
if(settings.rewind.length == 320) rewindLengthOption.item(5).setSelected();
|
||||
rewindLengthOption.onChange([&] {
|
||||
settings.rewind.length = 10 << rewindLengthOption.selected().offset();
|
||||
program.rewindReset();
|
||||
});
|
||||
|
||||
rewindMute.setText("Mute while rewinding").setChecked(settings.rewind.mute).onToggle([&] {
|
||||
settings.rewind.mute = rewindMute.checked();
|
||||
});
|
||||
}
|
|
@ -61,7 +61,7 @@ auto ToolsWindow::create() -> void {
|
|||
panelContainer.append(manifestViewer, Size{~0, ~0});
|
||||
|
||||
setTitle("Tools");
|
||||
setSize({720_sx, 400_sx});
|
||||
setSize({720_sx, 400_sy});
|
||||
setAlignment({1.0, 1.0});
|
||||
setDismissable();
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ ifeq ($(ruby),)
|
|||
ruby += input.sdl input.xlib input.udev
|
||||
else ifeq ($(platform),bsd)
|
||||
ruby += video.glx video.glx2 video.xvideo video.xshm
|
||||
ruby += audio.oss #audio.openal
|
||||
ruby += audio.oss #audio.pulseaudio
|
||||
ruby += input.sdl input.xlib
|
||||
endif
|
||||
endif
|
||||
|
|
Loading…
Reference in New Issue