mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-08-21 02:21:48 +02:00
v108.17
Enhanced perspective correction support [DerKoun]
This commit is contained in:
@@ -29,7 +29,7 @@ using namespace nall;
|
|||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "bsnes";
|
static const string Name = "bsnes";
|
||||||
static const string Version = "108.16";
|
static const string Version = "108.17";
|
||||||
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";
|
||||||
|
@@ -3,6 +3,7 @@ uint PPU::Line::count = 0;
|
|||||||
|
|
||||||
auto PPU::Line::flush() -> void {
|
auto PPU::Line::flush() -> void {
|
||||||
if(Line::count) {
|
if(Line::count) {
|
||||||
|
if(ppu.hdScale() > 1) cacheMode7HD();
|
||||||
#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++) {
|
||||||
if(ppu.deinterlace()) {
|
if(ppu.deinterlace()) {
|
||||||
|
@@ -16,8 +16,6 @@ auto PPU::Line::renderMode7(PPU::IO::Background& self, uint source) -> void {
|
|||||||
int hoffset = (int13)io.mode7.hoffset;
|
int hoffset = (int13)io.mode7.hoffset;
|
||||||
int voffset = (int13)io.mode7.voffset;
|
int voffset = (int13)io.mode7.voffset;
|
||||||
|
|
||||||
//if(source==Source::BG1&&y==1) print(a, " ", b, " ", c, " ", d, " ", hcenter, " ", vcenter, " ", hoffset, " ", voffset, "\n");
|
|
||||||
|
|
||||||
uint mosaicCounter = 1;
|
uint mosaicCounter = 1;
|
||||||
uint mosaicPalette = 0;
|
uint mosaicPalette = 0;
|
||||||
uint mosaicPriority = 0;
|
uint mosaicPriority = 0;
|
||||||
|
@@ -1,3 +1,100 @@
|
|||||||
|
//determine mode 7 line groups for perspective correction
|
||||||
|
auto PPU::Line::cacheMode7HD() -> void {
|
||||||
|
ppu.mode7LineGroups.count = 0;
|
||||||
|
if(ppu.hdPerspective()) {
|
||||||
|
#define isLineMode7(line) (line.io.bg1.tileMode == TileMode::Mode7 && !line.io.displayDisable && ( \
|
||||||
|
(line.io.bg1.aboveEnable || line.io.bg1.belowEnable) \
|
||||||
|
))
|
||||||
|
bool state = false;
|
||||||
|
uint y;
|
||||||
|
//find the moe 7 groups
|
||||||
|
for(y = 0; y < Line::count; y++) {
|
||||||
|
if(state != isLineMode7(ppu.lines[Line::start + y])) {
|
||||||
|
state = !state;
|
||||||
|
if(state) {
|
||||||
|
ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y;
|
||||||
|
} else {
|
||||||
|
ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y - 1;
|
||||||
|
//the lines at the edges of mode 7 groups may be erroneous, so start and end lines for interpolation are moved inside
|
||||||
|
int offset = (ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count]) / 8;
|
||||||
|
ppu.mode7LineGroups.startLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] + offset;
|
||||||
|
ppu.mode7LineGroups.endLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - offset;
|
||||||
|
ppu.mode7LineGroups.count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#undef isLineMode7
|
||||||
|
if(state) {
|
||||||
|
//close the last group if necessary
|
||||||
|
ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] = ppu.lines[Line::start + y].y - 1;
|
||||||
|
int offset = (ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count]) / 8;
|
||||||
|
ppu.mode7LineGroups.startLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.startLine[ppu.mode7LineGroups.count] + offset;
|
||||||
|
ppu.mode7LineGroups.endLerpLine[ppu.mode7LineGroups.count] = ppu.mode7LineGroups.endLine[ppu.mode7LineGroups.count] - offset;
|
||||||
|
ppu.mode7LineGroups.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//detect groups that do not have perspective
|
||||||
|
for(int i : range(ppu.mode7LineGroups.count)) {
|
||||||
|
int a = -1, b = -1, c = -1, d = -1; //the mode 7 scale factors of the current line
|
||||||
|
int aPrev = -1, bPrev = -1, cPrev = -1, dPrev = -1; //the mode 7 scale factors of the previous line
|
||||||
|
bool aVar = false, bVar = false, cVar = false, dVar = false; //has a varying value been found for the factors?
|
||||||
|
bool aInc = false, bInc = false, cInc = false, dInc = false; //has the variation been an increase or decrease?
|
||||||
|
for(y = ppu.mode7LineGroups.startLerpLine[i]; y <= ppu.mode7LineGroups.endLerpLine[i]; y++) {
|
||||||
|
a = ((int)((int16)(ppu.lines[y].io.mode7.a)));
|
||||||
|
b = ((int)((int16)(ppu.lines[y].io.mode7.b)));
|
||||||
|
c = ((int)((int16)(ppu.lines[y].io.mode7.c)));
|
||||||
|
d = ((int)((int16)(ppu.lines[y].io.mode7.d)));
|
||||||
|
//has the value of 'a' changed compared to the last line?
|
||||||
|
//(and is the factor larger than zero, which happens sometimes and seems to be game-specific, mostly at the edges of the screen)
|
||||||
|
if(aPrev > 0 && a > 0 && a != aPrev) {
|
||||||
|
if(!aVar) {
|
||||||
|
//if there has been no variation yet, store that there is one and store if it is an increase or decrease
|
||||||
|
aVar = true;
|
||||||
|
aInc = a > aPrev;
|
||||||
|
} else if(aInc != a > aPrev) {
|
||||||
|
//if there has been an increase and now we have a decrease, or vice versa, set the interpolation lines to -1
|
||||||
|
//to deactivate perspective correction for this group and stop analyzing it further
|
||||||
|
ppu.mode7LineGroups.startLerpLine[i] = -1;
|
||||||
|
ppu.mode7LineGroups.endLerpLine[i] = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(bPrev > 0 && b > 0 && b != bPrev) {
|
||||||
|
if(!bVar) {
|
||||||
|
bVar = true;
|
||||||
|
bInc = b > bPrev;
|
||||||
|
} else if(bInc != b > bPrev) {
|
||||||
|
ppu.mode7LineGroups.startLerpLine[i] = -1;
|
||||||
|
ppu.mode7LineGroups.endLerpLine[i] = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cPrev > 0 && c > 0 && c != cPrev) {
|
||||||
|
if(!cVar) {
|
||||||
|
cVar = true;
|
||||||
|
cInc = c > cPrev;
|
||||||
|
} else if(cInc != c > cPrev) {
|
||||||
|
ppu.mode7LineGroups.startLerpLine[i] = -1;
|
||||||
|
ppu.mode7LineGroups.endLerpLine[i] = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(dPrev > 0 && d > 0 && d != bPrev) {
|
||||||
|
if(!dVar) {
|
||||||
|
dVar = true;
|
||||||
|
dInc = d > dPrev;
|
||||||
|
} else if(dInc != d > dPrev) {
|
||||||
|
ppu.mode7LineGroups.startLerpLine[i] = -1;
|
||||||
|
ppu.mode7LineGroups.endLerpLine[i] = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
aPrev = a, bPrev = b, cPrev = c, dPrev = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto PPU::Line::renderMode7HD(PPU::IO::Background& self, uint source) -> void {
|
auto PPU::Line::renderMode7HD(PPU::IO::Background& self, uint source) -> void {
|
||||||
const bool extbg = source == Source::BG2;
|
const bool extbg = source == Source::BG2;
|
||||||
const uint scale = ppu.hdScale();
|
const uint scale = ppu.hdScale();
|
||||||
@@ -7,15 +104,25 @@ auto PPU::Line::renderMode7HD(PPU::IO::Background& self, uint source) -> void {
|
|||||||
Pixel* below = &this->below[-1];
|
Pixel* below = &this->below[-1];
|
||||||
|
|
||||||
//find the first and last scanline for interpolation
|
//find the first and last scanline for interpolation
|
||||||
int y_a = y;
|
int y_a = -1;
|
||||||
int y_b = y;
|
int y_b = -1;
|
||||||
#define isLineMode7(n) (ppu.lines[n].io.bg1.tileMode == TileMode::Mode7 && ( \
|
#define isLineMode7(n) (ppu.lines[n].io.bg1.tileMode == TileMode::Mode7 && !ppu.lines[n].io.displayDisable && ( \
|
||||||
(ppu.lines[n].io.bg1.aboveEnable || ppu.lines[n].io.bg1.belowEnable) \
|
(ppu.lines[n].io.bg1.aboveEnable || ppu.lines[n].io.bg1.belowEnable) \
|
||||||
))
|
))
|
||||||
if(ppu.hdPerspective()) {
|
if(ppu.hdPerspective()) {
|
||||||
while(y_a > 1 && isLineMode7(y_a)) y_a--; y_a += 1;
|
//find the mode 7 line group this line is in and use its interpolation lines
|
||||||
while(y_b < 239 && isLineMode7(y_b)) y_b++; y_b -= 8;
|
for(int i : range(ppu.mode7LineGroups.count)) {
|
||||||
} else {
|
if(y >= ppu.mode7LineGroups.startLine[i] && y <= ppu.mode7LineGroups.endLine[i]) {
|
||||||
|
y_a = ppu.mode7LineGroups.startLerpLine[i];
|
||||||
|
y_b = ppu.mode7LineGroups.endLerpLine[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(y_a == -1 || y_b == -1) {
|
||||||
|
//if perspective correction is disabled or the group was detected as non-perspective, use the neighboring lines
|
||||||
|
y_a = y;
|
||||||
|
y_b = y;
|
||||||
if(y_a > 1 && isLineMode7(y_a)) y_a--;
|
if(y_a > 1 && isLineMode7(y_a)) y_a--;
|
||||||
if(y_b < 239 && isLineMode7(y_b)) y_b++;
|
if(y_b < 239 && isLineMode7(y_b)) y_b++;
|
||||||
}
|
}
|
||||||
|
@@ -265,7 +265,7 @@ public:
|
|||||||
auto readObject(uint10 address) -> uint8;
|
auto readObject(uint10 address) -> uint8;
|
||||||
auto writeObject(uint10 address, uint8 data) -> void;
|
auto writeObject(uint10 address, uint8 data) -> void;
|
||||||
|
|
||||||
//[serialized]
|
//serialized:
|
||||||
Latch latch;
|
Latch latch;
|
||||||
IO io;
|
IO io;
|
||||||
|
|
||||||
@@ -303,6 +303,7 @@ public:
|
|||||||
auto renderMode7(PPU::IO::Background&, uint source) -> void;
|
auto renderMode7(PPU::IO::Background&, uint source) -> void;
|
||||||
|
|
||||||
//mode7hd.cpp
|
//mode7hd.cpp
|
||||||
|
static auto cacheMode7HD() -> void;
|
||||||
auto renderMode7HD(PPU::IO::Background&, uint source) -> void;
|
auto renderMode7HD(PPU::IO::Background&, uint source) -> void;
|
||||||
alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float;
|
alwaysinline auto lerp(float pa, float va, float pb, float vb, float pr) -> float;
|
||||||
|
|
||||||
@@ -313,7 +314,7 @@ public:
|
|||||||
auto renderWindow(PPU::IO::WindowLayer&, bool enable, bool output[256]) -> void;
|
auto renderWindow(PPU::IO::WindowLayer&, bool enable, bool output[256]) -> void;
|
||||||
auto renderWindow(PPU::IO::WindowColor&, uint mask, bool output[256]) -> void;
|
auto renderWindow(PPU::IO::WindowColor&, uint mask, bool output[256]) -> void;
|
||||||
|
|
||||||
//[unserialized]
|
//unserialized:
|
||||||
uint y; //constant
|
uint y; //constant
|
||||||
bool fieldID;
|
bool fieldID;
|
||||||
|
|
||||||
@@ -333,6 +334,8 @@ public:
|
|||||||
static uint start;
|
static uint start;
|
||||||
static uint count;
|
static uint count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//unserialized:
|
||||||
Line lines[240];
|
Line lines[240];
|
||||||
|
|
||||||
//used to help detect when the video output size changes between frames to clear overscan area.
|
//used to help detect when the video output size changes between frames to clear overscan area.
|
||||||
@@ -341,6 +344,14 @@ public:
|
|||||||
uint width = 0;
|
uint width = 0;
|
||||||
uint height = 0;
|
uint height = 0;
|
||||||
} frame;
|
} frame;
|
||||||
|
|
||||||
|
struct Mode7LineGroups {
|
||||||
|
int count = -1;
|
||||||
|
int startLine[32];
|
||||||
|
int endLine[32];
|
||||||
|
int startLerpLine[32];
|
||||||
|
int endLerpLine[32];
|
||||||
|
} mode7LineGroups;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PPU ppufast;
|
extern PPU ppufast;
|
||||||
|
Reference in New Issue
Block a user