Commit 36c2ede6 authored by Tim Allen's avatar Tim Allen

Add /u/DerKoun's HD Mode 7 patch beta 4.

Downloaded from the original Reddit thread:

https://www.reddit.com/r/emulation/comments/bhskjr/hd_mode_7_mod_beta_4_bsnes_1073_widescreen/

DerKoun writes:

> New in this version:
>
>   - Widescreen: Setting to expand Mode 7 backgrounds to the left and right for
>     a 16:9 aspect ratio.
>
>   - Tweaked the behavior of Output/Center to drop the top and bottom 4
>     scanlines in 1080p fullscreen. This bumps the scaling form 4x to 5x and
>     with widescreen allows native 1080p fullscreen Mode 7 with uniformly
>     scaled sprites.
>
>   - Replaced magic numbers with preliminary detection for values at the edges
>     that break perspective correction. Fixes Tales of Phantasia (and should
>     not break Super Mario Kart).
>
>   - Disabled the automatic switching to non-scaled when there is no Mode 7
>     background, as it breaks with widescreen. [may also help with some
>     shaders, IIRC someone asked for this]
parent d39ae3fd
Pipeline #58704758 passed with stage
in 7 minutes and 24 seconds
......@@ -20,6 +20,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit);
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/Widescreen", hacks.ppu.mode7.widescreen);
bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample);
bind(boolean, "Hacks/PPU/Mode7/Mosaic", hacks.ppu.mode7.mosaic);
bind(boolean, "Hacks/DSP/Fast", hacks.dsp.fast);
......
......@@ -31,6 +31,7 @@ struct Configuration {
struct Mode7 {
uint scale = 1;
bool perspective = true;
bool widescreen = true;
bool supersample = false;
bool mosaic = true;
} mode7;
......
......@@ -18,7 +18,7 @@ auto PPUfast::Line::render() -> void {
auto scale = ppufast.hdScale();
auto output = ppufast.output + (!hd
? (y * 1024 + (ppufast.interlace() && ppufast.field() ? 512 : 0))
: (y * 256 * scale * scale)
: (y * (256+2*ppufast.widescreen()) * scale * scale)
);
auto width = (!hd
? (!ppufast.hires() ? 256 : 512)
......@@ -33,7 +33,7 @@ auto PPUfast::Line::render() -> void {
auto aboveColor = cgram[0];
auto belowColor = hires ? cgram[0] : io.col.fixedColor;
uint xa = (hd || ss) && ppufast.interlace() && ppufast.field() ? 256 * scale * scale / 2 : 0;
uint xb = !(hd || ss) ? 256 : ppufast.interlace() && !ppufast.field() ? 256 * scale * scale / 2 : 256 * scale * scale;
uint xb = !(hd || ss) ? 256 : ppufast.interlace() && !ppufast.field() ? (256+2*ppufast.widescreen()) * scale * scale / 2 : (256+2*ppufast.widescreen()) * scale * scale;
for(uint x = xa; x < xb; x++) {
above[x] = {Source::COL, 0, aboveColor};
below[x] = {Source::COL, 0, belowColor};
......@@ -48,8 +48,8 @@ auto PPUfast::Line::render() -> void {
renderWindow(io.col.window, io.col.window.belowMask, windowBelow);
auto luma = io.displayBrightness << 15;
if(hd) for(uint x : range(256 * scale * scale)) {
*output++ = luma | pixel(x / scale & 255, above[x], below[x]);
if(hd) for(uint x : range((256+2*ppufast.widescreen()) * scale * scale)) {
*output++ = luma | pixel((x / scale % (256+2*ppufast.widescreen()) - ppufast.widescreen()), above[x], below[x]);
} else if(width == 256) for(uint x : range(256)) {
*output++ = luma | pixel(x, above[x], below[x]);
} else if(!hires) for(uint x : range(256)) {
......@@ -63,6 +63,8 @@ auto PPUfast::Line::render() -> void {
}
auto PPUfast::Line::pixel(uint x, Pixel above, Pixel below) const -> uint15 {
if (x < 0) x = 0;
if (x > 255) x = 255;
if(!windowAbove[x]) above.color = 0x0000;
if(!windowBelow[x]) return above.color;
if(!io.col.enable[above.source]) return above.color;
......@@ -112,6 +114,7 @@ auto PPUfast::Line::plotBelow(uint x, uint source, uint priority, uint color) ->
//todo: name these variables more clearly ...
auto PPUfast::Line::plotHD(Pixel* pixel, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void {
auto scale = ppufast.hdScale();
pixel += ppufast.widescreen() * scale;
int xss = hires && subpixel ? scale / 2 : 0;
int ys = ppufast.interlace() && ppufast.field() ? scale / 2 : 0;
if(priority > pixel[x * scale + xss + ys * 256 * scale].priority) {
......@@ -124,7 +127,7 @@ auto PPUfast::Line::plotHD(Pixel* pixel, uint x, uint source, uint priority, uin
int size = sizeof(Pixel) * (xsm - xss);
Pixel* source = &pixel[x * scale + xss + ys * 256 * scale];
for(int yst = ys + 1; yst < ysm; yst++) {
memcpy(&pixel[x * scale + xss + yst * 256 * scale], source, size);
memcpy(&pixel[x * scale + xss + yst * (256+2*ppufast.widescreen()) * scale], source, size);
}
}
}
......@@ -9,29 +9,49 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
//find the first and last scanline for interpolation
int y_a = y;
int y_b = y;
#define isLineMode7(n) (ppufast.lines[n].io.bg1.tileMode == TileMode::Mode7 && ( \
#define isLineMode7(n) (ppufast.lines[n].io.bg1.tileMode == TileMode::Mode7 && !ppufast.lines[n].io.displayDisable && ( \
(ppufast.lines[n].io.bg1.aboveEnable || ppufast.lines[n].io.bg1.belowEnable) \
))
if(ppufast.hdPerspective()) {
while(y_a > 1 && isLineMode7(y_a)) y_a--; y_a += 1;
while(y_b < 239 && isLineMode7(y_b)) y_b++; y_b -= 8;
while(y_a > 1 && isLineMode7(y_a)) y_a--; y_a++;
while(y_b < 239 && isLineMode7(y_b)) y_b++; y_b--;
} else {
if(y_a > 1 && isLineMode7(y_a)) y_a--;
if(y_b < 239 && isLineMode7(y_b)) y_b++;
}
#undef isLineMode7
Line line_a = ppufast.lines[y_a];
float a_a = (int16)line_a.io.mode7.a;
float b_a = (int16)line_a.io.mode7.b;
float c_a = (int16)line_a.io.mode7.c;
float d_a = (int16)line_a.io.mode7.d;
Line line_b = ppufast.lines[y_b];
float a_b = (int16)line_b.io.mode7.a;
float b_b = (int16)line_b.io.mode7.b;
float c_b = (int16)line_b.io.mode7.c;
float d_b = (int16)line_b.io.mode7.d;
float a_a;
float b_a;
float c_a;
float d_a;
y_a--;
do {
y_a++;
Line line_a = ppufast.lines[y_a];
a_a = (int16)line_a.io.mode7.a;
b_a = (int16)line_a.io.mode7.b;
c_a = (int16)line_a.io.mode7.c;
d_a = (int16)line_a.io.mode7.d;
} while(ppufast.hdPerspective() && y_a < y
&& b_a == 0 && c_a == 0
&& b_a != (int16)io.mode7.b && c_a != (int16)io.mode7.c);
float a_b;
float b_b;
float c_b;
float d_b;
y_b++;
do {
y_b--;
Line line_b = ppufast.lines[y_b];
a_b = (int16)line_b.io.mode7.a;
b_b = (int16)line_b.io.mode7.b;
c_b = (int16)line_b.io.mode7.c;
d_b = (int16)line_b.io.mode7.d;
} while(ppufast.hdPerspective() && y_b > y
&& b_b == 0 && c_b == 0
&& b_b != (int16)io.mode7.b && c_a != (int16)io.mode7.b);
int hcenter = (int13)io.mode7.x;
int vcenter = (int13)io.mode7.y;
......@@ -64,9 +84,13 @@ auto PPUfast::Line::renderMode7HD(PPUfast::IO::Background& self, uint source) ->
float originY = (c * ht) + (d * vty) + (vcenter << 8);
int pixelXp = INT_MIN;
for(int x : range(256)) {
bool doAbove = self.aboveEnable && !windowAbove[x];
bool doBelow = self.belowEnable && !windowBelow[x];
for(int x : range(256+2*ppufast.widescreen())) {
x -= ppufast.widescreen();
int wx = x;
if (wx < 0) wx = 0;
if (wx > 255) wx = 255;
bool doAbove = self.aboveEnable && !windowAbove[wx];
bool doBelow = self.belowEnable && !windowBelow[wx];
for(int xs : range(scale)) {
float xf = x + xs * 1.0 / scale - 0.5;
......
......@@ -24,6 +24,7 @@ auto PPUfast::hdScale() const -> uint { return configuration.hacks.ppu.mode7.sca
auto PPUfast::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; }
auto PPUfast::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; }
auto PPUfast::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; }
auto PPUfast::widescreen() const -> int { return configuration.hacks.ppu.mode7.widescreen ? 64 : 0; } // 64 / 0 #widescreenextension
PPUfast::PPUfast() {
output = new uint32[2304 * 2304] + 72 * 2304; //overscan offset
......@@ -87,7 +88,7 @@ auto PPUfast::scanline() -> void {
if(vcounter() > 0 && vcounter() < vdisp()) {
latch.hires |= io.pseudoHires || io.bgMode == 5 || io.bgMode == 6;
latch.hd |= io.bgMode == 7 && hdScale() > 1 && hdSupersample() == 0;
latch.hd |= /*io.bgMode == 7 &&*/ hdScale() > 1 && hdSupersample() == 0; //deactivated dynamic scale switching for widescreen
latch.ss |= io.bgMode == 7 && hdScale() > 1 && hdSupersample() == 1;
}
......@@ -111,9 +112,9 @@ auto PPUfast::refresh() -> void {
width = 256 << hires();
height = 240 << interlace();
} else {
if(!overscan()) output -= 7 * 256 * hdScale() * hdScale();
pitch = 256 * hdScale();
width = 256 * hdScale();
if(!overscan()) output -= 7 * (256+2*widescreen()) * hdScale() * hdScale();
pitch = (256+2*widescreen()) * hdScale();
width = (256+2*widescreen()) * hdScale();
height = 240 * hdScale();
}
Emulator::video.setEffect(Emulator::Video::Effect::ColorBleed, configuration.video.blurEmulation && hires());
......
......@@ -16,6 +16,7 @@ struct PPUfast : Thread, PPUcounter {
alwaysinline auto hdPerspective() const -> bool;
alwaysinline auto hdSupersample() const -> bool;
alwaysinline auto hdMosaic() const -> bool;
alwaysinline auto widescreen() const -> int;
//ppu.cpp
PPUfast();
......
......@@ -253,7 +253,8 @@ auto Presentation::resizeViewport() -> void {
uint layoutWidth = viewportLayout.geometry().width();
uint layoutHeight = viewportLayout.geometry().height();
uint width = 256 * (settings.video.aspectCorrection ? 8.0 / 7.0 : 1.0);
int widescreen = settings.emulator.hack.ppu.mode7.widescreen && settings.emulator.hack.ppu.mode7.scale > 1 ? 64 : 0; // 64 / 0 #widescreenextension
uint width = (256+2*widescreen) * (settings.video.aspectCorrection && !widescreen ? 8.0 / 7.0 : 1.0);
uint height = (settings.video.overscan ? 240.0 : 224.0);
uint viewportWidth, viewportHeight;
......@@ -274,7 +275,7 @@ auto Presentation::resizeViewport() -> void {
if(settings.video.output == "Center") {
uint widthMultiplier = layoutWidth / width;
uint heightMultiplier = layoutHeight / height;
uint heightMultiplier = layoutHeight / (height - 8); // allow the loss of 8 lines so 1080p can be 5x scale
uint multiplier = min(widthMultiplier, heightMultiplier);
viewportWidth = width * multiplier;
viewportHeight = height * multiplier;
......@@ -290,8 +291,8 @@ auto Presentation::resizeViewport() -> void {
}
//center viewport within viewportLayout by use of viewportLayout padding
uint paddingWidth = layoutWidth - viewportWidth;
uint paddingHeight = layoutHeight - viewportHeight;
int paddingWidth = layoutWidth - viewportWidth;
int paddingHeight = layoutHeight - viewportHeight;
viewportLayout.setPadding({
paddingWidth / 2, paddingHeight / 2,
paddingWidth - paddingWidth / 2, paddingHeight - paddingHeight / 2
......@@ -302,7 +303,8 @@ auto Presentation::resizeWindow() -> void {
if(fullScreen()) return;
if(maximized()) setMaximized(false);
uint width = 256 * (settings.video.aspectCorrection ? 8.0 / 7.0 : 1.0);
int widescreen = settings.emulator.hack.ppu.mode7.widescreen && settings.emulator.hack.ppu.mode7.scale > 1 ? 64 : 0; // 64 / 0 #widescreenextension
uint width = (256+2*widescreen) * (settings.video.aspectCorrection && !widescreen ? 8.0 / 7.0 : 1.0);
uint height = (settings.video.overscan ? 240.0 : 224.0);
uint multiplier = max(1, settings.video.multiplier);
uint statusHeight = settings.general.statusBar ? StatusHeight : 0;
......
......@@ -13,6 +13,7 @@ auto Program::hackCompatibility() -> void {
emulator->configure("Hacks/PPU/NoSpriteLimit", fastPPUNoSpriteLimit);
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/Widescreen", settings.emulator.hack.ppu.mode7.widescreen);
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
emulator->configure("Hacks/PPU/Mode7/Mosaic", settings.emulator.hack.ppu.mode7.mosaic);
emulator->configure("Hacks/DSP/Fast", fastDSP);
......
......@@ -66,11 +66,17 @@ auto EmulatorSettings::create() -> void {
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);
presentation.resizeViewport();
});
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);
});
mode7Widescreen.setText("Widescreen").setChecked(settings.emulator.hack.ppu.mode7.widescreen).onToggle([&] {
settings.emulator.hack.ppu.mode7.widescreen = mode7Widescreen.checked();
emulator->configure("Hacks/PPU/Mode7/Widescreen", settings.emulator.hack.ppu.mode7.widescreen);
presentation.resizeViewport();
});
mode7Supersample.setText("Supersample").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);
......@@ -109,6 +115,7 @@ auto EmulatorSettings::updateConfiguration() -> void {
emulator->configure("Hacks/PPU/NoSpriteLimit", noSpriteLimit.checked());
emulator->configure("Hacks/PPU/Mode7/Scale", mode7Scale.selected().property("multiplier").natural());
emulator->configure("Hacks/PPU/Mode7/Perspective", mode7Perspective.checked());
emulator->configure("Hacks/PPU/Mode7/Widescreen", mode7Widescreen.checked());
emulator->configure("Hacks/PPU/Mode7/Supersample", mode7Supersample.checked());
emulator->configure("Hacks/PPU/Mode7/Mosaic", mode7Mosaic.checked());
emulator->configure("Hacks/DSP/Fast", fastDSP.checked());
......
......@@ -99,6 +99,7 @@ auto Settings::process(bool load) -> void {
bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit);
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/Widescreen", emulator.hack.ppu.mode7.widescreen);
bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample);
bind(boolean, "Emulator/Hack/PPU/Mode7/Mosaic", emulator.hack.ppu.mode7.mosaic);
bind(boolean, "Emulator/Hack/DSP/Fast", emulator.hack.dsp.fast);
......
......@@ -81,6 +81,7 @@ struct Settings : Markup::Node {
struct Mode7 {
uint scale = 1;
bool perspective = true;
bool widescreen = true;
bool supersample = false;
bool mosaic = true;
} mode7;
......@@ -271,6 +272,7 @@ public:
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
ComboButton mode7Scale{&mode7Layout, Size{0, 0}};
CheckLabel mode7Perspective{&mode7Layout, Size{0, 0}};
CheckLabel mode7Widescreen{&mode7Layout, Size{0, 0}};
CheckLabel mode7Supersample{&mode7Layout, Size{0, 0}};
CheckLabel mode7Mosaic{&mode7Layout, Size{0, 0}};
Label dspLabel{&layout, Size{~0, 0}, 2};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment