mirror of https://github.com/bsnes-emu/bsnes.git
v108.17
Enhanced perspective correction support [DerKoun]
This commit is contained in:
parent
90f094b931
commit
1195c46ac0
|
@ -29,7 +29,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
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 License = "GPLv3";
|
||||
static const string Website = "https://byuu.org";
|
||||
|
|
|
@ -3,6 +3,7 @@ uint PPU::Line::count = 0;
|
|||
|
||||
auto PPU::Line::flush() -> void {
|
||||
if(Line::count) {
|
||||
if(ppu.hdScale() > 1) cacheMode7HD();
|
||||
#pragma omp parallel for if(Line::count >= 8)
|
||||
for(uint y = 0; y < Line::count; y++) {
|
||||
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 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 mosaicPalette = 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 {
|
||||
const bool extbg = source == Source::BG2;
|
||||
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];
|
||||
|
||||
//find the first and last scanline for interpolation
|
||||
int y_a = y;
|
||||
int y_b = y;
|
||||
#define isLineMode7(n) (ppu.lines[n].io.bg1.tileMode == TileMode::Mode7 && ( \
|
||||
int y_a = -1;
|
||||
int y_b = -1;
|
||||
#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) \
|
||||
))
|
||||
if(ppu.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;
|
||||
} else {
|
||||
//find the mode 7 line group this line is in and use its interpolation lines
|
||||
for(int i : range(ppu.mode7LineGroups.count)) {
|
||||
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_b < 239 && isLineMode7(y_b)) y_b++;
|
||||
}
|
||||
|
|
|
@ -265,7 +265,7 @@ public:
|
|||
auto readObject(uint10 address) -> uint8;
|
||||
auto writeObject(uint10 address, uint8 data) -> void;
|
||||
|
||||
//[serialized]
|
||||
//serialized:
|
||||
Latch latch;
|
||||
IO io;
|
||||
|
||||
|
@ -303,6 +303,7 @@ public:
|
|||
auto renderMode7(PPU::IO::Background&, uint source) -> void;
|
||||
|
||||
//mode7hd.cpp
|
||||
static auto cacheMode7HD() -> void;
|
||||
auto renderMode7HD(PPU::IO::Background&, uint source) -> void;
|
||||
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::WindowColor&, uint mask, bool output[256]) -> void;
|
||||
|
||||
//[unserialized]
|
||||
//unserialized:
|
||||
uint y; //constant
|
||||
bool fieldID;
|
||||
|
||||
|
@ -333,6 +334,8 @@ public:
|
|||
static uint start;
|
||||
static uint count;
|
||||
};
|
||||
|
||||
//unserialized:
|
||||
Line lines[240];
|
||||
|
||||
//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 height = 0;
|
||||
} frame;
|
||||
|
||||
struct Mode7LineGroups {
|
||||
int count = -1;
|
||||
int startLine[32];
|
||||
int endLine[32];
|
||||
int startLerpLine[32];
|
||||
int endLerpLine[32];
|
||||
} mode7LineGroups;
|
||||
};
|
||||
|
||||
extern PPU ppufast;
|
||||
|
|
Loading…
Reference in New Issue