bsnes/higan/sfc/ppu/background/mode7.cpp

104 lines
2.5 KiB
C++

auto PPU::Background::clip(int n) -> int {
//13-bit sign extend: --s---nnnnnnnnnn -> ssssssnnnnnnnnnn
return n & 0x2000 ? (n | ~1023) : (n & 1023);
}
//H = 28
auto PPU::Background::beginMode7() -> void {
latch.hoffset = ppu.r.hoffsetMode7;
latch.voffset = ppu.r.voffsetMode7;
}
auto PPU::Background::runMode7() -> void {
int a = (int16)ppu.r.m7a;
int b = (int16)ppu.r.m7b;
int c = (int16)ppu.r.m7c;
int d = (int16)ppu.r.m7d;
int cx = (int13)ppu.r.m7x;
int cy = (int13)ppu.r.m7y;
int hoffset = (int13)latch.hoffset;
int voffset = (int13)latch.voffset;
if(Background::x++ & ~255) return;
uint x = mosaic.hoffset;
uint y = ppu.bg1.mosaic.voffset; //BG2 vertical mosaic uses BG1 mosaic size
if(--mosaic.hcounter == 0) {
mosaic.hcounter = r.mosaic + 1;
mosaic.hoffset += r.mosaic + 1;
}
if(ppu.r.hflipMode7) x = 255 - x;
if(ppu.r.vflipMode7) y = 255 - y;
int psx = ((a * clip(hoffset - cx)) & ~63) + ((b * clip(voffset - cy)) & ~63) + ((b * y) & ~63) + (cx << 8);
int psy = ((c * clip(hoffset - cx)) & ~63) + ((d * clip(voffset - cy)) & ~63) + ((d * y) & ~63) + (cy << 8);
int px = psx + (a * x);
int py = psy + (c * x);
//mask pseudo-FP bits
px >>= 8;
py >>= 8;
uint tile;
uint palette;
switch(ppu.r.repeatMode7) {
//screen repetition outside of screen area
case 0:
case 1:
px &= 1023;
py &= 1023;
tile = ppu.vram[(py >> 3) * 128 + (px >> 3)].byte(0);
palette = ppu.vram[(tile << 6) + ((py & 7) << 3) + (px & 7)].byte(1);
break;
//palette color 0 outside of screen area
case 2:
if((px | py) & ~1023) {
palette = 0;
} else {
px &= 1023;
py &= 1023;
tile = ppu.vram[(py >> 3) * 128 + (px >> 3)].byte(0);
palette = ppu.vram[(tile << 6) + ((py & 7) << 3) + (px & 7)].byte(1);
}
break;
//character 0 repetition outside of screen area
case 3:
if((px | py) & ~1023) {
tile = 0;
} else {
px &= 1023;
py &= 1023;
tile = ppu.vram[(py >> 3) * 128 + (px >> 3)].byte(0);
}
palette = ppu.vram[(tile << 6) + ((py & 7) << 3) + (px & 7)].byte(1);
break;
}
uint priority;
if(id == ID::BG1) {
priority = r.priority[0];
} else if(id == ID::BG2) {
priority = r.priority[bool(palette & 0x80)];
palette &= 0x7f;
}
if(palette == 0) return;
if(r.aboveEnable) {
output.above.palette = palette;
output.above.priority = priority;
output.above.tile = 0;
}
if(r.belowEnable) {
output.below.palette = palette;
output.below.priority = priority;
output.below.tile = 0;
}
}