diff --git a/bsnes/Makefile b/bsnes/Makefile index 760ea410..da0794e7 100755 --- a/bsnes/Makefile +++ b/bsnes/Makefile @@ -1,6 +1,6 @@ include nall/Makefile snes := snes -profile := performance +profile := accuracy ui := qt # compiler diff --git a/bsnes/qt/base/main.cpp b/bsnes/qt/base/main.cpp index 1f7247cd..4ac11bc1 100755 --- a/bsnes/qt/base/main.cpp +++ b/bsnes/qt/base/main.cpp @@ -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(sender()); + if(action == 0) return; + unsigned slot = action->data().toUInt(); + state.load(slot); +} + +void MainWindow::saveState() { + QAction *action = dynamic_cast(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(); } diff --git a/bsnes/qt/base/main.moc.hpp b/bsnes/qt/base/main.moc.hpp index 4c89134a..fee112c3 100755 --- a/bsnes/qt/base/main.moc.hpp +++ b/bsnes/qt/base/main.moc.hpp @@ -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(); diff --git a/bsnes/snes/ppu/background/background.cpp b/bsnes/snes/ppu/background/background.cpp index d1b2ca5d..2c77aab6 100755 --- a/bsnes/snes/ppu/background/background.cpp +++ b/bsnes/snes/ppu/background/background.cpp @@ -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; diff --git a/bsnes/snes/ppu/background/background.hpp b/bsnes/snes/ppu/background/background.hpp index fc315068..b460539c 100755 --- a/bsnes/snes/ppu/background/background.hpp +++ b/bsnes/snes/ppu/background/background.hpp @@ -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(); diff --git a/bsnes/snes/ppu/background/mode7.cpp b/bsnes/snes/ppu/background/mode7.cpp index df170bab..7efa036c 100755 --- a/bsnes/snes/ppu/background/mode7.cpp +++ b/bsnes/snes/ppu/background/mode7.cpp @@ -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 diff --git a/bsnes/snes/ppu/ppu.cpp b/bsnes/snes/ppu/ppu.cpp index 32e864e9..85c77f9f 100755 --- a/bsnes/snes/ppu/ppu.cpp +++ b/bsnes/snes/ppu/ppu.cpp @@ -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(); diff --git a/bsnes/snes/ppu/screen/screen.cpp b/bsnes/snes/ppu/screen/screen.cpp index 6506612b..8bfea45d 100755 --- a/bsnes/snes/ppu/screen/screen.cpp +++ b/bsnes/snes/ppu/screen/screen.cpp @@ -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; } } diff --git a/bsnes/snes/ppu/serialization.cpp b/bsnes/snes/ppu/serialization.cpp index 53f0f1b5..af38171b 100755 --- a/bsnes/snes/ppu/serialization.cpp +++ b/bsnes/snes/ppu/serialization.cpp @@ -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); diff --git a/bsnes/snes/snes.hpp b/bsnes/snes/snes.hpp index b87209e4..53b13f38 100755 --- a/bsnes/snes/snes.hpp +++ b/bsnes/snes/snes.hpp @@ -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; } }