Path: blob/master/libsnes/bsnes/snes/alt/ppu-performance/sprite/sprite.cpp
2 views
#ifdef PPU_CPP12void PPU::Sprite::frame() {3regs.time_over = false;4regs.range_over = false;5}67void PPU::Sprite::update_list(unsigned addr, uint8 data) {8if(addr < 0x0200) {9unsigned i = addr >> 2;10switch(addr & 3) {11case 0: list[i].x = (list[i].x & 0x0100) | data; break;12case 1: list[i].y = (data + 1) & 0xff; break;13case 2: list[i].character = data; break;14case 3: list[i].vflip = data & 0x80;15list[i].hflip = data & 0x40;16list[i].priority = (data >> 4) & 3;17list[i].palette = (data >> 1) & 7;18list[i].use_nameselect = data & 0x01;19break;20}21} else {22unsigned i = (addr & 0x1f) << 2;23list[i + 0].x = ((data & 0x01) << 8) | (list[i + 0].x & 0xff);24list[i + 0].size = data & 0x02;25list[i + 1].x = ((data & 0x04) << 6) | (list[i + 1].x & 0xff);26list[i + 1].size = data & 0x08;27list[i + 2].x = ((data & 0x10) << 4) | (list[i + 2].x & 0xff);28list[i + 2].size = data & 0x20;29list[i + 3].x = ((data & 0x40) << 2) | (list[i + 3].x & 0xff);30list[i + 3].size = data & 0x80;31list_valid = false;32}33}3435void PPU::Sprite::address_reset() {36self.regs.oam_addr = self.regs.oam_baseaddr << 1;37set_first();38}3940void PPU::Sprite::set_first() {41regs.first_sprite = (self.regs.oam_priority == false ? 0 : (self.regs.oam_addr >> 2) & 127);42}4344bool PPU::Sprite::on_scanline(unsigned sprite) {45auto &s = list[sprite];46if(s.x > 256 && (s.x + s.width - 1) < 512) return false;47signed height = (regs.interlace == false ? s.height : s.height >> 1);48if(self.vcounter() >= s.y && self.vcounter() < (s.y + height)) return true;49if((s.y + height) >= 256 && self.vcounter() < ((s.y + height) & 255)) return true;50return false;51}5253void PPU::Sprite::render() {54if(list_valid == false) {55list_valid = true;56for(unsigned i = 0; i < 128; i++) {57if(list[i].size == 0) {58static unsigned width[] = { 8, 8, 8, 16, 16, 32, 16, 16 };59static unsigned height[] = { 8, 8, 8, 16, 16, 32, 32, 32 };60list[i].width = width[regs.base_size];61list[i].height = height[regs.base_size];62} else {63static unsigned width[] = { 16, 32, 64, 32, 64, 64, 32, 32 };64static unsigned height[] = { 16, 32, 64, 32, 64, 64, 64, 32 };65list[i].width = width[regs.base_size];66list[i].height = height[regs.base_size];67if(regs.interlace && regs.base_size >= 6) list[i].height = 16;68}69}70}7172unsigned itemcount = 0;73unsigned tilecount = 0;74memset(output.priority, 0xff, 256);75memset(itemlist, 0xff, 32);76for(unsigned i = 0; i < 34; i++) tilelist[i].tile = 0xffff;7778for(unsigned i = 0; i < 128; i++) {79unsigned s = (regs.first_sprite + i) & 127;80if(on_scanline(s) == false) continue;81if(itemcount++ >= 32) break;82itemlist[itemcount - 1] = s;83}8485for(signed i = 31; i >= 0; i--) {86if(itemlist[i] == 0xff) continue;87auto &s = list[itemlist[i]];88unsigned tile_width = s.width >> 3;89signed x = s.x;90signed y = (self.vcounter() - s.y) & 0xff;91if(regs.interlace) y <<= 1;9293if(s.vflip) {94if(s.width == s.height) {95y = (s.height - 1) - y;96} else {97y = (y < s.width) ? ((s.width - 1) - y) : (s.width + ((s.width - 1) - (y - s.width)));98}99}100101if(regs.interlace) {102y = (s.vflip == false) ? (y + self.field()) : (y - self.field());103}104105x &= 511;106y &= 255;107108uint16 tdaddr = regs.tiledata_addr;109uint16 chrx = (s.character >> 0) & 15;110uint16 chry = (s.character >> 4) & 15;111if(s.use_nameselect) {112tdaddr += (256 * 32) + (regs.nameselect << 13);113}114chry += (y >> 3);115chry &= 15;116chry <<= 4;117118for(unsigned tx = 0; tx < tile_width; tx++) {119unsigned sx = (x + (tx << 3)) & 511;120if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;121if(tilecount++ >= 34) break;122123unsigned n = tilecount - 1;124tilelist[n].x = sx;125tilelist[n].y = y;126tilelist[n].priority = s.priority;127tilelist[n].palette = 128 + (s.palette << 4);128tilelist[n].hflip = s.hflip;129130unsigned mx = (s.hflip == false) ? tx : ((tile_width - 1) - tx);131unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5);132tilelist[n].tile = (pos >> 5) & 0x07ff;133}134}135136regs.time_over |= (tilecount > 34);137regs.range_over |= (itemcount > 32);138139if(regs.main_enable == false && regs.sub_enable == false) return;140141for(unsigned i = 0; i < 34; i++) {142if(tilelist[i].tile == 0xffff) continue;143144auto &t = tilelist[i];145uint8 *tiledata = self.cache.tile_4bpp(t.tile);146tiledata += (t.y & 7) << 3;147unsigned sx = t.x;148for(unsigned x = 0; x < 8; x++) {149sx &= 511;150if(sx < 256) {151unsigned color = *(tiledata + (t.hflip == false ? x : 7 - x));152if(color) {153color += t.palette;154output.palette[sx] = color;155output.priority[sx] = t.priority;156}157}158sx++;159}160}161162if(regs.main_enable) window.render(0);163if(regs.sub_enable) window.render(1);164165unsigned priority0 = (priority0_enable ? regs.priority0 : 0);166unsigned priority1 = (priority1_enable ? regs.priority1 : 0);167unsigned priority2 = (priority2_enable ? regs.priority2 : 0);168unsigned priority3 = (priority3_enable ? regs.priority3 : 0);169if(priority0 + priority1 + priority2 + priority3 == 0) return;170const unsigned priority_table[] = { priority0, priority1, priority2, priority3 };171172for(unsigned x = 0; x < 256; x++) {173if(output.priority[x] == 0xff) continue;174unsigned priority = priority_table[output.priority[x]];175unsigned palette = output.palette[x];176unsigned color = self.screen.get_palette(output.palette[x]);177if(regs.main_enable && !window.main[x]) self.screen.output.plot_main(x, color, priority, 4 + (palette < 192));178if(regs.sub_enable && !window.sub[x]) self.screen.output.plot_sub(x, color, priority, 4 + (palette < 192));179}180}181182PPU::Sprite::Sprite(PPU &self) : self(self) {183priority0_enable = true;184priority1_enable = true;185priority2_enable = true;186priority3_enable = true;187}188189#endif190191192