mirror of https://github.com/bsnes-emu/bsnes.git
Update to v068r14 release.
byuu says: Holy hell, that was a total brain twister. After hours of crazy bit twiddling and debug printf's, I finally figured out how to allow both lores and hires scrolling in the accurate PPU renderer. In the process, I modified the main loop to run from -7 to 255, regardless of the hires setting, and perform X adjustment inside the tile fetching. This fixed a strange main/subscreen misalignment issue, so I was able to restore the proper sub-then-main rendering for the final screen output stage. Code looks a good bit cleaner this way overall. I also added load state and save state menus to the tools menu, so you can use the menubar to load and save to ten slots. I am thinking that I should nuke the icons. As pretty as they are, it's getting tiresome trying to find icons for everything, I have no pictures to represent loading or saving a slot, nor to represent individual slots. I'll just stick to radios and checkboxes.
This commit is contained in:
parent
3f43747474
commit
3a81ac94a5
|
@ -1,6 +1,6 @@
|
|||
include nall/Makefile
|
||||
snes := snes
|
||||
profile := performance
|
||||
profile := accuracy
|
||||
ui := qt
|
||||
|
||||
# compiler
|
||||
|
|
|
@ -174,6 +174,24 @@ MainWindow::MainWindow() {
|
|||
|
||||
tools->addSeparator();
|
||||
|
||||
tools_loadState = tools->addMenu("Load Quick State");
|
||||
for(unsigned i = 0; i < 10; i++) {
|
||||
QAction *loadAction = new QAction(string("Slot ", i + 1), 0);
|
||||
loadAction->setData(i);
|
||||
connect(loadAction, SIGNAL(triggered()), this, SLOT(loadState()));
|
||||
tools_loadState->addAction(loadAction);
|
||||
}
|
||||
|
||||
tools_saveState = tools->addMenu("Save Quick State");
|
||||
for(unsigned i = 0; i < 10; i++) {
|
||||
QAction *saveAction = new QAction(string("Slot ", i + 1), 0);
|
||||
saveAction->setData(i);
|
||||
connect(saveAction, SIGNAL(triggered()), this, SLOT(saveState()));
|
||||
tools_saveState->addAction(saveAction);
|
||||
}
|
||||
|
||||
tools->addSeparator();
|
||||
|
||||
tools_cheatEditor = tools->addAction("Cheat &Editor ...");
|
||||
tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png"));
|
||||
|
||||
|
@ -581,6 +599,20 @@ void MainWindow::saveScreenshot() {
|
|||
interface.saveScreenshot = true;
|
||||
}
|
||||
|
||||
void MainWindow::loadState() {
|
||||
QAction *action = dynamic_cast<QAction*>(sender());
|
||||
if(action == 0) return;
|
||||
unsigned slot = action->data().toUInt();
|
||||
state.load(slot);
|
||||
}
|
||||
|
||||
void MainWindow::saveState() {
|
||||
QAction *action = dynamic_cast<QAction*>(sender());
|
||||
if(action == 0) return;
|
||||
unsigned slot = action->data().toUInt();
|
||||
state.save(slot);
|
||||
}
|
||||
|
||||
void MainWindow::showCheatEditor() { toolsWindow->tab->setCurrentIndex(0); toolsWindow->show(); }
|
||||
void MainWindow::showCheatFinder() { toolsWindow->tab->setCurrentIndex(1); toolsWindow->show(); }
|
||||
void MainWindow::showStateManager() { toolsWindow->tab->setCurrentIndex(2); toolsWindow->show(); }
|
||||
|
|
|
@ -80,6 +80,8 @@ public:
|
|||
QAction *tools_movies_recordFromPowerOn;
|
||||
QAction *tools_movies_recordFromHere;
|
||||
QAction *tools_captureScreenshot;
|
||||
QMenu *tools_loadState;
|
||||
QMenu *tools_saveState;
|
||||
QAction *tools_cheatEditor;
|
||||
QAction *tools_cheatFinder;
|
||||
QAction *tools_stateManager;
|
||||
|
@ -150,6 +152,8 @@ public slots:
|
|||
void recordMovieFromPowerOn();
|
||||
void recordMovieFromHere();
|
||||
void saveScreenshot();
|
||||
void loadState();
|
||||
void saveState();
|
||||
void showCheatEditor();
|
||||
void showCheatFinder();
|
||||
void showStateManager();
|
||||
|
|
|
@ -7,9 +7,9 @@ void PPU::Background::frame() {
|
|||
|
||||
void PPU::Background::scanline() {
|
||||
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||
x = -8 << hires;
|
||||
x = -7;
|
||||
y = self.vcounter();
|
||||
edge = 7 - (regs.hoffset & 7);
|
||||
tile_counter = (7 - (regs.hoffset & 7)) << hires;
|
||||
for(unsigned n = 0; n < 8; n++) data[n] = 0;
|
||||
|
||||
if(self.vcounter() == 1) {
|
||||
|
@ -36,7 +36,7 @@ void PPU::Background::get_tile() {
|
|||
unsigned tile_height = (regs.tile_size == TileSize::Size8x8 ? 3 : 4);
|
||||
unsigned tile_width = (!hires ? tile_height : 4);
|
||||
|
||||
unsigned width = (!hires ? 256 : 512);
|
||||
unsigned width = 256 << hires;
|
||||
|
||||
unsigned mask_x = (tile_height == 3 ? width : (width << 1));
|
||||
unsigned mask_y = mask_x;
|
||||
|
@ -45,7 +45,7 @@ void PPU::Background::get_tile() {
|
|||
mask_x--;
|
||||
mask_y--;
|
||||
|
||||
unsigned px = x;
|
||||
unsigned px = x << hires;
|
||||
unsigned py = mosaic_voffset;
|
||||
|
||||
unsigned hscroll = regs.hoffset;
|
||||
|
@ -59,24 +59,24 @@ void PPU::Background::get_tile() {
|
|||
unsigned voffset = vscroll + py;
|
||||
|
||||
if(self.regs.bgmode == 2 || self.regs.bgmode == 4 || self.regs.bgmode == 6) {
|
||||
uint16 opt_x = (x + (hscroll & 7));
|
||||
uint16 offset_x = (x + (hscroll & 7));
|
||||
|
||||
if(opt_x >= 8) {
|
||||
unsigned hval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
|
||||
unsigned vval = self.bg3.get_tile((opt_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
|
||||
unsigned opt_valid_bit = (id == ID::BG1 ? 0x2000 : 0x4000);
|
||||
if(offset_x >= 8) {
|
||||
unsigned hval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 0);
|
||||
unsigned vval = self.bg3.get_tile((offset_x - 8) + (self.bg3.regs.hoffset & ~7), self.bg3.regs.voffset + 8);
|
||||
unsigned valid_mask = (id == ID::BG1 ? 0x2000 : 0x4000);
|
||||
|
||||
if(self.regs.bgmode == 4) {
|
||||
if(hval & opt_valid_bit) {
|
||||
if(!(hval & 0x8000)) {
|
||||
hoffset = opt_x + (hval & ~7);
|
||||
if(hval & valid_mask) {
|
||||
if((hval & 0x8000) == 0) {
|
||||
hoffset = offset_x + (hval & ~7);
|
||||
} else {
|
||||
voffset = y + hval;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(hval & opt_valid_bit) hoffset = opt_x + (hval & ~7);
|
||||
if(vval & opt_valid_bit) voffset = y + vval;
|
||||
if(hval & valid_mask) hoffset = offset_x + (hval & ~7);
|
||||
if(vval & valid_mask) voffset = y + vval;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,8 +84,8 @@ void PPU::Background::get_tile() {
|
|||
hoffset &= mask_x;
|
||||
voffset &= mask_y;
|
||||
|
||||
unsigned screen_x = (regs.screen_size & 1 ? (32 << 5) : 0);
|
||||
unsigned screen_y = (regs.screen_size & 2 ? (32 << 5) : 0);
|
||||
unsigned screen_x = (regs.screen_size & 1 ? 32 << 5 : 0);
|
||||
unsigned screen_y = (regs.screen_size & 2 ? 32 << 5 : 0);
|
||||
if(regs.screen_size == 3) screen_y <<= 1;
|
||||
|
||||
unsigned tx = hoffset >> tile_width;
|
||||
|
@ -126,21 +126,21 @@ void PPU::Background::get_tile() {
|
|||
}
|
||||
|
||||
if(mirror_x) for(unsigned n = 0; n < 8; n++) {
|
||||
//reverse data bits in data[n]: 01234567 -> 76543210
|
||||
data[n] = ((data[n] >> 4) & 0x0f) | ((data[n] << 4) & 0xf0);
|
||||
data[n] = ((data[n] >> 2) & 0x33) | ((data[n] << 2) & 0xcc);
|
||||
data[n] = ((data[n] >> 1) & 0x55) | ((data[n] << 1) & 0xaa);
|
||||
}
|
||||
}
|
||||
|
||||
void PPU::Background::run() {
|
||||
void PPU::Background::run(bool screen) {
|
||||
if(self.vcounter() == 0) return;
|
||||
bool hires = (self.regs.bgmode == 5 || self.regs.bgmode == 6);
|
||||
|
||||
if((self.hcounter() & 2) == 0) {
|
||||
if(screen == Screen::Sub) {
|
||||
output.main.priority = 0;
|
||||
output.sub.priority = 0;
|
||||
} else if(hires == false) {
|
||||
return;
|
||||
if(hires == false) return;
|
||||
}
|
||||
|
||||
if(regs.mode == Mode::Inactive) return;
|
||||
|
@ -148,7 +148,11 @@ void PPU::Background::run() {
|
|||
|
||||
if(regs.mode == Mode::Mode7) return run_mode7();
|
||||
|
||||
if((x++ & 7) == edge) get_tile();
|
||||
if(tile_counter-- == 0) {
|
||||
tile_counter = 7;
|
||||
get_tile();
|
||||
}
|
||||
if(screen == Screen::Main) x++;
|
||||
|
||||
uint8 palette = get_tile_color();
|
||||
if(x >= 0 && mosaic_hcounter++ >= regs.mosaic) {
|
||||
|
@ -169,19 +173,17 @@ void PPU::Background::run() {
|
|||
output.sub.palette = palette_index + mosaic_palette;
|
||||
output.sub.tile = tile;
|
||||
}
|
||||
} else {
|
||||
if(x & 1) {
|
||||
if(regs.main_enable) {
|
||||
output.main.priority = priority;
|
||||
output.main.palette = palette_index + mosaic_palette;
|
||||
output.main.tile = tile;
|
||||
}
|
||||
} else {
|
||||
if(regs.sub_enable) {
|
||||
output.sub.priority = priority;
|
||||
output.sub.palette = palette_index + mosaic_palette;
|
||||
output.sub.tile = tile;
|
||||
}
|
||||
} else if(screen == Screen::Main) {
|
||||
if(regs.main_enable) {
|
||||
output.main.priority = priority;
|
||||
output.main.palette = palette_index + mosaic_palette;
|
||||
output.main.tile = tile;
|
||||
}
|
||||
} else if(screen == Screen::Sub) {
|
||||
if(regs.sub_enable) {
|
||||
output.sub.priority = priority;
|
||||
output.sub.palette = palette_index + mosaic_palette;
|
||||
output.sub.tile = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +228,6 @@ void PPU::Background::reset() {
|
|||
|
||||
x = 0;
|
||||
y = 0;
|
||||
edge = 0;
|
||||
|
||||
mosaic_vcounter = 0;
|
||||
mosaic_voffset = 0;
|
||||
|
@ -234,6 +235,7 @@ void PPU::Background::reset() {
|
|||
mosaic_hoffset = 0;
|
||||
mosaic_palette = 0;
|
||||
|
||||
tile_counter = 0;
|
||||
tile = 0;
|
||||
priority = 0;
|
||||
palette_number = 0;
|
||||
|
|
|
@ -5,6 +5,7 @@ class Background {
|
|||
struct Mode { enum { BPP2, BPP4, BPP8, Mode7, Inactive }; };
|
||||
struct ScreenSize { enum { Size32x32, Size32x64, Size64x32, Size64x64 }; };
|
||||
struct TileSize { enum { Size8x8, Size16x16 }; };
|
||||
struct Screen { enum { Main, Sub }; };
|
||||
|
||||
struct Regs {
|
||||
unsigned tiledata_addr;
|
||||
|
@ -35,7 +36,6 @@ class Background {
|
|||
struct {
|
||||
signed x;
|
||||
signed y;
|
||||
signed edge;
|
||||
|
||||
unsigned mosaic_vcounter;
|
||||
unsigned mosaic_voffset;
|
||||
|
@ -43,6 +43,7 @@ class Background {
|
|||
unsigned mosaic_hoffset;
|
||||
unsigned mosaic_palette;
|
||||
|
||||
unsigned tile_counter;
|
||||
unsigned tile;
|
||||
unsigned priority;
|
||||
unsigned palette_number;
|
||||
|
@ -52,7 +53,7 @@ class Background {
|
|||
|
||||
void frame();
|
||||
void scanline();
|
||||
void run();
|
||||
void run(bool screen);
|
||||
void reset();
|
||||
|
||||
void get_tile();
|
||||
|
|
|
@ -16,7 +16,7 @@ void PPU::Background::run_mode7() {
|
|||
signed hoffset = sclip<13>(self.regs.mode7_hoffset);
|
||||
signed voffset = sclip<13>(self.regs.mode7_voffset);
|
||||
|
||||
if(++Background::x & ~255) return;
|
||||
if(Background::x++ & ~255) return;
|
||||
unsigned x = mosaic_hoffset;
|
||||
unsigned y = self.bg1.mosaic_voffset; //BG2 vertical mosaic uses BG1 mosaic size
|
||||
|
||||
|
|
|
@ -43,16 +43,16 @@ void PPU::enter() {
|
|||
if(vcounter() <= (!regs.overscan ? 224 : 239)) {
|
||||
add_clocks(4);
|
||||
for(unsigned pixel = 1; pixel < 8 + 256; pixel++) {
|
||||
bg1.run();
|
||||
bg2.run();
|
||||
bg3.run();
|
||||
bg4.run();
|
||||
bg1.run(1);
|
||||
bg2.run(1);
|
||||
bg3.run(1);
|
||||
bg4.run(1);
|
||||
add_clocks(2);
|
||||
|
||||
bg1.run();
|
||||
bg2.run();
|
||||
bg3.run();
|
||||
bg4.run();
|
||||
bg1.run(0);
|
||||
bg2.run(0);
|
||||
bg3.run(0);
|
||||
bg4.run(0);
|
||||
if(pixel >= 8) {
|
||||
oam.run();
|
||||
window.run();
|
||||
|
|
|
@ -8,13 +8,13 @@ void PPU::Screen::scanline() {
|
|||
void PPU::Screen::run() {
|
||||
uint16 color;
|
||||
if(self.regs.pseudo_hires == false && self.regs.bgmode != 5 && self.regs.bgmode != 6) {
|
||||
color = get_pixel(false);
|
||||
color = get_pixel(0);
|
||||
*output++ = color;
|
||||
*output++ = color;
|
||||
} else {
|
||||
color = get_pixel(false);
|
||||
color = get_pixel(1);
|
||||
*output++ = color;
|
||||
color = get_pixel(true);
|
||||
color = get_pixel(0);
|
||||
*output++ = color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,6 @@ void PPU::Background::serialize(serializer &s) {
|
|||
|
||||
s.integer(x);
|
||||
s.integer(y);
|
||||
s.integer(edge);
|
||||
|
||||
s.integer(mosaic_vcounter);
|
||||
s.integer(mosaic_voffset);
|
||||
|
@ -123,6 +122,7 @@ void PPU::Background::serialize(serializer &s) {
|
|||
s.integer(mosaic_hoffset);
|
||||
s.integer(mosaic_palette);
|
||||
|
||||
s.integer(tile_counter);
|
||||
s.integer(tile);
|
||||
s.integer(priority);
|
||||
s.integer(palette_number);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SNES {
|
||||
namespace Info {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "068.13";
|
||||
static const char Version[] = "068.14";
|
||||
static const unsigned SerializerVersion = 13;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue