bsnes/higan/ws/ppu/render.cpp

115 lines
3.9 KiB
C++

auto PPU::renderFetch(uint10 tile, uint3 y, uint3 x) -> uint4 {
uint16 offset = 0x200 + tile << (4 + system.depth());
uint4 color = 0;
if(system.planar()) {
if(!system.depth()) {
uint16 data = iram.read(offset + (y << 1), Word);
color |= data.bit( 7 - x) << 0;
color |= data.bit(15 - x) << 1;
} else {
uint32 data = iram.read(offset + (y << 2), Long);
color |= data.bit( 7 - x) << 0;
color |= data.bit(15 - x) << 1;
color |= data.bit(23 - x) << 2;
color |= data.bit(31 - x) << 3;
}
}
if(system.packed()) {
if(!system.depth()) {
uint8 data = iram.read(offset + (y << 1) + (x >> 2));
color = data >> (6 - (x.bits(0,1) << 1));
color = color.bits(0,1);
} else {
uint8 data = iram.read(offset + (y << 2) + (x >> 1));
color = data >> (4 - (x.bit(0) << 2));
}
}
return color;
}
auto PPU::renderTransparent(bool palette, uint4 color) -> bool {
if(color) return false;
if(!system.depth() && !palette) return false;
return true;
}
auto PPU::renderPalette(uint4 palette, uint4 color) -> uint12 {
if(!system.color()) {
uint3 paletteColor = r.palette[palette].color[color.bits(0,1)];
uint4 poolColor = 15 - r.pool[paletteColor];
return poolColor << 0 | poolColor << 4 | poolColor << 8;
} else {
return iram.read(0xfe00 + (palette << 5) + (color << 1), Word);
}
}
auto PPU::renderBack() -> void {
if(!system.color()) {
uint4 poolColor = 15 - r.pool[l.backColor.bits(0,2)];
s.pixel = {Pixel::Source::Back, poolColor << 0 | poolColor << 4 | poolColor << 8};
} else {
uint12 color = iram.read(0xfe00 + (l.backColor << 1), Word);
s.pixel = {Pixel::Source::Back, color};
}
}
auto PPU::renderScreenOne() -> void {
uint8 scrollY = s.vclk + l.scrollOneY;
uint8 scrollX = s.hclk + l.scrollOneX;
uint16 tilemapOffset = l.screenOneMapBase.bits(0, 2 + system.depth()) << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint3 tileY = scrollY ^ tile.bit(15) * 7;
uint3 tileX = scrollX ^ tile.bit(14) * 7;
uint4 tileColor = renderFetch(tile.bit(13) << 9 | tile.bits(0,8), tileY, tileX);
if(renderTransparent(tile.bit(11), tileColor)) return;
s.pixel = {Pixel::Source::ScreenOne, renderPalette(tile.bits(9,12), tileColor)};
}
auto PPU::renderScreenTwo() -> void {
bool windowInside = s.vclk >= l.screenTwoWindowY0 && s.vclk <= l.screenTwoWindowY1
&& s.hclk >= l.screenTwoWindowX0 && s.hclk <= l.screenTwoWindowX1;
windowInside ^= l.screenTwoWindowInvert;
if(l.screenTwoWindowEnable && !windowInside) return;
uint8 scrollY = s.vclk + l.scrollTwoY;
uint8 scrollX = s.hclk + l.scrollTwoX;
uint16 tilemapOffset = l.screenTwoMapBase.bits(0, 2 + system.depth()) << 11;
tilemapOffset += (scrollY >> 3) << 6;
tilemapOffset += (scrollX >> 3) << 1;
uint16 tile = iram.read(tilemapOffset, Word);
uint3 tileY = scrollY ^ tile.bit(15) * 7;
uint3 tileX = scrollX ^ tile.bit(14) * 7;
uint4 tileColor = renderFetch(tile.bit(13) << 9 | tile.bits(0,8), tileY, tileX);
if(renderTransparent(tile.bit(11), tileColor)) return;
s.pixel = {Pixel::Source::ScreenTwo, renderPalette(tile.bits(9,12), tileColor)};
}
auto PPU::renderSprite() -> void {
bool windowInside = s.hclk >= l.spriteWindowX0 && s.hclk <= l.spriteWindowY0;
for(auto index : range(l.spriteCount)) {
auto& sprite = l.sprite[index];
if(l.spriteWindowEnable && !sprite.window && !windowInside) continue;
if((uint8)(s.hclk - sprite.x) > 7) continue;
uint3 tileY = (s.vclk - sprite.y) ^ sprite.vflip * 7;
uint3 tileX = (s.hclk - sprite.x) ^ sprite.hflip * 7;
uint4 tileColor = renderFetch(sprite.tile, tileY, tileX);
if(renderTransparent(sprite.palette.bit(2), tileColor)) continue;
if(!sprite.priority && s.pixel.source == Pixel::Source::ScreenTwo) continue;
s.pixel = {Pixel::Source::Sprite, renderPalette(sprite.palette, tileColor)};
break;
}
}