mirror of https://github.com/bsnes-emu/bsnes.git
179 lines
6.3 KiB
C++
179 lines
6.3 KiB
C++
auto PPU::Screen::scanline() -> void {
|
|
lineA = ppu.output + ppu.vcounter() * 1024;
|
|
lineB = lineA + (ppu.display.interlace ? 0 : 512);
|
|
if(ppu.display.interlace && ppu.field()) lineA += 512, lineB += 512;
|
|
|
|
//the first hires pixel of each scanline is transparent
|
|
//note: exact value initializations are not confirmed on hardware
|
|
math.above.color = paletteColor(0);
|
|
math.below.color = math.above.color;
|
|
|
|
math.above.colorEnable = !(ppu.window.r.col.aboveMask & 1);
|
|
math.below.colorEnable = !(ppu.window.r.col.belowMask & 1) && r.back.colorEnable;
|
|
|
|
math.transparent = true;
|
|
math.blendMode = false;
|
|
math.colorHalve = r.colorHalve && !r.blendMode && math.above.colorEnable;
|
|
}
|
|
|
|
auto PPU::Screen::run() -> void {
|
|
if(ppu.vcounter() == 0) return;
|
|
|
|
bool hires = ppu.r.pseudoHires || ppu.r.bgMode == 5 || ppu.r.bgMode == 6;
|
|
auto belowColor = below(hires);
|
|
auto aboveColor = above();
|
|
|
|
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (hires ? belowColor : aboveColor);
|
|
*lineA++ = *lineB++ = ppu.r.displayBrightness << 15 | (aboveColor);
|
|
}
|
|
|
|
auto PPU::Screen::below(bool hires) -> uint16 {
|
|
if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0;
|
|
|
|
uint priority = 0;
|
|
if(ppu.bg1.output.below.priority) {
|
|
priority = ppu.bg1.output.below.priority;
|
|
if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) {
|
|
math.below.color = directColor(ppu.bg1.output.below.palette, ppu.bg1.output.below.tile);
|
|
} else {
|
|
math.below.color = paletteColor(ppu.bg1.output.below.palette);
|
|
}
|
|
}
|
|
if(ppu.bg2.output.below.priority > priority) {
|
|
priority = ppu.bg2.output.below.priority;
|
|
math.below.color = paletteColor(ppu.bg2.output.below.palette);
|
|
}
|
|
if(ppu.bg3.output.below.priority > priority) {
|
|
priority = ppu.bg3.output.below.priority;
|
|
math.below.color = paletteColor(ppu.bg3.output.below.palette);
|
|
}
|
|
if(ppu.bg4.output.below.priority > priority) {
|
|
priority = ppu.bg4.output.below.priority;
|
|
math.below.color = paletteColor(ppu.bg4.output.below.palette);
|
|
}
|
|
if(ppu.oam.output.below.priority > priority) {
|
|
priority = ppu.oam.output.below.priority;
|
|
math.below.color = paletteColor(ppu.oam.output.below.palette);
|
|
}
|
|
if(math.transparent = (priority == 0)) math.below.color = paletteColor(0);
|
|
|
|
if(!hires) return 0;
|
|
if(!math.below.colorEnable) return math.above.colorEnable ? math.below.color : (uint16)0;
|
|
|
|
return blend(
|
|
math.above.colorEnable ? math.below.color : (uint16)0,
|
|
math.blendMode ? math.above.color : fixedColor()
|
|
);
|
|
}
|
|
|
|
auto PPU::Screen::above() -> uint16 {
|
|
if(ppu.r.displayDisable || (!ppu.r.overscan && ppu.vcounter() >= 225)) return 0;
|
|
|
|
uint priority = 0;
|
|
if(ppu.bg1.output.above.priority) {
|
|
priority = ppu.bg1.output.above.priority;
|
|
if(r.directColor && (ppu.r.bgMode == 3 || ppu.r.bgMode == 4 || ppu.r.bgMode == 7)) {
|
|
math.above.color = directColor(ppu.bg1.output.above.palette, ppu.bg1.output.above.tile);
|
|
} else {
|
|
math.above.color = paletteColor(ppu.bg1.output.above.palette);
|
|
}
|
|
math.below.colorEnable = r.bg1.colorEnable;
|
|
}
|
|
if(ppu.bg2.output.above.priority > priority) {
|
|
priority = ppu.bg2.output.above.priority;
|
|
math.above.color = paletteColor(ppu.bg2.output.above.palette);
|
|
math.below.colorEnable = r.bg2.colorEnable;
|
|
}
|
|
if(ppu.bg3.output.above.priority > priority) {
|
|
priority = ppu.bg3.output.above.priority;
|
|
math.above.color = paletteColor(ppu.bg3.output.above.palette);
|
|
math.below.colorEnable = r.bg3.colorEnable;
|
|
}
|
|
if(ppu.bg4.output.above.priority > priority) {
|
|
priority = ppu.bg4.output.above.priority;
|
|
math.above.color = paletteColor(ppu.bg4.output.above.palette);
|
|
math.below.colorEnable = r.bg4.colorEnable;
|
|
}
|
|
if(ppu.oam.output.above.priority > priority) {
|
|
priority = ppu.oam.output.above.priority;
|
|
math.above.color = paletteColor(ppu.oam.output.above.palette);
|
|
math.below.colorEnable = r.oam.colorEnable && ppu.oam.output.above.palette >= 192;
|
|
}
|
|
if(priority == 0) {
|
|
math.above.color = paletteColor(0);
|
|
math.below.colorEnable = r.back.colorEnable;
|
|
}
|
|
|
|
if(!ppu.window.output.below.colorEnable) math.below.colorEnable = false;
|
|
math.above.colorEnable = ppu.window.output.above.colorEnable;
|
|
if(!math.below.colorEnable) return math.above.colorEnable ? math.above.color : (uint16)0;
|
|
|
|
if(r.blendMode && math.transparent) {
|
|
math.blendMode = false;
|
|
math.colorHalve = false;
|
|
} else {
|
|
math.blendMode = r.blendMode;
|
|
math.colorHalve = r.colorHalve && math.above.colorEnable;
|
|
}
|
|
|
|
return blend(
|
|
math.above.colorEnable ? math.above.color : (uint16)0,
|
|
math.blendMode ? math.below.color : fixedColor()
|
|
);
|
|
}
|
|
|
|
auto PPU::Screen::blend(uint x, uint y) const -> uint16 {
|
|
if(!r.colorMode) {
|
|
if(!math.colorHalve) {
|
|
uint sum = x + y;
|
|
uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420;
|
|
return (sum - carry) | (carry - (carry >> 5));
|
|
} else {
|
|
return (x + y - ((x ^ y) & 0x0421)) >> 1;
|
|
}
|
|
} else {
|
|
uint diff = x - y + 0x8420;
|
|
uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420;
|
|
if(!math.colorHalve) {
|
|
return (diff - borrow) & (borrow - (borrow >> 5));
|
|
} else {
|
|
return (((diff - borrow) & (borrow - (borrow >> 5))) & 0x7bde) >> 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
auto PPU::Screen::paletteColor(uint palette) const -> uint16 {
|
|
palette <<= 1;
|
|
ppu.latch.cgramAddress = palette;
|
|
return ppu.memory.cgram[palette + 0] + (ppu.memory.cgram[palette + 1] << 8);
|
|
}
|
|
|
|
auto PPU::Screen::directColor(uint palette, uint tile) const -> uint16 {
|
|
//palette = -------- BBGGGRRR
|
|
//tile = ---bgr-- --------
|
|
//output = 0BBb00GG Gg0RRRr0
|
|
return ((palette << 7) & 0x6000) + ((tile >> 0) & 0x1000)
|
|
+ ((palette << 4) & 0x0380) + ((tile >> 5) & 0x0040)
|
|
+ ((palette << 2) & 0x001c) + ((tile >> 9) & 0x0002);
|
|
}
|
|
|
|
auto PPU::Screen::fixedColor() const -> uint16 {
|
|
return r.colorBlue << 10 | r.colorGreen << 5 | r.colorRed << 0;
|
|
}
|
|
|
|
auto PPU::Screen::reset() -> void {
|
|
r.blendMode = random(false);
|
|
r.directColor = random(false);
|
|
r.colorMode = random(false);
|
|
r.colorHalve = random(false);
|
|
r.bg1.colorEnable = random(false);
|
|
r.bg2.colorEnable = random(false);
|
|
r.bg3.colorEnable = random(false);
|
|
r.bg4.colorEnable = random(false);
|
|
r.oam.colorEnable = random(false);
|
|
r.back.colorEnable = random(false);
|
|
r.colorBlue = random(0);
|
|
r.colorGreen = random(0);
|
|
r.colorRed = random(0);
|
|
}
|