mirror of https://github.com/bsnes-emu/bsnes.git
Update to bsnes v067r04 release.
This build simplifies the tile cache significantly, and it now builds the cache and fetches the VRAM data during Hblank, the VRAM reads are modeled after real hardware. This fixes Mega lo Mania without regressing Winter Gold or Adventures of Dr. Franken. I also fixed a pseudo-hires back color glitch in Super Buster Bros.
This commit is contained in:
parent
dcc661cb28
commit
254a5016e1
|
@ -103,7 +103,7 @@ uint16 sPPU::Screen::get_pixel(bool swap) {
|
|||
source_sub = OAM;
|
||||
}
|
||||
if(priority_sub == 0) {
|
||||
if(self.regs.bgmode == 5 || self.regs.bgmode == 6) {
|
||||
if(self.regs.pseudo_hires == true || self.regs.bgmode == 5 || self.regs.bgmode == 6) {
|
||||
color_sub = get_color(0);
|
||||
} else {
|
||||
color_sub = (regs.color_b << 10) + (regs.color_g << 5) + (regs.color_r << 0);
|
||||
|
|
|
@ -118,7 +118,6 @@ void sPPU::Sprite::serialize(serializer &s) {
|
|||
s.integer(t.x);
|
||||
s.integer(t.y);
|
||||
|
||||
s.integer(t.active_sprite);
|
||||
s.integer(t.item_count);
|
||||
s.integer(t.tile_count);
|
||||
|
||||
|
@ -127,11 +126,13 @@ void sPPU::Sprite::serialize(serializer &s) {
|
|||
s.array(t.item[n]);
|
||||
for(unsigned i = 0; i < 34; i++) {
|
||||
s.integer(t.tile[n][i].x);
|
||||
s.integer(t.tile[n][i].y);
|
||||
s.integer(t.tile[n][i].priority);
|
||||
s.integer(t.tile[n][i].palette);
|
||||
s.integer(t.tile[n][i].tile);
|
||||
s.integer(t.tile[n][i].hflip);
|
||||
s.integer(t.tile[n][i].d0);
|
||||
s.integer(t.tile[n][i].d1);
|
||||
s.integer(t.tile[n][i].d2);
|
||||
s.integer(t.tile[n][i].d3);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ void sPPU::enter() {
|
|||
scanline();
|
||||
add_clocks(88);
|
||||
|
||||
if(vcounter() >= 1 && vcounter() <= (!regs.overscan ? 224 : 239)) {
|
||||
if(vcounter() <= (!regs.overscan ? 224 : 239)) {
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
bg1.run();
|
||||
bg2.run();
|
||||
|
@ -43,11 +43,14 @@ void sPPU::enter() {
|
|||
screen.run();
|
||||
add_clocks(2);
|
||||
}
|
||||
|
||||
add_clocks(22);
|
||||
oam.tilefetch();
|
||||
} else {
|
||||
add_clocks(1024);
|
||||
add_clocks(1024 + 22 + 136);
|
||||
}
|
||||
|
||||
add_clocks(lineclocks() - 88 - 1024);
|
||||
add_clocks(lineclocks() - 88 - 1024 - 22 - 136);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,136 +26,135 @@ void sPPU::Sprite::scanline() {
|
|||
auto oam_item = t.item[t.active];
|
||||
auto oam_tile = t.tile[t.active];
|
||||
|
||||
memset(oam_item, 0xff, 32);
|
||||
for(unsigned i = 0; i < 34; i++) oam_tile[i].tile = 0xffff;
|
||||
memset(oam_item, 0xff, 32); //default to invalid
|
||||
for(unsigned i = 0; i < 34; i++) oam_tile[i].x = 0xffff; //default to invalid
|
||||
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
t.active_sprite = (i + regs.first_sprite) & 127;
|
||||
if(on_scanline() == false) continue;
|
||||
unsigned sprite = (regs.first_sprite + i) & 127;
|
||||
if(on_scanline(list[sprite]) == false) continue;
|
||||
if(t.item_count++ >= 32) break;
|
||||
oam_item[t.item_count - 1] = (i + regs.first_sprite) & 127;
|
||||
oam_item[t.item_count - 1] = sprite;
|
||||
}
|
||||
|
||||
if(t.item_count > 0 && oam_item[t.item_count - 1] != 0xff) {
|
||||
ppu.regs.ioamaddr = 0x0200 + (oam_item[t.item_count - 1] >> 2);
|
||||
}
|
||||
|
||||
for(signed i = 31; i >= 0; i--) {
|
||||
if(oam_item[i] == 0xff) continue;
|
||||
t.active_sprite = oam_item[i];
|
||||
load_tiles();
|
||||
}
|
||||
|
||||
regs.time_over |= (t.tile_count > 34);
|
||||
regs.range_over |= (t.item_count > 32);
|
||||
}
|
||||
|
||||
bool sPPU::Sprite::on_scanline() {
|
||||
SpriteItem &sprite = list[t.active_sprite];
|
||||
bool sPPU::Sprite::on_scanline(SpriteItem &sprite) {
|
||||
if(sprite.x > 256 && (sprite.x + sprite.width() - 1) < 512) return false;
|
||||
|
||||
signed height = (regs.interlace == false ? sprite.height() : (sprite.height() >> 1));
|
||||
if(t.y >= sprite.y && t.y < (sprite.y + height)) return true;
|
||||
if((sprite.y + height) >= 256 && t.y < ((sprite.y + height) & 255)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void sPPU::Sprite::load_tiles() {
|
||||
SpriteItem &sprite = list[t.active_sprite];
|
||||
unsigned tile_width = sprite.width() >> 3;
|
||||
signed x = sprite.x;
|
||||
signed y = (t.y - sprite.y) & 0xff;
|
||||
if(regs.interlace) y <<= 1;
|
||||
|
||||
if(sprite.vflip) {
|
||||
if(sprite.width() == sprite.height()) {
|
||||
y = (sprite.height() - 1) - y;
|
||||
} else {
|
||||
y = (y < sprite.width()) ? ((sprite.width() - 1) - y) : (sprite.width() + ((sprite.width() - 1) - (y - sprite.width())));
|
||||
}
|
||||
}
|
||||
|
||||
if(regs.interlace) {
|
||||
y = (sprite.vflip == false ? y + self.field() : y - self.field());
|
||||
}
|
||||
|
||||
x &= 511;
|
||||
y &= 255;
|
||||
|
||||
uint16 tiledata_addr = regs.tiledata_addr;
|
||||
uint16 chrx = (sprite.character >> 0) & 15;
|
||||
uint16 chry = (sprite.character >> 4) & 15;
|
||||
if(sprite.nameselect) {
|
||||
tiledata_addr += (256 * 32) + (regs.nameselect << 13);
|
||||
}
|
||||
chry += (y >> 3);
|
||||
chry &= 15;
|
||||
chry <<= 4;
|
||||
|
||||
auto oam_tile = t.tile[t.active];
|
||||
|
||||
for(unsigned tx = 0; tx < tile_width; tx++) {
|
||||
unsigned sx = (x + (tx << 3)) & 511;
|
||||
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
|
||||
|
||||
if(t.tile_count++ >= 34) break;
|
||||
unsigned n = t.tile_count - 1;
|
||||
oam_tile[n].x = sx;
|
||||
oam_tile[n].y = y;
|
||||
oam_tile[n].priority = sprite.priority;
|
||||
oam_tile[n].palette = 128 + (sprite.palette << 4);
|
||||
oam_tile[n].hflip = sprite.hflip;
|
||||
|
||||
unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx);
|
||||
unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
oam_tile[n].tile = (pos >> 5) & 0x07ff;
|
||||
}
|
||||
}
|
||||
|
||||
void sPPU::Sprite::run() {
|
||||
output.main.priority = 0;
|
||||
output.sub.priority = 0;
|
||||
|
||||
auto oam_tile = t.tile[!t.active];
|
||||
unsigned priority_table[] = { regs.priority0, regs.priority1, regs.priority2, regs.priority3 };
|
||||
unsigned x = t.x++;
|
||||
|
||||
for(unsigned n = 0; n < 34; n++) {
|
||||
TileItem &item = t.tile[!t.active][n];
|
||||
if(item.tile == 0xffff) break;
|
||||
auto tile = oam_tile[n];
|
||||
if(tile.x == 0xffff) break;
|
||||
|
||||
int px = x - sclip<9>(item.x);
|
||||
int px = x - sclip<9>(tile.x);
|
||||
if(px & ~7) continue;
|
||||
|
||||
uint16 addr = (item.tile << 5) + ((item.y & 7) * 2);
|
||||
unsigned mask = 0x80 >> (item.hflip == false ? px : 7 - px);
|
||||
|
||||
uint8 d0 = memory::vram[addr + 0];
|
||||
uint8 d1 = memory::vram[addr + 1];
|
||||
uint8 d2 = memory::vram[addr + 16];
|
||||
uint8 d3 = memory::vram[addr + 17];
|
||||
|
||||
unsigned mask = 0x80 >> (tile.hflip == false ? px : 7 - px);
|
||||
unsigned color;
|
||||
color = ((bool)(d0 & mask)) << 0;
|
||||
color |= ((bool)(d1 & mask)) << 1;
|
||||
color |= ((bool)(d2 & mask)) << 2;
|
||||
color |= ((bool)(d3 & mask)) << 3;
|
||||
color = ((bool)(tile.d0 & mask)) << 0;
|
||||
color |= ((bool)(tile.d1 & mask)) << 1;
|
||||
color |= ((bool)(tile.d2 & mask)) << 2;
|
||||
color |= ((bool)(tile.d3 & mask)) << 3;
|
||||
|
||||
if(color) {
|
||||
color += item.palette;
|
||||
|
||||
if(regs.main_enabled) {
|
||||
output.main.palette = color;
|
||||
output.main.priority = priority_table[item.priority];
|
||||
output.main.palette = tile.palette + color;
|
||||
output.main.priority = priority_table[tile.priority];
|
||||
}
|
||||
|
||||
if(regs.sub_enabled) {
|
||||
output.sub.palette = color;
|
||||
output.sub.priority = priority_table[item.priority];
|
||||
output.sub.palette = tile.palette + color;
|
||||
output.sub.priority = priority_table[tile.priority];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sPPU::Sprite::tilefetch() {
|
||||
auto oam_item = t.item[t.active];
|
||||
auto oam_tile = t.tile[t.active];
|
||||
|
||||
for(signed i = 31; i >= 0; i--) {
|
||||
if(oam_item[i] == 0xff) continue;
|
||||
auto sprite = list[oam_item[i]];
|
||||
|
||||
unsigned tile_width = sprite.width() >> 3;
|
||||
signed x = sprite.x;
|
||||
signed y = (t.y - sprite.y) & 0xff;
|
||||
if(regs.interlace) y <<= 1;
|
||||
|
||||
if(sprite.vflip) {
|
||||
if(sprite.width() == sprite.height()) {
|
||||
y = (sprite.height() - 1) - y;
|
||||
} else if(y < sprite.width()) {
|
||||
y = (sprite.width() - 1) - y;
|
||||
} else {
|
||||
y = sprite.width() + ((sprite.width() - 1) - (y - sprite.width()));
|
||||
}
|
||||
}
|
||||
|
||||
if(regs.interlace) {
|
||||
y = (sprite.vflip == false ? y + self.field() : y - self.field());
|
||||
}
|
||||
|
||||
x &= 511;
|
||||
y &= 255;
|
||||
|
||||
uint16 tiledata_addr = regs.tiledata_addr;
|
||||
uint16 chrx = (sprite.character >> 0) & 15;
|
||||
uint16 chry = (sprite.character >> 4) & 15;
|
||||
if(sprite.nameselect) {
|
||||
tiledata_addr += (256 * 32) + (regs.nameselect << 13);
|
||||
}
|
||||
chry += (y >> 3);
|
||||
chry &= 15;
|
||||
chry <<= 4;
|
||||
|
||||
for(unsigned tx = 0; tx < tile_width; tx++) {
|
||||
unsigned sx = (x + (tx << 3)) & 511;
|
||||
if(x != 256 && sx >= 256 && (sx + 7) < 512) continue;
|
||||
if(t.tile_count++ >= 34) break;
|
||||
|
||||
unsigned n = t.tile_count - 1;
|
||||
oam_tile[n].x = sx;
|
||||
oam_tile[n].priority = sprite.priority;
|
||||
oam_tile[n].palette = 128 + (sprite.palette << 4);
|
||||
oam_tile[n].hflip = sprite.hflip;
|
||||
|
||||
unsigned mx = (sprite.hflip == false) ? tx : ((tile_width - 1) - tx);
|
||||
unsigned pos = tiledata_addr + ((chry + ((chrx + mx) & 15)) << 5);
|
||||
uint16 addr = (pos & 0xffe0) + ((y & 7) * 2);
|
||||
|
||||
oam_tile[n].d0 = memory::vram[addr + 0];
|
||||
oam_tile[n].d1 = memory::vram[addr + 1];
|
||||
self.add_clocks(2);
|
||||
|
||||
oam_tile[n].d2 = memory::vram[addr + 16];
|
||||
oam_tile[n].d3 = memory::vram[addr + 17];
|
||||
self.add_clocks(2);
|
||||
}
|
||||
}
|
||||
|
||||
if(t.tile_count < 34) self.add_clocks((34 - t.tile_count) * 4);
|
||||
regs.time_over |= (t.tile_count > 34);
|
||||
regs.range_over |= (t.item_count > 32);
|
||||
}
|
||||
|
||||
void sPPU::Sprite::reset() {
|
||||
for(unsigned i = 0; i < 128; i++) {
|
||||
list[i].x = 0;
|
||||
|
@ -172,7 +171,6 @@ void sPPU::Sprite::reset() {
|
|||
t.x = 0;
|
||||
t.y = 0;
|
||||
|
||||
t.active_sprite = 0;
|
||||
t.item_count = 0;
|
||||
t.tile_count = 0;
|
||||
|
||||
|
@ -181,11 +179,13 @@ void sPPU::Sprite::reset() {
|
|||
memset(t.item[n], 0, 32);
|
||||
for(unsigned i = 0; i < 34; i++) {
|
||||
t.tile[n][i].x = 0;
|
||||
t.tile[n][i].y = 0;
|
||||
t.tile[n][i].priority = 0;
|
||||
t.tile[n][i].palette = 0;
|
||||
t.tile[n][i].tile = 0;
|
||||
t.tile[n][i].hflip = 0;
|
||||
t.tile[n][i].d0 = 0;
|
||||
t.tile[n][i].d1 = 0;
|
||||
t.tile[n][i].d2 = 0;
|
||||
t.tile[n][i].d3 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,18 +18,16 @@ public:
|
|||
|
||||
struct TileItem {
|
||||
uint16 x;
|
||||
uint16 y;
|
||||
uint16 priority;
|
||||
uint16 palette;
|
||||
uint16 tile;
|
||||
bool hflip;
|
||||
uint8 d0, d1, d2, d3;
|
||||
};
|
||||
|
||||
struct State {
|
||||
unsigned x;
|
||||
unsigned y;
|
||||
|
||||
unsigned active_sprite;
|
||||
unsigned item_count;
|
||||
unsigned tile_count;
|
||||
|
||||
|
@ -72,12 +70,12 @@ public:
|
|||
void frame();
|
||||
void scanline();
|
||||
void run();
|
||||
void tilefetch();
|
||||
void reset();
|
||||
|
||||
void serialize(serializer&);
|
||||
Sprite(sPPU &self);
|
||||
|
||||
private:
|
||||
bool on_scanline();
|
||||
void load_tiles();
|
||||
bool on_scanline(SpriteItem&);
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
static const char bsnesVersion[] = "067.03";
|
||||
static const char bsnesVersion[] = "067.04";
|
||||
static const char bsnesTitle[] = "bsnes";
|
||||
static const unsigned bsnesSerializerVersion = 12;
|
||||
|
||||
|
|
Loading…
Reference in New Issue