mirror of https://github.com/bsnes-emu/bsnes.git
parent
46dbe00f14
commit
252f479b22
|
@ -30,7 +30,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "bsnes";
|
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 Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org";
|
static const string Website = "https://byuu.org";
|
||||||
|
|
|
@ -19,6 +19,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
|
||||||
bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
|
bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
|
||||||
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast);
|
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast);
|
||||||
bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit);
|
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(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale);
|
||||||
bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective);
|
bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective);
|
||||||
bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample);
|
bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample);
|
||||||
|
|
|
@ -30,7 +30,8 @@ struct Configuration {
|
||||||
} cpu;
|
} cpu;
|
||||||
struct PPU {
|
struct PPU {
|
||||||
bool fast = true;
|
bool fast = true;
|
||||||
bool noSpriteLimit = false;
|
bool noSpriteLimit = true;
|
||||||
|
bool deinterlace = true;
|
||||||
struct Mode7 {
|
struct Mode7 {
|
||||||
uint scale = 1;
|
uint scale = 1;
|
||||||
bool perspective = true;
|
bool perspective = true;
|
||||||
|
|
|
@ -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);
|
uint y = this->y - (self.mosaicEnable ? this->y % (1 + io.mosaicSize) : 0);
|
||||||
if(hires) {
|
if(hires) {
|
||||||
hscroll <<= 1;
|
hscroll <<= 1;
|
||||||
if(io.interlace) y = y << 1 | ppu.field();
|
if(io.interlace) y = y << 1 | field();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint mosaicCounter = 1;
|
uint mosaicCounter = 1;
|
||||||
|
|
|
@ -5,21 +5,34 @@ auto PPU::Line::flush() -> void {
|
||||||
if(Line::count) {
|
if(Line::count) {
|
||||||
#pragma omp parallel for if(Line::count >= 8)
|
#pragma omp parallel for if(Line::count >= 8)
|
||||||
for(uint y = 0; y < Line::count; y++) {
|
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::start = 0;
|
||||||
Line::count = 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);
|
uint y = this->y + (!ppu.latch.overscan ? 7 : 0);
|
||||||
|
|
||||||
auto hd = ppu.hd();
|
auto hd = ppu.hd();
|
||||||
auto ss = ppu.ss();
|
auto ss = ppu.ss();
|
||||||
auto scale = ppu.hdScale();
|
auto scale = ppu.hdScale();
|
||||||
auto output = ppu.output + (!hd
|
auto output = ppu.output + (!hd
|
||||||
? (y * 1024 + (ppu.interlace() && ppu.field() ? 512 : 0))
|
? (y * 1024 + (ppu.interlace() && field() ? 512 : 0))
|
||||||
: (y * 256 * scale * scale)
|
: (y * 256 * scale * scale)
|
||||||
);
|
);
|
||||||
auto width = (!hd
|
auto width = (!hd
|
||||||
|
@ -34,8 +47,8 @@ auto PPU::Line::render() -> void {
|
||||||
bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6;
|
bool hires = io.pseudoHires || io.bgMode == 5 || io.bgMode == 6;
|
||||||
auto aboveColor = cgram[0];
|
auto aboveColor = cgram[0];
|
||||||
auto belowColor = hires ? cgram[0] : io.col.fixedColor;
|
auto belowColor = hires ? cgram[0] : io.col.fixedColor;
|
||||||
uint xa = (hd || ss) && ppu.interlace() && ppu.field() ? 256 * scale * scale / 2 : 0;
|
uint xa = (hd || ss) && ppu.interlace() && field() ? 256 * scale * scale / 2 : 0;
|
||||||
uint xb = !(hd || ss) ? 256 : ppu.interlace() && !ppu.field() ? 256 * scale * scale / 2 : 256 * scale * scale;
|
uint xb = !(hd || ss) ? 256 : ppu.interlace() && !field() ? 256 * scale * scale / 2 : 256 * scale * scale;
|
||||||
for(uint x = xa; x < xb; x++) {
|
for(uint x = xa; x < xb; x++) {
|
||||||
above[x] = {Source::COL, 0, aboveColor};
|
above[x] = {Source::COL, 0, aboveColor};
|
||||||
below[x] = {Source::COL, 0, belowColor};
|
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 PPU::Line::plotHD(Pixel* pixel, uint x, uint source, uint priority, uint color, bool hires, bool subpixel) -> void {
|
||||||
auto scale = ppu.hdScale();
|
auto scale = ppu.hdScale();
|
||||||
int xss = hires && subpixel ? scale / 2 : 0;
|
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) {
|
if(priority > pixel[x * scale + xss + ys * 256 * scale].priority) {
|
||||||
Pixel p = {source, priority, color};
|
Pixel p = {source, priority, color};
|
||||||
int xsm = hires && !subpixel ? scale / 2 : scale;
|
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++) {
|
for(int xs = xss; xs < xsm; xs++) {
|
||||||
pixel[x * scale + xs + ys * 256 * scale] = p;
|
pixel[x * scale + xs + ys * 256 * scale] = p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(self.interlace) {
|
if(self.interlace) {
|
||||||
y = !object.vflip ? y + ppu.field() : y - ppu.field();
|
y = !object.vflip ? y + field() : y - field();
|
||||||
}
|
}
|
||||||
|
|
||||||
x &= 511;
|
x &= 511;
|
||||||
|
|
|
@ -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::hdPerspective() const -> bool { return configuration.hacks.ppu.mode7.perspective; }
|
||||||
auto PPU::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; }
|
auto PPU::hdSupersample() const -> bool { return configuration.hacks.ppu.mode7.supersample; }
|
||||||
auto PPU::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; }
|
auto PPU::hdMosaic() const -> bool { return configuration.hacks.ppu.mode7.mosaic; }
|
||||||
|
auto PPU::deinterlace() const -> bool { return configuration.hacks.ppu.deinterlace; }
|
||||||
#define ppu ppufast
|
#define ppu ppufast
|
||||||
|
|
||||||
PPU::PPU() {
|
PPU::PPU() {
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct PPU : PPUcounter {
|
||||||
alwaysinline auto hdPerspective() const -> bool;
|
alwaysinline auto hdPerspective() const -> bool;
|
||||||
alwaysinline auto hdSupersample() const -> bool;
|
alwaysinline auto hdSupersample() const -> bool;
|
||||||
alwaysinline auto hdMosaic() const -> bool;
|
alwaysinline auto hdMosaic() const -> bool;
|
||||||
|
alwaysinline auto deinterlace() const -> bool;
|
||||||
|
|
||||||
//ppu.cpp
|
//ppu.cpp
|
||||||
PPU();
|
PPU();
|
||||||
|
@ -278,8 +279,9 @@ public:
|
||||||
|
|
||||||
struct Line {
|
struct Line {
|
||||||
//line.cpp
|
//line.cpp
|
||||||
|
inline auto field() const -> bool { return fieldID; }
|
||||||
static auto flush() -> void;
|
static auto flush() -> void;
|
||||||
auto render() -> void;
|
auto render(bool field) -> void;
|
||||||
auto pixel(uint x, Pixel above, Pixel below) const -> uint16;
|
auto pixel(uint x, Pixel above, Pixel below) const -> uint16;
|
||||||
auto blend(uint x, uint y, bool halve) const -> uint16;
|
auto blend(uint x, uint y, bool halve) const -> uint16;
|
||||||
alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint16;
|
alwaysinline auto directColor(uint paletteIndex, uint paletteColor) const -> uint16;
|
||||||
|
@ -307,6 +309,7 @@ public:
|
||||||
|
|
||||||
//[unserialized]
|
//[unserialized]
|
||||||
uint y; //constant
|
uint y; //constant
|
||||||
|
bool fieldID;
|
||||||
|
|
||||||
IO io;
|
IO io;
|
||||||
uint16 cgram[256];
|
uint16 cgram[256];
|
||||||
|
|
|
@ -4,6 +4,7 @@ auto Program::load() -> void {
|
||||||
emulator->configure("Hacks/CPU/Overclock", settings.emulator.hack.cpu.overclock);
|
emulator->configure("Hacks/CPU/Overclock", settings.emulator.hack.cpu.overclock);
|
||||||
emulator->configure("Hacks/PPU/Fast", settings.emulator.hack.ppu.fast);
|
emulator->configure("Hacks/PPU/Fast", settings.emulator.hack.ppu.fast);
|
||||||
emulator->configure("Hacks/PPU/NoSpriteLimit", settings.emulator.hack.ppu.noSpriteLimit);
|
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/Scale", settings.emulator.hack.ppu.mode7.scale);
|
||||||
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
|
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
|
||||||
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
|
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
|
||||||
|
|
|
@ -26,14 +26,22 @@ auto EmulatorSettings::create() -> void {
|
||||||
fastPPU.setText("Fast mode").setChecked(settings.emulator.hack.ppu.fast).onToggle([&] {
|
fastPPU.setText("Fast mode").setChecked(settings.emulator.hack.ppu.fast).onToggle([&] {
|
||||||
settings.emulator.hack.ppu.fast = fastPPU.checked();
|
settings.emulator.hack.ppu.fast = fastPPU.checked();
|
||||||
if(!fastPPU.checked()) {
|
if(!fastPPU.checked()) {
|
||||||
noSpriteLimit.setEnabled(false).setChecked(false).doToggle();
|
noSpriteLimit.setEnabled(false);
|
||||||
|
deinterlace.setEnabled(false);
|
||||||
|
mode7Layout.setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
noSpriteLimit.setEnabled(true);
|
noSpriteLimit.setEnabled(true);
|
||||||
|
deinterlace.setEnabled(true);
|
||||||
|
mode7Layout.setEnabled(true);
|
||||||
}
|
}
|
||||||
}).doToggle();
|
}).doToggle();
|
||||||
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
|
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
|
||||||
settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked();
|
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());
|
mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold());
|
||||||
mode7ScaleLabel.setText("Scale:");
|
mode7ScaleLabel.setText("Scale:");
|
||||||
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1));
|
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1));
|
||||||
|
|
|
@ -112,6 +112,7 @@ auto Settings::process(bool load) -> void {
|
||||||
bind(natural, "Emulator/Hack/CPU/Overclock", emulator.hack.cpu.overclock);
|
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/Fast", emulator.hack.ppu.fast);
|
||||||
bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit);
|
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(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/Perspective", emulator.hack.ppu.mode7.perspective);
|
||||||
bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample);
|
bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample);
|
||||||
|
|
|
@ -97,7 +97,8 @@ struct Settings : Markup::Node {
|
||||||
} cpu;
|
} cpu;
|
||||||
struct PPU {
|
struct PPU {
|
||||||
bool fast = true;
|
bool fast = true;
|
||||||
bool noSpriteLimit = false;
|
bool noSpriteLimit = true;
|
||||||
|
bool deinterlace = true;
|
||||||
struct Mode7 {
|
struct Mode7 {
|
||||||
uint scale = 1;
|
uint scale = 1;
|
||||||
bool perspective = true;
|
bool perspective = true;
|
||||||
|
@ -330,6 +331,7 @@ public:
|
||||||
HorizontalLayout ppuLayout{this, Size{~0, 0}};
|
HorizontalLayout ppuLayout{this, Size{~0, 0}};
|
||||||
CheckLabel fastPPU{&ppuLayout, Size{0, 0}};
|
CheckLabel fastPPU{&ppuLayout, Size{0, 0}};
|
||||||
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
|
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
|
||||||
|
CheckLabel deinterlace{&ppuLayout, Size{0, 0}};
|
||||||
Label mode7Label{this, Size{~0, 0}, 2};
|
Label mode7Label{this, Size{~0, 0}, 2};
|
||||||
HorizontalLayout mode7Layout{this, Size{~0, 0}};
|
HorizontalLayout mode7Layout{this, Size{~0, 0}};
|
||||||
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
|
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
|
||||||
|
|
Loading…
Reference in New Issue