Path: blob/master/libsnes/bsnes/snes/ppu/sprite/sprite.cpp
2 views
#ifdef PPU_CPP12#include "list.cpp"34void PPU::Sprite::address_reset() {5self.regs.oam_addr = self.regs.oam_baseaddr;6set_first_sprite();7}89void PPU::Sprite::set_first_sprite() {10regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127);11}1213void PPU::Sprite::frame() {14regs.time_over = false;15regs.range_over = false;16}1718void PPU::Sprite::scanline() {19t.x = 0;20t.y = self.vcounter();2122t.item_count = 0;23t.tile_count = 0;2425t.active = !t.active;26auto oam_item = t.item[t.active];27auto oam_tile = t.tile[t.active];2829if(t.y == (!self.regs.overscan ? 225 : 240) && self.regs.display_disable == false) address_reset();30if(t.y >= (!self.regs.overscan ? 224 : 239)) return;3132memset(oam_item, 0xff, 32); //default to invalid33for(unsigned i = 0; i < 34; i++) oam_tile[i].x = 0xffff; //default to invalid3435for(unsigned i = 0; i < 128; i++) {36unsigned sprite = (regs.first_sprite + i) & 127;37if(on_scanline(list[sprite]) == false) continue;38if(t.item_count++ >= 32) break;39oam_item[t.item_count - 1] = sprite;40}4142if(t.item_count > 0 && oam_item[t.item_count - 1] != 0xff) {43ppu.regs.oam_iaddr = 0x0200 + (oam_item[t.item_count - 1] >> 2);44}45}4647bool PPU::Sprite::on_scanline(SpriteItem &sprite) {48if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;49signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1));50if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;51if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;52return false;53}5455void PPU::Sprite::run() {56output.main.priority = 0;57output.sub.priority = 0;5859auto oam_tile = t.tile[!t.active];60unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 };61unsigned x = t.x++;6263for(unsigned n = 0; n < 34; n++) {64auto tile = oam_tile[n];65if(tile.x == 0xffff) break;6667int px = x - sclip<9>(tile.x);68if(px & ~7) continue;6970unsigned mask = 0x80 >> (tile.hflip == false ? px : 7 - px);71unsigned color;72color = ((bool)(tile.d0 & mask)) << 0;73color |= ((bool)(tile.d1 & mask)) << 1;74color |= ((bool)(tile.d2 & mask)) << 2;75color |= ((bool)(tile.d3 & mask)) << 3;7677if(color) {78if(regs.main_enable) {79output.main.palette = tile.palette + color;80output.main.priority = priority_table[tile.priority];81}8283if(regs.sub_enable) {84output.sub.palette = tile.palette + color;85output.sub.priority = priority_table[tile.priority];86}87}88}89}9091void PPU::Sprite::tilefetch() {92auto oam_item = t.item[t.active];93auto oam_tile = t.tile[t.active];9495for(signed i = 31; i >= 0; i--) {96if(oam_item[i] == 0xff) continue;97auto sprite = list[oam_item[i]];9899unsigned tile_width = sprite.width() >> 3;100signed x = sprite.x;101signed y = (t.y - sprite.y) & 0xff;102if(regs.interlace) y <<= 1;103104if(sprite.vflip) {105if(sprite.width() == sprite.height()) {106y = (sprite.height() - 1) - y;107} else if(y < sprite.width()) {108y = (sprite.width() - 1) - y;109} else {110y = sprite.width() + ((sprite.width() - 1) - (y - sprite.width()));111}112}113114if(regs.interlace) {115y = (sprite.vflip == false ? y + self.field() : y - self.field());116}117118x &= 511;119y &= 255;120121uint16 tiledata_addr = regs.tiledata_addr;122uint16 chrx = (sprite.character >> 0) & 15;123uint16 chry = (sprite.character >> 4) & 15;124if(sprite.nameselect) {125tiledata_addr += (256 * 32) + (regs.nameselect << 13);126}127chry += (y >> 3);128chry &= 15;129chry <<= 4;130131for(unsigned tx = 0; tx < tile_width; tx++) {132unsigned sx = (x + (tx << 3)) & 511;133if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;134if(t.tile_count++ >= 34) break;135136unsigned n = t.tile_count - 1;137oam_tile[n].x = sx;138oam_tile[n].priority = sprite.priority;139oam_tile[n].palette = 128 + (sprite.palette << 4);140oam_tile[n].hflip = sprite.hflip;141142unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx);143unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5);144uint16 addr = (pos & 0xffe0) + ((y & 7) * 2);145146oam_tile[n].d0 = ppu.vram[addr + 0];147oam_tile[n].d1 = ppu.vram[addr + 1];148self.add_clocks(2);149150oam_tile[n].d2 = ppu.vram[addr + 16];151oam_tile[n].d3 = ppu.vram[addr + 17];152self.add_clocks(2);153}154}155156if(t.tile_count < 34) self.add_clocks((34 - t.tile_count) * 4);157regs.time_over |= (t.tile_count > 34);158regs.range_over |= (t.item_count > 32);159}160161void PPU::Sprite::reset() {162for(unsigned i = 0; i < 128; i++) {163list[i].x = 0;164list[i].y = 0;165list[i].character = 0;166list[i].nameselect = 0;167list[i].vflip = 0;168list[i].hflip = 0;169list[i].priority = 0;170list[i].palette = 0;171list[i].size = 0;172}173synchronize();174175t.x = 0;176t.y = 0;177178t.item_count = 0;179t.tile_count = 0;180181t.active = 0;182for(unsigned n = 0; n < 2; n++) {183memset(t.item[n], 0, 32);184for(unsigned i = 0; i < 34; i++) {185t.tile[n][i].x = 0;186t.tile[n][i].priority = 0;187t.tile[n][i].palette = 0;188t.tile[n][i].hflip = 0;189t.tile[n][i].d0 = 0;190t.tile[n][i].d1 = 0;191t.tile[n][i].d2 = 0;192t.tile[n][i].d3 = 0;193}194}195196regs.main_enable = random(false);197regs.sub_enable = random(false);198regs.interlace = random(false);199200regs.base_size = random(0);201regs.nameselect = random(0);202regs.tiledata_addr = (random(0x0000) & 3) << 14;203regs.first_sprite = 0;204205regs.priority0 = 0;206regs.priority1 = 0;207regs.priority2 = 0;208regs.priority3 = 0;209210regs.time_over = false;211regs.range_over = false;212213output.main.palette = 0;214output.main.priority = 0;215output.sub.palette = 0;216output.sub.priority = 0;217}218219PPU::Sprite::Sprite(PPU &self) : self(self) {220}221222#endif223224225