diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 04cc680e..fa27d877 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "103.08"; + static const string Version = "103.09"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index 51d69d2c..17645885 100644 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -43,10 +43,14 @@ struct Interface { virtual auto title() -> string = 0; //video information - struct VideoSize { uint width, height; }; - virtual auto videoResolution() -> VideoSize = 0; - virtual auto videoSize(uint width, uint height, bool aspectCorrection, uint cropWidth = 0, uint cropHeight = 0) -> VideoSize = 0; - virtual auto videoCrop(const uint32*& data, uint& width, uint& height, uint cropWidth, uint cropHeight) -> void {} + struct VideoResolution { + uint width; + uint height; + uint internalWidth; + uint internalHeight; + double aspectCorrection; + }; + virtual auto videoResolution() -> VideoResolution = 0; virtual auto videoColors() -> uint32 = 0; virtual auto videoColor(uint32 color) -> uint64 = 0; diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp index 20fc4683..7af4e9a5 100644 --- a/higan/fc/interface/interface.cpp +++ b/higan/fc/interface/interface.cpp @@ -44,21 +44,8 @@ auto Interface::title() -> string { return cartridge.title(); } -auto Interface::videoResolution() -> VideoSize { - return {256, 240}; -} - -auto Interface::videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize { - double widthDivider = (256 - cropHorizontal * 2) * (aspectCorrection ? 8.0 / 7.0 : 1.0); - double heightDivider = (240 - cropVertical * 2); - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; -} - -auto Interface::videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void { - data += cropVertical * 256 + cropHorizontal; - width -= cropHorizontal * 2; - height -= cropVertical * 2; +auto Interface::videoResolution() -> VideoResolution { + return {256, 240, 256, 240, 8.0 / 7.0}; } auto Interface::videoColors() -> uint32 { diff --git a/higan/fc/interface/interface.hpp b/higan/fc/interface/interface.hpp index 08df5b9f..3ce8110e 100644 --- a/higan/fc/interface/interface.hpp +++ b/higan/fc/interface/interface.hpp @@ -26,9 +26,7 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize override; - auto videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void override; + auto videoResolution() -> VideoResolution override; auto videoColors() -> uint32 override; auto videoColor(uint32 color) -> uint64 override; diff --git a/higan/gb/interface/interface.cpp b/higan/gb/interface/interface.cpp index 864a3c0b..8a85971b 100644 --- a/higan/gb/interface/interface.cpp +++ b/higan/gb/interface/interface.cpp @@ -33,15 +33,8 @@ auto Interface::title() -> string { return cartridge.title(); } -auto Interface::videoResolution() -> VideoSize { - return {160, 144}; -} - -auto Interface::videoSize(uint width, uint height, bool, uint, uint) -> VideoSize { - double widthDivider = 160; - double heightDivider = 144; - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; +auto Interface::videoResolution() -> VideoResolution { + return {160, 144, 160, 144, 1.0}; } auto Interface::loaded() -> bool { diff --git a/higan/gb/interface/interface.hpp b/higan/gb/interface/interface.hpp index 6a243ef6..9da3820e 100644 --- a/higan/gb/interface/interface.hpp +++ b/higan/gb/interface/interface.hpp @@ -23,8 +23,7 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool, uint, uint) -> VideoSize override; + auto videoResolution() -> VideoResolution override; auto loaded() -> bool override; auto sha256() -> string override; diff --git a/higan/gba/apu/wave.cpp b/higan/gba/apu/wave.cpp index ebfcb223..070cd88c 100644 --- a/higan/gba/apu/wave.cpp +++ b/higan/gba/apu/wave.cpp @@ -66,14 +66,14 @@ auto APU::Wave::write(uint addr, uint8 byte) -> void { auto APU::Wave::readram(uint addr) const -> uint8 { uint8 byte = 0; - byte |= pattern[!bank << 5 | addr << 1 | 0] << 0; - byte |= pattern[!bank << 5 | addr << 1 | 1] << 4; + byte |= pattern[!bank << 5 | addr << 1 | 0] << 4; + byte |= pattern[!bank << 5 | addr << 1 | 1] << 0; return byte; } auto APU::Wave::writeram(uint addr, uint8 byte) -> void { - pattern[!bank << 5 | addr << 1 | 0] = byte >> 0; - pattern[!bank << 5 | addr << 1 | 1] = byte >> 4; + pattern[!bank << 5 | addr << 1 | 0] = byte >> 4; + pattern[!bank << 5 | addr << 1 | 1] = byte >> 0; } auto APU::Wave::power() -> void { diff --git a/higan/gba/interface/interface.cpp b/higan/gba/interface/interface.cpp index 2debeb74..504c1ad3 100644 --- a/higan/gba/interface/interface.cpp +++ b/higan/gba/interface/interface.cpp @@ -39,21 +39,14 @@ auto Interface::title() -> string { return cartridge.title(); } -auto Interface::videoResolution() -> VideoSize { +auto Interface::videoResolution() -> VideoResolution { if(!settings.rotateLeft) { - return {240, 160}; + return {240, 160, 240, 160, 1.0}; } else { - return {160, 240}; + return {160, 240, 160, 240, 1.0}; } } -auto Interface::videoSize(uint width, uint height, bool, uint, uint) -> VideoSize { - double widthDivider = videoResolution().width; - double heightDivider = videoResolution().height; - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; -} - auto Interface::videoColors() -> uint32 { return 1 << 15; } diff --git a/higan/gba/interface/interface.hpp b/higan/gba/interface/interface.hpp index ab18d920..ca85e284 100644 --- a/higan/gba/interface/interface.hpp +++ b/higan/gba/interface/interface.hpp @@ -23,8 +23,7 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool, uint, uint) -> VideoSize override; + auto videoResolution() -> VideoResolution override; auto videoColors() -> uint32 override; auto videoColor(uint32 color) -> uint64 override; diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp index 9896c208..5ed75279 100644 --- a/higan/md/interface/interface.cpp +++ b/higan/md/interface/interface.cpp @@ -52,23 +52,8 @@ auto Interface::title() -> string { return cartridge.title(); } -auto Interface::videoResolution() -> VideoSize { - return {1280, 480}; -} - -auto Interface::videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize { - double widthDivider = (320 - cropHorizontal * 2); - double heightDivider = (240 - cropVertical * 2); - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; -} - -auto Interface::videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void { - cropHorizontal *= 4; - cropVertical *= 2; - data += cropVertical * 1280 + cropHorizontal; - width -= cropHorizontal * 2; - height -= cropVertical * 2; +auto Interface::videoResolution() -> VideoResolution { + return {320, 240, 1280, 480, 1.0}; } auto Interface::videoColors() -> uint32 { diff --git a/higan/md/interface/interface.hpp b/higan/md/interface/interface.hpp index 3dc386fb..664af71a 100644 --- a/higan/md/interface/interface.hpp +++ b/higan/md/interface/interface.hpp @@ -26,9 +26,7 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize override; - auto videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void override; + auto videoResolution() -> VideoResolution override; auto videoColors() -> uint32 override; auto videoColor(uint32 color) -> uint64 override; diff --git a/higan/ms/interface/game-gear.cpp b/higan/ms/interface/game-gear.cpp index c452f259..fdb2a01d 100644 --- a/higan/ms/interface/game-gear.cpp +++ b/higan/ms/interface/game-gear.cpp @@ -21,15 +21,8 @@ GameGearInterface::GameGearInterface() { ports.append(move(hardware)); } -auto GameGearInterface::videoResolution() -> VideoSize { - return {160, 144}; -} - -auto GameGearInterface::videoSize(uint width, uint height, bool, uint, uint) -> VideoSize { - double widthDivider = 160; - double heightDivider = 144; - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; +auto GameGearInterface::videoResolution() -> VideoResolution { + return {160, 144, 160, 144, 1.0}; } auto GameGearInterface::videoColors() -> uint32 { diff --git a/higan/ms/interface/interface.hpp b/higan/ms/interface/interface.hpp index 30d9ac24..998cfc0f 100644 --- a/higan/ms/interface/interface.hpp +++ b/higan/ms/interface/interface.hpp @@ -50,9 +50,7 @@ struct MasterSystemInterface : Interface { MasterSystemInterface(); - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool aspectCorrection, uint cropWidth, uint cropHeight) -> VideoSize override; - auto videoCrop(const uint32*& data, uint& width, uint& height, uint cropWidth, uint cropHeight) -> void override; + auto videoResolution() -> VideoResolution override; auto videoColors() -> uint32 override; auto videoColor(uint32 color) -> uint64 override; @@ -66,8 +64,7 @@ struct GameGearInterface : Interface { GameGearInterface(); - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool, uint, uint) -> VideoSize override; + auto videoResolution() -> VideoResolution override; auto videoColors() -> uint32 override; auto videoColor(uint32 color) -> uint64 override; diff --git a/higan/ms/interface/master-system.cpp b/higan/ms/interface/master-system.cpp index 001ace55..6b0529a0 100644 --- a/higan/ms/interface/master-system.cpp +++ b/higan/ms/interface/master-system.cpp @@ -36,21 +36,8 @@ MasterSystemInterface::MasterSystemInterface() { ports.append(move(controllerPort2)); } -auto MasterSystemInterface::videoResolution() -> VideoSize { - return {256, 240}; -} - -auto MasterSystemInterface::videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize { - double widthDivider = (256 - cropHorizontal * 2) * (aspectCorrection ? 8.0 / 7.0 : 1.0); - double heightDivider = (240 - cropVertical * 2); - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; -} - -auto MasterSystemInterface::videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void { - data += cropVertical * 256 + cropHorizontal; - width -= cropHorizontal * 2; - height -= cropVertical * 2; +auto MasterSystemInterface::videoResolution() -> VideoResolution { + return {256, 240, 256, 240, 8.0 / 7.0}; } auto MasterSystemInterface::videoColors() -> uint32 { diff --git a/higan/pce/interface/interface.cpp b/higan/pce/interface/interface.cpp index 080fbbe8..5de84f22 100644 --- a/higan/pce/interface/interface.cpp +++ b/higan/pce/interface/interface.cpp @@ -39,22 +39,8 @@ auto Interface::title() -> string { return cartridge.title(); } -auto Interface::videoResolution() -> VideoSize { - return {1120, 240}; -} - -auto Interface::videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize { - double widthDivider = (280 - cropHorizontal * 2) * (aspectCorrection ? 8.0 / 7.0 : 1.0); - double heightDivider = (240 - cropVertical * 2); - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; -} - -auto Interface::videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void { - cropHorizontal *= 4; - data += cropVertical * 1120 + cropHorizontal; - width -= cropHorizontal * 2; - height -= cropVertical * 2; +auto Interface::videoResolution() -> VideoResolution { + return {280, 240, 1120, 240, 8.0 / 7.0}; } auto Interface::videoColors() -> uint32 { diff --git a/higan/pce/interface/interface.hpp b/higan/pce/interface/interface.hpp index 441900c4..103838ef 100644 --- a/higan/pce/interface/interface.hpp +++ b/higan/pce/interface/interface.hpp @@ -23,9 +23,7 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize override; - auto videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void override; + auto videoResolution() -> VideoResolution override; auto videoColors() -> uint32 override; auto videoColor(uint32 color) -> uint64 override; diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index 4452efaa..a9585dc1 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -118,23 +118,8 @@ auto Interface::title() -> string { return cartridge.title(); } -auto Interface::videoResolution() -> VideoSize { - return {512, 480}; -} - -auto Interface::videoSize(uint width, uint height, bool aspectCorrection, uint cropHorizontal, uint cropVertical) -> VideoSize { - double widthDivider = (256 - cropHorizontal * 2) * (aspectCorrection ? 8.0 / 7.0 : 1.0); - double heightDivider = (240 - cropVertical * 2); - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; -} - -auto Interface::videoCrop(const uint32*& data, uint& width, uint& height, uint cropHorizontal, uint cropVertical) -> void { - cropHorizontal *= 2; - cropVertical *= 2; - data += cropVertical * 512 + cropHorizontal; - width -= cropHorizontal * 2; - height -= cropVertical * 2; +auto Interface::videoResolution() -> VideoResolution { + return {256, 240, 512, 480, 8.0 / 7.0}; } auto Interface::videoColors() -> uint32 { diff --git a/higan/sfc/interface/interface.hpp b/higan/sfc/interface/interface.hpp index 1a8f3358..7502a9bf 100644 --- a/higan/sfc/interface/interface.hpp +++ b/higan/sfc/interface/interface.hpp @@ -38,9 +38,7 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool aspectCorrection, uint cropWidth, uint cropHeight) -> VideoSize override; - auto videoCrop(const uint32*& data, uint& width, uint& height, uint cropWidth, uint cropHeight) -> void override; + auto videoResolution() -> VideoResolution override; auto videoColors() -> uint32 override; auto videoColor(uint32 color) -> uint64 override; diff --git a/higan/target-tomoko/configuration/configuration.cpp b/higan/target-tomoko/configuration/configuration.cpp index 980d82a8..9c4e2c06 100644 --- a/higan/target-tomoko/configuration/configuration.cpp +++ b/higan/target-tomoko/configuration/configuration.cpp @@ -16,8 +16,6 @@ Settings::Settings() { set("Video/Driver", ruby::Video::optimalDriver()); set("Video/Synchronize", false); - set("Video/Scale", "Small"); - set("Video/AspectCorrection", true); set("Video/Shader", "Blur"); set("Video/BlurEmulation", true); set("Video/ColorEmulation", true); @@ -31,6 +29,16 @@ Settings::Settings() { set("Video/Overscan/Horizontal", 8); set("Video/Overscan/Vertical", 8); + set("Video/Windowed/AspectCorrection", true); + set("Video/Windowed/Adaptive", false); + set("Video/Windowed/Multiplier", "Small"); + set("Video/Windowed/Multiplier/Small", 2); + set("Video/Windowed/Multiplier/Medium", 3); + set("Video/Windowed/Multiplier/Large", 4); + + set("Video/Fullscreen/AspectCorrection", true); + set("Video/Fullscreen/Adaptive", false); + set("Audio/Driver", ruby::Audio::optimalDriver()); set("Audio/Device", ""); set("Audio/Exclusive", false); diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index 1b50a159..5b97dafa 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -47,23 +47,19 @@ Presentation::Presentation() { settingsMenu.setText("Settings"); videoScaleMenu.setText("Video Scale"); - if(settings["Video/Scale"].text() == "Small") videoScaleSmall.setChecked(); - if(settings["Video/Scale"].text() == "Medium") videoScaleMedium.setChecked(); - if(settings["Video/Scale"].text() == "Large") videoScaleLarge.setChecked(); + if(settings["Video/Windowed/Multiplier"].text() == "Small") videoScaleSmall.setChecked(); + if(settings["Video/Windowed/Multiplier"].text() == "Medium") videoScaleMedium.setChecked(); + if(settings["Video/Windowed/Multiplier"].text() == "Large") videoScaleLarge.setChecked(); videoScaleSmall.setText("Small").onActivate([&] { - settings["Video/Scale"].setValue("Small"); + settings["Video/Windowed/Multiplier"].setValue("Small"); resizeViewport(); }); videoScaleMedium.setText("Medium").onActivate([&] { - settings["Video/Scale"].setValue("Medium"); + settings["Video/Windowed/Multiplier"].setValue("Medium"); resizeViewport(); }); videoScaleLarge.setText("Large").onActivate([&] { - settings["Video/Scale"].setValue("Large"); - resizeViewport(); - }); - aspectCorrection.setText("Aspect Correction").setChecked(settings["Video/AspectCorrection"].boolean()).onToggle([&] { - settings["Video/AspectCorrection"].setValue(aspectCorrection.checked()); + settings["Video/Windowed/Multiplier"].setValue("Large"); resizeViewport(); }); videoEmulationMenu.setText("Video Emulation"); @@ -243,35 +239,59 @@ auto Presentation::resizeViewport() -> void { //clear video area before resizing to avoid seeing distorted video momentarily clearViewport(); - uint scale = 2; - if(settings["Video/Scale"].text() == "Small" ) scale = 2; - if(settings["Video/Scale"].text() == "Medium") scale = 3; - if(settings["Video/Scale"].text() == "Large" ) scale = 4; - - uint windowWidth = 0, windowHeight = 0; - bool aspectCorrection = true; - if(!fullScreen()) { - windowWidth = 320 * scale; - windowHeight = 240 * scale; - aspectCorrection = settings["Video/AspectCorrection"].boolean(); - } else { - windowWidth = geometry().width(); - windowHeight = geometry().height(); - } - if(!fullScreen()) setSize({windowWidth, windowHeight}); - - if(!emulator) { - viewport.setGeometry({0, 0, windowWidth, windowHeight}); - } else { - uint overscanWidth = 0, overscanHeight = 0; + double emulatorWidth = 320; + double emulatorHeight = 240; + double aspectCorrection = 1.0; + if(emulator) { + auto resolution = emulator->videoResolution(); + emulatorWidth = resolution.width; + emulatorHeight = resolution.height; + aspectCorrection = resolution.aspectCorrection; if(emulator->information.overscan && settings["Video/Overscan/Mask"].boolean()) { - overscanWidth = settings["Video/Overscan/Horizontal"].natural(); - overscanHeight = settings["Video/Overscan/Vertical" ].natural(); + uint overscanHorizontal = settings["Video/Overscan/Horizontal"].natural(); + uint overscanVertical = settings["Video/Overscan/Vertical"].natural(); + emulatorWidth -= overscanHorizontal * 2; + emulatorHeight -= overscanVertical * 2; + } + } + + if(!fullScreen()) { + if(settings["Video/Windowed/AspectCorrection"].boolean()) emulatorWidth *= aspectCorrection; + uint viewportMultiplier = 2; + if(settings["Video/Windowed/Multiplier"].text() == "Small") viewportMultiplier = settings["Video/Windowed/Multiplier/Small"].natural(); + if(settings["Video/Windowed/Multiplier"].text() == "Medium") viewportMultiplier = settings["Video/Windowed/Multiplier/Medium"].natural(); + if(settings["Video/Windowed/Multiplier"].text() == "Large") viewportMultiplier = settings["Video/Windowed/Multiplier/Large"].natural(); + uint viewportWidth = 320 * viewportMultiplier; + uint viewportHeight = 240 * viewportMultiplier; + uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight); + if(!settings["Video/Windowed/Adaptive"].boolean()) { + emulatorWidth *= multiplier; + emulatorHeight *= multiplier; + setSize({viewportWidth, viewportHeight}); + viewport.setGeometry({ + (viewportWidth - emulatorWidth) / 2, (viewportHeight - emulatorHeight) / 2, + emulatorWidth, emulatorHeight + }); + } else { + setSize({emulatorWidth * multiplier, emulatorHeight * multiplier}); + viewport.setGeometry({0, 0, emulatorWidth * multiplier, emulatorHeight * multiplier}); + } + } else { + if(settings["Video/Fullscreen/AspectCorrection"].boolean()) emulatorWidth *= aspectCorrection; + uint viewportWidth = geometry().width(); + uint viewportHeight = geometry().height(); + if(!settings["Video/Fullscreen/Adaptive"].boolean()) { + uint multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight); + emulatorWidth *= multiplier; + emulatorHeight *= multiplier; + } else { + double multiplier = min(viewportWidth / emulatorWidth, viewportHeight / emulatorHeight); + emulatorWidth *= multiplier; + emulatorHeight *= multiplier; } - auto videoSize = emulator->videoSize(windowWidth, windowHeight, aspectCorrection, overscanWidth, overscanHeight); viewport.setGeometry({ - (windowWidth - videoSize.width) / 2, (windowHeight - videoSize.height) / 2, - videoSize.width, videoSize.height + (viewportWidth - emulatorWidth) / 2, (viewportHeight - emulatorHeight) / 2, + emulatorWidth, emulatorHeight }); } diff --git a/higan/target-tomoko/presentation/presentation.hpp b/higan/target-tomoko/presentation/presentation.hpp index abea4ccb..c80fd9b9 100644 --- a/higan/target-tomoko/presentation/presentation.hpp +++ b/higan/target-tomoko/presentation/presentation.hpp @@ -31,8 +31,6 @@ struct Presentation : Window { MenuRadioItem videoScaleMedium{&videoScaleMenu}; MenuRadioItem videoScaleLarge{&videoScaleMenu}; Group videoScales{&videoScaleSmall, &videoScaleMedium, &videoScaleLarge}; - MenuSeparator videoScaleSeparator{&videoScaleMenu}; - MenuCheckItem aspectCorrection{&videoScaleMenu}; Menu videoEmulationMenu{&settingsMenu}; MenuCheckItem blurEmulation{&videoEmulationMenu}; MenuCheckItem colorEmulation{&videoEmulationMenu}; diff --git a/higan/target-tomoko/program/interface.cpp b/higan/target-tomoko/program/interface.cpp index 5c08e3e0..b1a4af62 100644 --- a/higan/target-tomoko/program/interface.cpp +++ b/higan/target-tomoko/program/interface.cpp @@ -56,9 +56,14 @@ auto Program::videoRefresh(const uint32* data, uint pitch, uint width, uint heig pitch >>= 2; if(emulator->information.overscan && settings["Video/Overscan/Mask"].boolean()) { - uint horizontal = settings["Video/Overscan/Horizontal"].natural(); - uint vertical = settings["Video/Overscan/Vertical"].natural(); - emulator->videoCrop(data, width, height, horizontal, vertical); + uint overscanHorizontal = settings["Video/Overscan/Horizontal"].natural(); + uint overscanVertical = settings["Video/Overscan/Vertical"].natural(); + auto resolution = emulator->videoResolution(); + overscanHorizontal *= resolution.internalWidth / resolution.width; + overscanVertical *= resolution.internalHeight / resolution.height; + data += overscanVertical * pitch + overscanHorizontal; + width -= overscanHorizontal * 2; + height -= overscanVertical * 2; } if(video->lock(output, length, width, height)) { diff --git a/higan/target-tomoko/settings/settings.hpp b/higan/target-tomoko/settings/settings.hpp index 351ad696..673358cd 100644 --- a/higan/target-tomoko/settings/settings.hpp +++ b/higan/target-tomoko/settings/settings.hpp @@ -2,7 +2,7 @@ struct VideoSettings : TabFrameItem { VideoSettings(TabFrame*); VerticalLayout layout{this}; - Label colorAdjustmentLabel{&layout, Size{~0, 0}}; + Label colorAdjustmentLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout saturationLayout{&layout, Size{~0, 0}}; Label saturationLabel{&saturationLayout, Size{80, 0}}; Label saturationValue{&saturationLayout, Size{50, 0}}; @@ -15,7 +15,7 @@ struct VideoSettings : TabFrameItem { Label luminanceLabel{&luminanceLayout, Size{80, 0}}; Label luminanceValue{&luminanceLayout, Size{50, 0}}; HorizontalSlider luminanceSlider{&luminanceLayout, Size{~0, 0}}; - Label overscanMaskLabel{&layout, Size{~0, 0}}; + Label overscanMaskLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout horizontalMaskLayout{&layout, Size{~0, 0}}; Label horizontalMaskLabel{&horizontalMaskLayout, Size{80, 0}}; Label horizontalMaskValue{&horizontalMaskLayout, Size{50, 0}}; @@ -24,16 +24,25 @@ struct VideoSettings : TabFrameItem { Label verticalMaskLabel{&verticalMaskLayout, Size{80, 0}}; Label verticalMaskValue{&verticalMaskLayout, Size{50, 0}}; HorizontalSlider verticalMaskSlider{&verticalMaskLayout, Size{~0, 0}}; + Label windowedModeLabel{&layout, Size{~0, 0}, 2}; + HorizontalLayout windowedModeLayout{&layout, Size{~0, 0}}; + CheckLabel windowedModeAspectCorrection{&windowedModeLayout, Size{0, 0}}; + CheckLabel windowedModeAdaptive{&windowedModeLayout, Size{0, 0}}; + Label fullscreenModeLabel{&layout, Size{~0, 0}, 2}; + HorizontalLayout fullscreenModeLayout{&layout, Size{~0, 0}}; + CheckLabel fullscreenModeAspectCorrection{&fullscreenModeLayout, Size{0, 0}}; + CheckLabel fullscreenModeAdaptive{&fullscreenModeLayout, Size{0, 0}}; auto updateColor() -> void; auto updateOverscan() -> void; + auto updateViewport() -> void; }; struct AudioSettings : TabFrameItem { AudioSettings(TabFrame*); VerticalLayout layout{this}; - Label driverLabel{&layout, Size{~0, 0}}; + Label driverLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout controlLayout{&layout, Size{~0, 0}}; Label latencyLabel{&controlLayout, Size{0, 0}}; ComboButton latencyCombo{&controlLayout, Size{~0, 0}}; @@ -42,7 +51,7 @@ struct AudioSettings : TabFrameItem { Label resamplerLabel{&controlLayout, Size{0, 0}}; ComboButton resamplerCombo{&controlLayout, Size{~0, 0}}; CheckLabel exclusiveMode{&layout, Size{~0, 0}}; - Label effectsLabel{&layout, Size{~0, 0}}; + Label effectsLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout volumeLayout{&layout, Size{~0, 0}}; Label volumeLabel{&volumeLayout, Size{80, 0}}; Label volumeValue{&volumeLayout, Size{50, 0}}; diff --git a/higan/target-tomoko/settings/video.cpp b/higan/target-tomoko/settings/video.cpp index a86eafc2..772d7f33 100644 --- a/higan/target-tomoko/settings/video.cpp +++ b/higan/target-tomoko/settings/video.cpp @@ -23,8 +23,17 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { verticalMaskValue.setAlignment(0.5); verticalMaskSlider.setLength(25).setPosition(settings["Video/Overscan/Vertical"].natural()).onChange([&] { updateOverscan(); }); + windowedModeLabel.setFont(Font().setBold()).setText("Windowed Mode"); + windowedModeAspectCorrection.setText("Correct aspect ratio").setChecked(settings["Video/Windowed/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); }); + windowedModeAdaptive.setText("Resize window to viewport").setChecked(settings["Video/Windowed/Adaptive"].boolean()).onToggle([&] { updateViewport(); }); + + fullscreenModeLabel.setFont(Font().setBold()).setText("Fullscreen Mode"); + fullscreenModeAspectCorrection.setText("Correct aspect ratio").setChecked(settings["Video/Fullscreen/AspectCorrection"].boolean()).onToggle([&] { updateViewport(); }); + fullscreenModeAdaptive.setText("Resize viewport to window").setChecked(settings["Video/Fullscreen/Adaptive"].boolean()).onToggle([&] { updateViewport(); }); + updateColor(); updateOverscan(); + updateViewport(); } auto VideoSettings::updateColor() -> void { @@ -44,3 +53,11 @@ auto VideoSettings::updateOverscan() -> void { verticalMaskValue.setText({verticalMaskSlider.position()}); presentation->resizeViewport(); } + +auto VideoSettings::updateViewport() -> void { + settings["Video/Windowed/AspectCorrection"].setValue(windowedModeAspectCorrection.checked()); + settings["Video/Windowed/Adaptive"].setValue(windowedModeAdaptive.checked()); + settings["Video/Fullscreen/AspectCorrection"].setValue(fullscreenModeAspectCorrection.checked()); + settings["Video/Fullscreen/Adaptive"].setValue(fullscreenModeAdaptive.checked()); + presentation->resizeViewport(); +} diff --git a/higan/ws/interface/interface.cpp b/higan/ws/interface/interface.cpp index f9c5af66..78bfbd9c 100644 --- a/higan/ws/interface/interface.cpp +++ b/higan/ws/interface/interface.cpp @@ -35,21 +35,14 @@ auto Interface::title() -> string { return cartridge.information.title; } -auto Interface::videoResolution() -> VideoSize { +auto Interface::videoResolution() -> VideoResolution { if(!settings.rotateLeft) { - return {224, 144}; + return {224, 144, 224, 144, 1.0}; } else { - return {144, 224}; + return {144, 224, 144, 224, 1.0}; } } -auto Interface::videoSize(uint width, uint height, bool, uint, uint) -> VideoSize { - double widthDivider = videoResolution().width; - double heightDivider = videoResolution().height; - uint multiplier = min(width / widthDivider, height / heightDivider); - return {uint(widthDivider * multiplier), uint(heightDivider * multiplier)}; -} - auto Interface::loaded() -> bool { return system.loaded(); } diff --git a/higan/ws/interface/interface.hpp b/higan/ws/interface/interface.hpp index e1ba60d8..05893b02 100644 --- a/higan/ws/interface/interface.hpp +++ b/higan/ws/interface/interface.hpp @@ -22,8 +22,7 @@ struct Interface : Emulator::Interface { auto manifest() -> string override; auto title() -> string override; - auto videoResolution() -> VideoSize override; - auto videoSize(uint width, uint height, bool, uint, uint) -> VideoSize override; + auto videoResolution() -> VideoResolution override; auto loaded() -> bool override; auto sha256() -> string override;