diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index c65cb0afe..af85deff6 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -30,7 +30,7 @@ using namespace nall; namespace Emulator { static const string Name = "bsnes"; - static const string Version = "108.7"; + static const string Version = "108.8"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org"; diff --git a/bsnes/sfc/interface/configuration.cpp b/bsnes/sfc/interface/configuration.cpp index 22b8fd114..822a4992e 100644 --- a/bsnes/sfc/interface/configuration.cpp +++ b/bsnes/sfc/interface/configuration.cpp @@ -19,6 +19,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void { bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock); bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast); bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit); + bind(boolean, "Hacks/PPU/Deinterlace", hacks.ppu.deinterlace); bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale); bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective); bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample); diff --git a/bsnes/sfc/interface/configuration.hpp b/bsnes/sfc/interface/configuration.hpp index 1b8986b35..2ee9b68ae 100644 --- a/bsnes/sfc/interface/configuration.hpp +++ b/bsnes/sfc/interface/configuration.hpp @@ -30,7 +30,8 @@ struct Configuration { } cpu; struct PPU { bool fast = true; - bool noSpriteLimit = false; + bool noSpriteLimit = true; + bool deinterlace = true; struct Mode7 { uint scale = 1; bool perspective = true; diff --git a/bsnes/sfc/ppu-fast/background.cpp b/bsnes/sfc/ppu-fast/background.cpp index e34a09633..7b4c7acdb 100644 --- a/bsnes/sfc/ppu-fast/background.cpp +++ b/bsnes/sfc/ppu-fast/background.cpp @@ -29,7 +29,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint source) -> void uint y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0); if(hires) { hscroll <<= 1; - if(io.interlace) y = y << 1 | ppu.field(); + if(io.interlace) y = y << 1 | field(); } uint mosaicCounter = 1; diff --git a/bsnes/sfc/ppu-fast/line.cpp b/bsnes/sfc/ppu-fast/line.cpp index 0e0b124ed..6e060ec7c 100644 --- a/bsnes/sfc/ppu-fast/line.cpp +++ b/bsnes/sfc/ppu-fast/line.cpp @@ -5,21 +5,34 @@ auto PPU::Line::flush() -> void { if(Line::count) { #pragma omp parallel for if(Line::count >= 8) for(uint y = 0; y < Line::count; y++) { - ppu.lines[Line::start + y].render(); + if(ppu.deinterlace()) { + if(!ppu.interlace()) { + //some games enable interlacing in 240p mode, just force these to even fields + ppu.lines[Line::start + y].render(0); + } else { + //for actual interlaced frames, render both fields every farme for 480i -> 480p + ppu.lines[Line::start + y].render(0); + ppu.lines[Line::start + y].render(1); + } + } else { + //standard 240p (progressive) and 480i (interlaced) rendering + ppu.lines[Line::start + y].render(ppu.field()); + } } Line::start = 0; Line::count = 0; } } -auto PPU::Line::render() -> void { +auto PPU::Line::render(bool fieldID) -> void { + this->fieldID = fieldID; uint y = this->y + (!ppu.latch.overscan ? 7 : 0); auto hd = ppu.hd(); auto ss = ppu.ss(); auto scale = ppu.hdScale(); auto output = ppu.output + (!hd - ? (y * 1024 + (ppu.interlace() && ppu.field() ? 512 : 0)) + ? (y * 1024 + (ppu.interlace() && field() ? 512 : 0)) : (y * 256 * scale * scale) ); auto width = (!hd @@ -34,8 +47,8 @@ auto PPU::Line::render() -> void { bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6; auto aboveColor = cgram[0]; auto belowColor = hires ? cgram[0] : io.col.fixedColor; - uint xa = (hd || ss) && ppu.interlace() && ppu.field() ? 256 * scale * scale / 2 : 0; - uint xb = !(hd || ss) ? 256 : ppu.interlace() && !ppu.field() ? 256 * scale * scale / 2 : 256 * scale * scale; + uint xa = (hd || ss) && ppu.interlace() && field() ? 256 * scale * scale / 2 : 0; + uint xb = !(hd || ss) ? 256 : ppu.interlace() && !field() ? 256 * scale * scale / 2 : 256 * scale * scale; for(uint x = xa; x < xb; x++) { above[x] = {Source::COL, 0, aboveColor}; below[x] = {Source::COL, 0, belowColor}; @@ -128,11 +141,11 @@ auto PPU::Line::plotBelow(uint x, uint source, uint priority, uint color) -> voi auto PPU::Line::plotHD(Pixel* pixel, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void { auto scale = ppu.hdScale(); int xss = hires && subpixel ? scale / 2 : 0; - int ys = ppu.interlace() && ppu.field() ? scale / 2 : 0; + int ys = ppu.interlace() && field() ? scale / 2 : 0; if(priority > pixel[x * scale + xss + ys * 256 * scale].priority) { Pixel p = {source, priority, color}; int xsm = hires && !subpixel ? scale / 2 : scale; - int ysm = ppu.interlace() && !ppu.field() ? scale / 2 : scale; + int ysm = ppu.interlace() && !field() ? scale / 2 : scale; for(int xs = xss; xs < xsm; xs++) { pixel[x * scale + xs + ys * 256 * scale] = p; } diff --git a/bsnes/sfc/ppu-fast/object.cpp b/bsnes/sfc/ppu-fast/object.cpp index cfea2e18f..85224f11a 100644 --- a/bsnes/sfc/ppu-fast/object.cpp +++ b/bsnes/sfc/ppu-fast/object.cpp @@ -59,7 +59,7 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { } if(self.interlace) { - y = !object.vflip ? y + ppu.field() : y - ppu.field(); + y = !object.vflip ? y + field() : y - field(); } x &= 511; diff --git a/bsnes/sfc/ppu-fast/ppu.cpp b/bsnes/sfc/ppu-fast/ppu.cpp index 9ae5bca6a..7df82e8ce 100644 --- a/bsnes/sfc/ppu-fast/ppu.cpp +++ b/bsnes/sfc/ppu-fast/ppu.cpp @@ -28,6 +28,7 @@ auto PPU::hdScale() const -> uint { return configuration.hacks.ppu.mode7.scale; auto PPU::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; } auto PPU::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; } auto PPU::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; } +auto PPU::deinterlace() const -> bool { return configuration.hacks.ppu.deinterlace; } #define ppu ppufast PPU::PPU() { diff --git a/bsnes/sfc/ppu-fast/ppu.hpp b/bsnes/sfc/ppu-fast/ppu.hpp index e5d7c9d6a..98756bf10 100644 --- a/bsnes/sfc/ppu-fast/ppu.hpp +++ b/bsnes/sfc/ppu-fast/ppu.hpp @@ -18,6 +18,7 @@ struct PPU : PPUcounter { alwaysinline auto hdPerspective() const -> bool; alwaysinline auto hdSupersample() const -> bool; alwaysinline auto hdMosaic() const -> bool; + alwaysinline auto deinterlace() const -> bool; //ppu.cpp PPU(); @@ -278,8 +279,9 @@ public: struct Line { //line.cpp + inline auto field() const -> bool { return fieldID; } static auto flush() -> void; - auto render() -> void; + auto render(bool field) -> void; auto pixel(uint x, Pixel above, Pixel below) const -> uint16; auto blend(uint x, uint y, bool halve) const -> uint16; alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint16; @@ -307,6 +309,7 @@ public: //[unserialized] uint y; //constant + bool fieldID; IO io; uint16 cgram[256]; diff --git a/bsnes/target-bsnes/program/game.cpp b/bsnes/target-bsnes/program/game.cpp index 4c878e92e..4bf9959c5 100644 --- a/bsnes/target-bsnes/program/game.cpp +++ b/bsnes/target-bsnes/program/game.cpp @@ -4,6 +4,7 @@ auto Program::load() -> void { emulator->configure("Hacks/CPU/Overclock", settings.emulator.hack.cpu.overclock); emulator->configure("Hacks/PPU/Fast", settings.emulator.hack.ppu.fast); emulator->configure("Hacks/PPU/NoSpriteLimit", settings.emulator.hack.ppu.noSpriteLimit); + emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace); emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale); emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective); emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample); diff --git a/bsnes/target-bsnes/settings/emulator.cpp b/bsnes/target-bsnes/settings/emulator.cpp index d6a2011ff..964a1f530 100644 --- a/bsnes/target-bsnes/settings/emulator.cpp +++ b/bsnes/target-bsnes/settings/emulator.cpp @@ -26,14 +26,22 @@ auto EmulatorSettings::create() -> void { fastPPU.setText("Fast mode").setChecked(settings.emulator.hack.ppu.fast).onToggle([&] { settings.emulator.hack.ppu.fast = fastPPU.checked(); if(!fastPPU.checked()) { - noSpriteLimit.setEnabled(false).setChecked(false).doToggle(); + noSpriteLimit.setEnabled(false); + deinterlace.setEnabled(false); + mode7Layout.setEnabled(false); } else { noSpriteLimit.setEnabled(true); + deinterlace.setEnabled(true); + mode7Layout.setEnabled(true); } }).doToggle(); noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] { settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked(); }); + 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); + }); mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold()); mode7ScaleLabel.setText("Scale:"); mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1)); diff --git a/bsnes/target-bsnes/settings/settings.cpp b/bsnes/target-bsnes/settings/settings.cpp index 67708b63a..40a60669d 100644 --- a/bsnes/target-bsnes/settings/settings.cpp +++ b/bsnes/target-bsnes/settings/settings.cpp @@ -112,6 +112,7 @@ auto Settings::process(bool load) -> void { bind(natural, "Emulator/Hack/CPU/Overclock", emulator.hack.cpu.overclock); bind(boolean, "Emulator/Hack/PPU/Fast", emulator.hack.ppu.fast); bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit); + bind(boolean, "Emulator/Hack/PPU/Deinterlace", emulator.hack.ppu.deinterlace); bind(natural, "Emulator/Hack/PPU/Mode7/Scale", emulator.hack.ppu.mode7.scale); bind(boolean, "Emulator/Hack/PPU/Mode7/Perspective", emulator.hack.ppu.mode7.perspective); bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample); diff --git a/bsnes/target-bsnes/settings/settings.hpp b/bsnes/target-bsnes/settings/settings.hpp index 3f88dd2c7..824c087e1 100644 --- a/bsnes/target-bsnes/settings/settings.hpp +++ b/bsnes/target-bsnes/settings/settings.hpp @@ -97,7 +97,8 @@ struct Settings : Markup::Node { } cpu; struct PPU { bool fast = true; - bool noSpriteLimit = false; + bool noSpriteLimit = true; + bool deinterlace = true; struct Mode7 { uint scale = 1; bool perspective = true; @@ -330,6 +331,7 @@ public: HorizontalLayout ppuLayout{this, Size{~0, 0}}; CheckLabel fastPPU{&ppuLayout, Size{0, 0}}; CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}}; + CheckLabel deinterlace{&ppuLayout, Size{0, 0}}; Label mode7Label{this, Size{~0, 0}, 2}; HorizontalLayout mode7Layout{this, Size{~0, 0}}; Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};