From de27b9ea856953eea81e31b7ef250cfdcb48f4e5 Mon Sep 17 00:00:00 2001 From: DerKoun Date: Thu, 17 Jun 2021 23:03:05 +0200 Subject: [PATCH] beta 10.6 --- .github/workflows/CI.yml | 4 +- README.md | 32 +++--- bsnes/emulator/emulator.hpp | 2 +- bsnes/heuristics/super-famicom.cpp | 40 +++++-- bsnes/sfc/interface/configuration.cpp | 1 + bsnes/sfc/interface/configuration.hpp | 1 + bsnes/sfc/ppu-fast/background.cpp | 4 +- bsnes/sfc/ppu-fast/io.cpp | 24 ++-- bsnes/sfc/ppu-fast/object.cpp | 2 +- bsnes/sfc/ppu-fast/ppu.cpp | 1 + bsnes/sfc/ppu-fast/ppu.hpp | 4 +- bsnes/target-bsnes/program/game.cpp | 27 ++++- bsnes/target-bsnes/program/hacks.cpp | 22 +++- bsnes/target-bsnes/program/patch.cpp | 22 ++-- bsnes/target-bsnes/program/program.hpp | 4 +- bsnes/target-libretro/libretro.cpp | 23 ++++ bsnes/target-libretro/program.cpp | 149 ++++++++++++++++++++++--- hiro/GNUmakefile | 16 +-- hiro/components.hpp | 2 +- 19 files changed, 288 insertions(+), 92 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 74626def..bcb85d3c 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -57,7 +57,7 @@ jobs: - name: Setup run: | sudo apt-get update - sudo apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libgtksourceview2.0-dev libcairo2-dev libsdl2-dev libxv-dev libao-dev libopenal-dev libudev-dev + sudo apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libcairo2-dev libsdl2-dev libxv-dev libao-dev libopenal-dev libudev-dev - name: Build run: make -j $(nproc) -C bsnes - name: Prepare artifacts @@ -85,7 +85,7 @@ jobs: - name: Setup run: | sudo apt-get update - sudo apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libgtksourceview2.0-dev libcairo2-dev libsdl2-dev libxv-dev libao-dev libopenal-dev libudev-dev + sudo apt-get -y install build-essential libgtk2.0-dev libpulse-dev mesa-common-dev libcairo2-dev libsdl2-dev libxv-dev libao-dev libopenal-dev libudev-dev - name: Build run: make -j $(nproc) -C bsnes target=libretro - name: Prepare artifacts diff --git a/README.md b/README.md index 839a83a4..9062bb00 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# bsnes-hd *beta 10.5* +# bsnes-hd *beta 10.6* - [downloads](https://github.com/DerKoun/bsnes-hd/releases) for the latest betas (there are only beta) / also on the libretro auto-updater - [GitHub project](https://github.com/DerKoun/bsnes-hd) for source code, issues, feature requests, ... @@ -19,8 +19,8 @@ bsnes-hd (called "*HD Mode 7 mod, for bsnes*" in early betas) is a fork of bsnes ### HD Mode 7 Rendering the rotated, scaled or pseudo perspective backgrounds at higher resolutions. This does not involve new custom imagery or upscaling algorithms. It is a higher resolution version of the process the SNES uses. -- [image comparison](http://www.framecompare.com/image-compare/screenshotcomparison/EB9MNNNU) (framecompare) - [video comparison](https://www.youtube.com/watch?v=6VrzJ6Y1kjQ) by *reznoire* (youtube) +- [video demo](https://www.youtube.com/watch?v=IW7VOQKxtUQ) by *Emulators & Gameplay HD* (youtube) ### Widescreen @@ -193,18 +193,22 @@ The file must contain alternating letters and numbers, each pair overriding a se #### Settings -| Description | Letter | Values | -| ----------------------------------- | ------- | ----------------------------------------------- | -| widescreen mode | w | 0:off 1:on(always) 2:on(mode7) | -| widescreen sprites | s | 0:safe 1:unsafe(widescreen) 2:clip | -| widescreen aspect ratio | W | 0-200:widescreen-extension 201+:AR(*see below*) | -| widescreen background 1/2/3/4 | b/B/c/C | 0+:WS 10+:crop 20:disab 1000+:line(*see below*) | -| widescreen marker | m | 0:off 1+:line 11+:darken (*see below*) | -| mode 7 perspective correction | P | 0:off 1-3:auto 4-6+:on (*see below*) | -| ignore window | i | 0:none 1:outside 2:outside&always 3:all | -| ignore window fallback x-coordinate | I | 0-255:x-coordinate | -| overclock CPU | O | 100+:percentage(100 is normal) | -| stretch windowing | S | (*for widescreen patches only*, *see below*) | +| Description | Letter | Values | +| ----------------------------------- | ------- | ------------------------------------------------ | +| widescreen mode | w | 0:off 1:on(always) 2:on(mode7) | +| widescreen sprites | s | 0:safe 1:unsafe(widescreen) 2:clip | +| widescreen aspect ratio | W | 0-200:widescreen-extension 201+:AR (*see below*) | +| widescreen background 1/2/3/4 | b/B/c/C | 0+:WS 10+:crop 20:disab 1000+:line (*see below*) | +| widescreen marker | m | 0:off 1+:line 11+:darken (*see below*) | +| mode 7 perspective correction | P | 0:off 1-3:auto 4-6+:on (*see below*) | +| scale factor | f | 0:off 1-10:factor | +| disable sprite limit | l | 0:off 1:on | +| ignore window | i | 0:none 1:outside 2:outside&always 3:all | +| ignore window fallback x-coordinate | I | 0-255:x-coordinate | +| overclock CPU | O | 100+:percentage(100 is normal) | +| stretch windowing | S | (*for widescreen patches only*, *see below*) | +| pixel aspect ratio correction | p | 0:off 1:on (*libretro only*) | +| overscan | o | 0:off(216 / 5th HD) 1:on(224) (*libretro only*) | #### Widescreen Aspect Ratio values diff --git a/bsnes/emulator/emulator.hpp b/bsnes/emulator/emulator.hpp index bda3388a..1e16ca58 100644 --- a/bsnes/emulator/emulator.hpp +++ b/bsnes/emulator/emulator.hpp @@ -31,7 +31,7 @@ using namespace nall; namespace Emulator { static const string Name = "bsnes-hd beta"; - static const string Version = "10.5";//bsnes/target-bsnes/presentation/presentation.cpp:create:about:setVersion + static const string Version = "10.6";//bsnes/target-bsnes/presentation/presentation.cpp:create:about:setVersion static const string Author = "DerKoun(Near)"; static const string License = "GPLv3"; static const string Website = "https://github.com/DerKoun/bsnes-hd"; diff --git a/bsnes/heuristics/super-famicom.cpp b/bsnes/heuristics/super-famicom.cpp index 0101a246..674196e3 100644 --- a/bsnes/heuristics/super-famicom.cpp +++ b/bsnes/heuristics/super-famicom.cpp @@ -433,13 +433,7 @@ auto SuperFamicom::serial() const -> string { } auto SuperFamicom::romSize() const -> uint { - //subtract appended firmware size, if firmware is present - if((size() & 0x7fff) == 0x100) return size() - 0x100; - if((size() & 0x7fff) == 0xc00) return size() - 0xc00; - if((size() & 0x7fff) == 0x2000) return size() - 0x2000; - if((size() & 0xffff) == 0xd000) return size() - 0xd000; - if((size() & 0x3ffff) == 0x28000) return size() - 0x28000; - return size(); + return size() - firmwareRomSize(); } auto SuperFamicom::programRomSize() const -> uint { @@ -459,8 +453,38 @@ auto SuperFamicom::expansionRomSize() const -> uint { return 0; } +//detect if any firmware is appended to the ROM image, and return its size if so auto SuperFamicom::firmwareRomSize() const -> uint { - return size() - romSize(); + auto cartridgeTypeLo = data[headerAddress + 0x26] & 15; + auto cartridgeTypeHi = data[headerAddress + 0x26] >> 4; + auto cartridgeSubType = data[headerAddress + 0x0f]; + + if(serial() == "042J" || (cartridgeTypeLo == 0x3 && cartridgeTypeHi == 0xe)) { + //Game Boy + if((size() & 0x7fff) == 0x100) return 0x100; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x10) { + //Hitachi HG51BS169 + if((size() & 0x7fff) == 0xc00) return 0xc00; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0x0) { + //NEC uPD7725 + if((size() & 0x7fff) == 0x2000) return 0x2000; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x01) { + //NEC uPD96050 + if((size() & 0xffff) == 0xd000) return 0xd000; + } + + if(cartridgeTypeLo >= 0x3 && cartridgeTypeHi == 0xf && cartridgeSubType == 0x02) { + //ARM6 + if((size() & 0x3ffff) == 0x28000) return 0x28000; + } + + return 0; } auto SuperFamicom::ramSize() const -> uint { diff --git a/bsnes/sfc/interface/configuration.cpp b/bsnes/sfc/interface/configuration.cpp index 7d12c8f9..35b5b876 100644 --- a/bsnes/sfc/interface/configuration.cpp +++ b/bsnes/sfc/interface/configuration.cpp @@ -43,6 +43,7 @@ auto Configuration::process(Markup::Node document, bool load) -> void { bind(natural, "Hacks/PPU/Mode7/Igwin", hacks.ppu.mode7.igwin); bind(natural, "Hacks/PPU/Mode7/Igwinx", hacks.ppu.mode7.igwinx); bind(boolean, "Hacks/PPU/Mode7/Strwin", hacks.ppu.mode7.strwin); + bind(natural, "Hacks/PPU/Mode7/VramExt", hacks.ppu.mode7.vramExt); bind(natural, "Hacks/PPU/Mode7/BgGrad", hacks.ppu.mode7.bgGrad); bind(natural, "Hacks/PPU/Mode7/WindRad", hacks.ppu.mode7.windRad); bind(natural, "Hacks/PPU/Mode7/WsMode", hacks.ppu.mode7.wsMode); diff --git a/bsnes/sfc/interface/configuration.hpp b/bsnes/sfc/interface/configuration.hpp index 10348e66..be5bbe2b 100644 --- a/bsnes/sfc/interface/configuration.hpp +++ b/bsnes/sfc/interface/configuration.hpp @@ -58,6 +58,7 @@ struct Configuration { uint igwin = 1; uint igwinx = 128; bool strwin = false; + uint vramExt = 0x7fff; uint bgGrad = 4; uint windRad = 0; uint wsMode = 1; diff --git a/bsnes/sfc/ppu-fast/background.cpp b/bsnes/sfc/ppu-fast/background.cpp index f0bbb5ba..4eac82fe 100644 --- a/bsnes/sfc/ppu-fast/background.cpp +++ b/bsnes/sfc/ppu-fast/background.cpp @@ -115,7 +115,7 @@ auto PPU::Line::renderBackground(PPU::IO::Background& self, uint8 source) -> voi tileNumber = (tileNumber & 0x03ff) + tiledataIndex & tileMask; uint16 address; - address = (tileNumber << colorShift) + (voffset & 7 ^ mirrorY) & 0x7fff; + address = ppu.vramExt((tileNumber << colorShift) + (voffset & 7 ^ mirrorY)) /*& 0x7fff*/; uint64 data; data = (uint64)ppu.vram[address + 0] << 0; @@ -196,5 +196,5 @@ auto PPU::Line::getTile(PPU::IO::Background& self, uint hoffset, uint voffset) - uint offset = (tileY & 0x1f) << 5 | (tileX & 0x1f); if(tileX & 0x20) offset += screenX; if(tileY & 0x20) offset += screenY; - return ppu.vram[self.screenAddress + offset & 0x7fff]; + return ppu.vram[ppu.vramExt(self.screenAddress + offset) /*& 0x7fff*/]; } diff --git a/bsnes/sfc/ppu-fast/io.cpp b/bsnes/sfc/ppu-fast/io.cpp index 4e445a03..24843e9b 100644 --- a/bsnes/sfc/ppu-fast/io.cpp +++ b/bsnes/sfc/ppu-fast/io.cpp @@ -13,10 +13,10 @@ auto PPU::latchCounters() -> void { auto PPU::vramAddress() const -> uint { uint address = io.vramAddress; switch(io.vramMapping) { - case 0: return address & 0x7fff; - case 1: return address & 0x7f00 | address << 3 & 0x00f8 | address >> 5 & 7; - case 2: return address & 0x7e00 | address << 3 & 0x01f8 | address >> 6 & 7; - case 3: return address & 0x7c00 | address << 3 & 0x03f8 | address >> 7 & 7; + case 0: return ppu.vramExt(address & 0xffff /*0x7fff*/); + case 1: return ppu.vramExt(address & 0xff00 /*0x7f00*/| address << 3 & 0x00f8 | address >> 5 & 7); + case 2: return ppu.vramExt(address & 0xfe00 /*0x7e00*/| address << 3 & 0x01f8 | address >> 6 & 7); + case 3: return ppu.vramExt(address & 0xfc00 /*0x7c00*/| address << 3 & 0x03f8 | address >> 7 & 7); } unreachable; } @@ -263,37 +263,37 @@ auto PPU::writeIO(uint address, uint8 data) -> void { case 0x2107: { //BG1SC io.bg1.screenSize = data >> 0 & 3; - io.bg1.screenAddress = data << 8 & 0x7c00; + io.bg1.screenAddress = ppu.vramExt(data << 8 & 0xfc00) /*0x7c00*/; return; } case 0x2108: { //BG2SC io.bg2.screenSize = data >> 0 & 3; - io.bg2.screenAddress = data << 8 & 0x7c00; + io.bg2.screenAddress = ppu.vramExt(data << 8 & 0xfc00) /*0x7c00*/; return; } case 0x2109: { //BG3SC io.bg3.screenSize = data >> 0 & 3; - io.bg3.screenAddress = data << 8 & 0x7c00; + io.bg3.screenAddress = ppu.vramExt(data << 8 & 0xfc00) /*0x7c00*/; return; } case 0x210a: { //BG4SC io.bg4.screenSize = data >> 0 & 3; - io.bg4.screenAddress = data << 8 & 0x7c00; + io.bg4.screenAddress = ppu.vramExt(data << 8 & 0xfc00) /*0x7c00*/; return; } case 0x210b: { //BG12NBA - io.bg1.tiledataAddress = data << 12 & 0x7000; - io.bg2.tiledataAddress = data << 8 & 0x7000; + io.bg1.tiledataAddress = ppu.vramExt(data << 12 & 0xf000) /*0x7000*/; + io.bg2.tiledataAddress = ppu.vramExt(data << 8 & 0xf000) /*0x7000*/; return; } case 0x210c: { //BG34NBA - io.bg3.tiledataAddress = data << 12 & 0x7000; - io.bg4.tiledataAddress = data << 8 & 0x7000; + io.bg3.tiledataAddress = ppu.vramExt(data << 12 & 0xf000) /*0x7000*/; + io.bg4.tiledataAddress = ppu.vramExt(data << 8 & 0xf000) /*0x7000*/; return; } diff --git a/bsnes/sfc/ppu-fast/object.cpp b/bsnes/sfc/ppu-fast/object.cpp index 2d69a39b..1fc167a5 100644 --- a/bsnes/sfc/ppu-fast/object.cpp +++ b/bsnes/sfc/ppu-fast/object.cpp @@ -88,7 +88,7 @@ auto PPU::Line::renderObject(PPU::IO::Object& self) -> void { uint mirrorX = !object.hflip ? tileX : tileWidth - 1 - tileX; uint address = tiledataAddress + ((characterY + (characterX + mirrorX & 15)) << 4); - address = (address & 0x7ff0) + (y & 7); + address = ppu.vramExt((address & 0xfff0 /*0x7ff0*/) + (y & 7)); tile.data = ppu.vram[address + 0] << 0; tile.data |= ppu.vram[address + 8] << 16; diff --git a/bsnes/sfc/ppu-fast/ppu.cpp b/bsnes/sfc/ppu-fast/ppu.cpp index fff5781f..d7260af9 100644 --- a/bsnes/sfc/ppu-fast/ppu.cpp +++ b/bsnes/sfc/ppu-fast/ppu.cpp @@ -48,6 +48,7 @@ auto PPU::winXadHd(uint x, bool bel) const -> uint { || configuration.hacks.ppu.mode7.igwin >= 1 && ((bel ? io.col.window.belowMask : io.col.window.aboveMask) == 2))) ? configuration.hacks.ppu.mode7.igwinx * PPU::hdScale() : x; } auto PPU::strwin() const -> bool { return configuration.hacks.ppu.mode7.strwin; } +auto PPU::vramExt(uint addr) const -> uint { return addr & configuration.hacks.ppu.mode7.vramExt; } auto PPU::bgGrad() const -> uint { return !hd() ? 0 : configuration.hacks.ppu.mode7.bgGrad; } auto PPU::windRad() const -> uint { return !hd() ? 0 : configuration.hacks.ppu.mode7.windRad; } auto PPU::wsOverrideCandidate() const -> bool { return configuration.hacks.ppu.mode7.wsMode == 1; } diff --git a/bsnes/sfc/ppu-fast/ppu.hpp b/bsnes/sfc/ppu-fast/ppu.hpp index 19ee798c..b4a71c01 100644 --- a/bsnes/sfc/ppu-fast/ppu.hpp +++ b/bsnes/sfc/ppu-fast/ppu.hpp @@ -3,7 +3,6 @@ //limitations: //* mid-scanline effects not support //* vertical mosaic coordinates are not exact -//* (hardware-mod) 128KB VRAM mode not supported #define PPU PPUfast @@ -25,6 +24,7 @@ struct PPU : PPUcounter { alwaysinline auto winXad(uint x, bool bel) const -> uint; alwaysinline auto winXadHd(uint x, bool bel) const -> uint; alwaysinline auto strwin() const -> bool; + alwaysinline auto vramExt(uint addr) const -> uint; alwaysinline auto bgGrad() const -> uint; alwaysinline auto windRad() const -> uint; alwaysinline auto wsOverrideCandidate() const -> bool; @@ -287,7 +287,7 @@ struct PPU : PPUcounter { Latch latch; IO io; - uint16 vram[32 * 1024] = {}; + uint16 vram[32 * 1024 * 2] = {}; //0-ffff uint16 cgram[256] = {}; Object objects[128] = {}; diff --git a/bsnes/target-bsnes/program/game.cpp b/bsnes/target-bsnes/program/game.cpp index a897af80..f24f05c3 100644 --- a/bsnes/target-bsnes/program/game.cpp +++ b/bsnes/target-bsnes/program/game.cpp @@ -123,8 +123,23 @@ auto Program::loadSuperFamicom(string location) -> bool { rom.resize(rom.size() - 512); } - if(!superFamicom.patched) superFamicom.patched = applyPatchIPS(rom, location); - if(!superFamicom.patched) superFamicom.patched = applyPatchBPS(rom, location); + if (!superFamicom.patched) { + bool p = applyPatchBPS(rom, location, "") || applyPatchIPS(rom, location, ""); + superFamicom.patched = p; + if (p) { + p = applyPatchBPS(rom, location, "1") || applyPatchIPS(rom, location, "1"); + if (p) { + p = applyPatchBPS(rom, location, "2") || applyPatchIPS(rom, location, "2"); + if (p) { + p = applyPatchBPS(rom, location, "3") || applyPatchIPS(rom, location, "3"); + if (p) { + p = applyPatchBPS(rom, location, "4") || applyPatchIPS(rom, location, "4"); + } + } + } + } + } + auto heuristics = Heuristics::SuperFamicom(rom, location); auto sha256 = Hash::SHA256(rom).digest(); superFamicom.title = heuristics.title(); @@ -199,7 +214,7 @@ auto Program::loadGameBoy(string location) -> bool { } if(rom.size() < 0x4000) return false; - gameBoy.patched = applyPatchIPS(rom, location) || applyPatchBPS(rom, location); + gameBoy.patched = applyPatchIPS(rom, location, "") || applyPatchBPS(rom, location, ""); auto heuristics = Heuristics::GameBoy(rom, location); auto sha256 = Hash::SHA256(rom).digest(); if(auto document = BML::unserialize(string::read(locate("Database/Game Boy.bml")))) { @@ -236,7 +251,7 @@ auto Program::loadBSMemory(string location) -> bool { } if(rom.size() < 0x8000) return false; - bsMemory.patched = applyPatchIPS(rom, location) || applyPatchBPS(rom, location); + bsMemory.patched = applyPatchIPS(rom, location, "") || applyPatchBPS(rom, location, ""); auto heuristics = Heuristics::BSMemory(rom, location); auto sha256 = Hash::SHA256(rom).digest(); if(auto document = BML::unserialize(string::read(locate("Database/BS Memory.bml")))) { @@ -266,7 +281,7 @@ auto Program::loadSufamiTurboA(string location) -> bool { } if(rom.size() < 0x20000) return false; - sufamiTurboA.patched = applyPatchIPS(rom, location) || applyPatchBPS(rom, location); + sufamiTurboA.patched = applyPatchIPS(rom, location, "") || applyPatchBPS(rom, location, ""); auto heuristics = Heuristics::SufamiTurbo(rom, location); auto sha256 = Hash::SHA256(rom).digest(); if(auto document = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml")))) { @@ -296,7 +311,7 @@ auto Program::loadSufamiTurboB(string location) -> bool { } if(rom.size() < 0x20000) return false; - sufamiTurboB.patched = applyPatchIPS(rom, location) || applyPatchBPS(rom, location); + sufamiTurboB.patched = applyPatchIPS(rom, location, "") || applyPatchBPS(rom, location, ""); auto heuristics = Heuristics::SufamiTurbo(rom, location); auto sha256 = Hash::SHA256(rom).digest(); if(auto document = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml")))) { diff --git a/bsnes/target-bsnes/program/hacks.cpp b/bsnes/target-bsnes/program/hacks.cpp index dc55c9bc..c1de0d82 100644 --- a/bsnes/target-bsnes/program/hacks.cpp +++ b/bsnes/target-bsnes/program/hacks.cpp @@ -82,6 +82,7 @@ auto Program::hackCompatibility() -> void { emulator->configure("Hacks/PPU/Mode7/Igwin", settings.emulator.hack.ppu.mode7.igwin); emulator->configure("Hacks/PPU/Mode7/Igwinx", settings.emulator.hack.ppu.mode7.igwinx); emulator->configure("Hacks/PPU/Mode7/Strwin", false); + emulator->configure("Hacks/PPU/Mode7/VramExt", 0x7fff); emulator->configure("Hacks/PPU/Mode7/BgGrad", settings.emulator.hack.ppu.mode7.bgGrad); emulator->configure("Hacks/PPU/Mode7/WindRad", settings.emulator.hack.ppu.mode7.windRad); emulator->configure("Hacks/PPU/Mode7/WsMode", settings.emulator.hack.ppu.mode7.wsMode); @@ -114,12 +115,12 @@ auto Program::hackCompatibility() -> void { n = (n * 10) + (v - '0'); if (i == rso.size() || rso[i] < '0' || rso[i] > '9') { switch (c) { - // case 'p': //pixelAspectCorrect 0:off 1:on - // emulator->configure("Video/AspectCorrection", n == 1); - // break; - // case 'o': //overscan 0:216 1:224 (2:240 3:240f) - // emulator->configure("Video/Overscan", n == 1); - // break; + // case 'p': //pixelAspectCorrect 0:off 1:on [libretro exclusive] + // aspectcorrection = n == 1; + // break; + // case 'o': //overscan 0:216 1:224 (2:240 3:240f) [libretro exclusive] + // overscan = n == 1; + // break; case 'w': //widescreenMode 0:none 1:on 2:mode7 emulator->configure("Hacks/PPU/Mode7/WsMode", n == 1 ? 2 : (n == 2 ? 1 : 0)); break; @@ -196,6 +197,15 @@ auto Program::hackCompatibility() -> void { case 'S': //Stretch Window [for widescreen patches only] emulator->configure("Hacks/PPU/Mode7/Strwin", n == 2 ); break; + case 'v': //VRAM extension + emulator->configure("Hacks/PPU/Mode7/VramExt", n > 0 ? 0xffff : 0x7fff ); + break; + case 'f': //Scale factor 0:disable 1-10:scale + emulator->configure("Hacks/PPU/Mode7/Scale", n >= 0 && n <= 10 ? n : 2); + break; + case 'l': //Disable sprite limit + emulator->configure("Hacks/PPU/NoSpriteLimit", n == 1); + break; } c = -1; n = 0; diff --git a/bsnes/target-bsnes/program/patch.cpp b/bsnes/target-bsnes/program/patch.cpp index c696e0e1..ea061072 100644 --- a/bsnes/target-bsnes/program/patch.cpp +++ b/bsnes/target-bsnes/program/patch.cpp @@ -8,29 +8,29 @@ auto Program::appliedPatch() const -> bool { ); } -auto Program::applyPatchIPS(vector& data, string location) -> bool { +auto Program::applyPatchIPS(vector& data, string location, string suffix) -> bool { vector patch; if(location.endsWith("/")) { - patch = file::read({location, "patch.ips"}); + patch = file::read({location, "patch.ips", suffix}); } else if(location.iendsWith(".zip")) { Decode::ZIP archive; if(archive.open(location)) { for(auto& file : archive.file) { - if(file.name.iendsWith(".ips")) { + if(file.name.iendsWith({".ips", suffix})) { patch = archive.extract(file); break; } } } - if(!patch) patch = file::read(path("Patches", location, ".ips")); + if(!patch) patch = file::read(path("Patches", location, {".ips", suffix})); } else { - patch = file::read(path("Patches", location, ".ips")); + patch = file::read(path("Patches", location, {".ips", suffix})); } if(!patch) return false; bool headered = false; - if(MessageDialog().setAlignment(*presentation).setTitle({Location::prefix(location), ".ips"}).setText({ + if(MessageDialog().setAlignment(*presentation).setTitle({Location::prefix(location), ".ips", suffix}).setText({ "(You're seeing this prompt because IPS is a terrible patch file format,\n" " and nobody can agree on whether SNES ROMs should be headered or not.\n" " Please consider asking the patch author to use BPS patches instead.)\n\n" @@ -103,24 +103,24 @@ auto Program::applyPatchIPS(vector& data, string location) -> bool { #include -auto Program::applyPatchBPS(vector& input, string location) -> bool { +auto Program::applyPatchBPS(vector& input, string location, string suffix) -> bool { vector patch; if(location.endsWith("/")) { - patch = file::read({location, "patch.bps"}); + patch = file::read({location, "patch.bps", suffix}); } else if(location.iendsWith(".zip")) { Decode::ZIP archive; if(archive.open(location)) { for(auto& file : archive.file) { - if(file.name.iendsWith(".bps")) { + if(file.name.iendsWith({".bps", suffix})) { patch = archive.extract(file); break; } } } - if(!patch) patch = file::read(path("Patches", location, ".bps")); + if(!patch) patch = file::read(path("Patches", location, {".bps", suffix})); } else { - patch = file::read(path("Patches", location, ".bps")); + patch = file::read(path("Patches", location, {".bps", suffix})); } if(!patch) return false; diff --git a/bsnes/target-bsnes/program/program.hpp b/bsnes/target-bsnes/program/program.hpp index 3e16b22c..87c252b2 100644 --- a/bsnes/target-bsnes/program/program.hpp +++ b/bsnes/target-bsnes/program/program.hpp @@ -124,8 +124,8 @@ struct Program : Lock, Emulator::Platform { //patch.cpp auto appliedPatch() const -> bool; - auto applyPatchIPS(vector& data, string location) -> bool; - auto applyPatchBPS(vector& data, string location) -> bool; + auto applyPatchIPS(vector& data, string location, string suffix) -> bool; + auto applyPatchBPS(vector& data, string location, string suffix) -> bool; //hacks.cpp auto hackCompatibility() -> void; diff --git a/bsnes/target-libretro/libretro.cpp b/bsnes/target-libretro/libretro.cpp index 35c4645c..5af50465 100644 --- a/bsnes/target-libretro/libretro.cpp +++ b/bsnes/target-libretro/libretro.cpp @@ -504,6 +504,15 @@ static bool flush_variables() // returns whether video dimensions have changed ( emulator->configure("Hacks/PPU/Mode7/WindRad", val); } + variable = { "bsnes_mode7_strWin", nullptr }; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value) + { + if (strcmp(variable.value, "ON") == 0) + emulator->configure("Hacks/PPU/Mode7/Strwin", true); + else if (strcmp(variable.value, "OFF") == 0) + emulator->configure("Hacks/PPU/Mode7/StrwinE", false); + } + bool aspectcorrection = program->aspectcorrection; variable = { "bsnes_video_aspectcorrection", nullptr }; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value) @@ -536,6 +545,18 @@ static bool flush_variables() // returns whether video dimensions have changed ( emulator->configure("Video/Gamma", val); } + variable = { "bsnes_ips_headered", nullptr }; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value) + { + if (strcmp(variable.value, "ON") == 0) + program->ipsHeadered = true; + else if (strcmp(variable.value, "OFF") == 0) + program->ipsHeadered = false; + } + + //override with setting overrides (BSO) if any + program->applySettingOverrides(); + bool vc = program->overscan != overscan; // overscan changed program->overscan = overscan; vc = vc | program->aspectcorrection != aspectcorrection; // aspectcorrection changed @@ -758,6 +779,8 @@ static void set_environment_info(retro_environment_t cb) { "bsnes_video_luminance", "Luminance; 100|90|80|70|60|50|40|30|20|10|0" }, { "bsnes_video_saturation", "Saturation; 100|90|80|70|60|50|40|30|20|10|0|200|190|180|170|160|150|140|130|120|110" }, { "bsnes_video_gamma", "Gamma; 100|110|120|130|140|150|160|170|180|190|200" }, + { "bsnes_mode7_strWin", "Stretch Window (For WideScreen Hacks Only!); OFF|ON" }, + { "bsnes_ips_headered", "IPS Patches expect headered ROMs; OFF|ON" }, { nullptr }, }; cb(RETRO_ENVIRONMENT_SET_VARIABLES, const_cast(vars)); diff --git a/bsnes/target-libretro/program.cpp b/bsnes/target-libretro/program.cpp index 8bf44a07..9e8e28aa 100644 --- a/bsnes/target-libretro/program.cpp +++ b/bsnes/target-libretro/program.cpp @@ -48,7 +48,9 @@ struct Program : Emulator::Platform auto hackPatchMemory(vector& data) -> void; - auto applyPatchBPS(vector& data, string location) -> bool; + auto applyPatchBPS(vector& data, string location, string suffix) -> bool; + auto applyPatchIPS(vector& data, string location, string suffix) -> bool; + auto applySettingOverrides() -> void; vector rso; string base_name; @@ -57,7 +59,7 @@ struct Program : Emulator::Platform bool aspectcorrection = false; uint ws = 0; uint scale = 1; - + bool ipsHeadered = false; public: struct Game { @@ -229,6 +231,12 @@ auto Program::load() -> void { if (title == "ニチブツ・アーケード・クラシックス") emulator->configure("Hacks/Entropy", "None"); } + Program::applySettingOverrides(); + + emulator->power(); +} + +auto Program::applySettingOverrides() -> void { // setting override processing (copied from standalone target) if(rso) { int i = 0; @@ -250,12 +258,12 @@ auto Program::load() -> void { n = (n * 10) + (v - '0'); if (i == rso.size() || rso[i] < '0' || rso[i] > '9') { switch (c) { - // case 'p': //pixelAspectCorrect 0:off 1:on - // emulator->configure("Video/AspectCorrection", n == 1); - // break; - // case 'o': //overscan 0:216 1:224 (2:240 3:240f) - // emulator->configure("Video/Overscan", n == 1); - // break; + case 'p': //pixelAspectCorrect 0:off 1:on [libretro exclusive] + aspectcorrection = n == 1; + break; + case 'o': //overscan 0:216 1:224 (2:240 3:240f) [libretro exclusive] + overscan = n == 1; + break; case 'w': //widescreenMode 0:none 1:on 2:mode7 emulator->configure("Hacks/PPU/Mode7/WsMode", n == 1 ? 2 : (n == 2 ? 1 : 0)); break; @@ -332,6 +340,15 @@ auto Program::load() -> void { case 'S': //Stretch Window [for widescreen patches only] emulator->configure("Hacks/PPU/Mode7/Strwin", n == 2 ); break; + case 'v': //VRAM extension + emulator->configure("Hacks/PPU/Mode7/VramExt", n > 0 ? 0xffff : 0x7fff ); + break; + case 'f': //Scale factor 0:disable 1-10:scale + emulator->configure("Hacks/PPU/Mode7/Scale", n >= 0 && n <= 10 ? n : 2); + break; + case 'l': //Disable sprite limit + emulator->configure("Hacks/PPU/NoSpriteLimit", n == 1); + break; } c = -1; n = 0; @@ -340,8 +357,6 @@ auto Program::load() -> void { } } // END OF setting override processing (copied from standalone target) - - emulator->power(); } auto Program::load(uint id, string name, string type, vector options) -> Emulator::Platform::Load { @@ -611,7 +626,22 @@ auto Program::loadSuperFamicom(string location) -> bool // soft patching (copied from standalone target) // note: soft patching should be done via the libretro frontend // so this is only a workaround until that is possible - if(!superFamicom.patched) superFamicom.patched = applyPatchBPS(rom, location); + if (!superFamicom.patched) { + bool p = applyPatchBPS(rom, location, "") || applyPatchIPS(rom, location, ""); + superFamicom.patched = p; + if (p) { + p = applyPatchBPS(rom, location, "1") || applyPatchIPS(rom, location, "1"); + if (p) { + p = applyPatchBPS(rom, location, "2") || applyPatchIPS(rom, location, "2"); + if (p) { + p = applyPatchBPS(rom, location, "3") || applyPatchIPS(rom, location, "3"); + if (p) { + p = applyPatchBPS(rom, location, "4") || applyPatchIPS(rom, location, "4"); + } + } + } + } + } // END OF soft patching (copied from standalone target) // setting override loading (copied from standalone target) @@ -896,26 +926,26 @@ auto decodeGB(string& code) -> bool { } // soft patching (copied from standalone target), note: soft patching should be done via the libretro frontend, so this is only a workaround until that is possible -auto Program::applyPatchBPS(vector& input, string location) -> bool { +auto Program::applyPatchBPS(vector& input, string location, string suffix) -> bool { vector patch; if(location.endsWith("/")) { - patch = file::read({location, "patch.bps"}); + patch = file::read({location, "patch.bps", suffix}); } else if(location.iendsWith(".zip")) { Decode::ZIP archive; if(archive.open(location)) { for(auto& file : archive.file) { - if(file.name.iendsWith(".bps")) { + if(file.name.iendsWith({".bps", suffix})) { patch = archive.extract(file); break; } } } if(!patch) patch = file::read({Location::path(location), - Location::prefix(Location::file(location)), ".bps"}); + Location::prefix(Location::file(location)), ".bps", suffix}); } else { patch = file::read({Location::path(location), - Location::prefix(Location::file(location)), ".bps"}); + Location::prefix(Location::file(location)), ".bps", suffix}); } if(!patch) return false; @@ -931,4 +961,91 @@ auto Program::applyPatchBPS(vector& input, string location) -> bool { return false; } + +auto Program::applyPatchIPS(vector& data, string location, string suffix) -> bool { + vector patch; + + if(location.endsWith("/")) { + patch = file::read({location, "patch.ips", suffix}); + } else if(location.iendsWith(".zip")) { + Decode::ZIP archive; + if(archive.open(location)) { + for(auto& file : archive.file) { + if(file.name.iendsWith({".ips", suffix})) { + patch = archive.extract(file); + break; + } + } + } + if(!patch) patch = file::read({Location::path(location), + Location::prefix(Location::file(location)), ".ips", suffix}); + } else { + patch = file::read({Location::path(location), + Location::prefix(Location::file(location)), ".ips", suffix}); + } + + if(!patch) return false; + + //sanity checks + if(patch.size() < 8) return false; + if(patch[0] != 'P') return false; + if(patch[1] != 'A') return false; + if(patch[2] != 'T') return false; + if(patch[3] != 'C') return false; + if(patch[4] != 'H') return false; + + for(uint index = 5;;) { + if(index == patch.size() - 6) { + if(patch[index + 0] == 'E' && patch[index + 1] == 'O' && patch[index + 2] == 'F') { + uint32_t truncate = 0; + truncate |= patch[index + 3] << 16; + truncate |= patch[index + 4] << 8; + truncate |= patch[index + 5] << 0; + data.resize(truncate); + return true; + } + } + + if(index == patch.size() - 3) { + if(patch[index + 0] == 'E' && patch[index + 1] == 'O' && patch[index + 2] == 'F') { + return true; + } + } + + if(index >= patch.size()) break; + + int32_t offset = 0; + offset |= patch(index++, 0) << 16; + offset |= patch(index++, 0) << 8; + offset |= patch(index++, 0) << 0; + if(ipsHeadered) offset -= 512; + + uint16_t length = 0; + length |= patch(index++, 0) << 8; + length |= patch(index++, 0) << 0; + + if(length == 0) { + uint16_t repeat = 0; + repeat |= patch(index++, 0) << 8; + repeat |= patch(index++, 0) << 0; + + uint8_t fill = patch(index++, 0); + + while(repeat--) { + if(offset >= 0) data(offset) = fill; + offset++; + } + } else { + while(length--) { + if(offset >= 0) data(offset) = patch(index, 0); + offset++; + index++; + } + } + } + + //"EOF" marker not found in correct place + //technically should return false, but be permissive (data was already modified) + return true; +} // END OF soft patching (copied from standalone target) \ No newline at end of file diff --git a/hiro/GNUmakefile b/hiro/GNUmakefile index 51671b96..f28c2355 100644 --- a/hiro/GNUmakefile +++ b/hiro/GNUmakefile @@ -9,13 +9,13 @@ ifeq ($(platform),windows) endif ifeq ($(hiro),gtk2) - hiro.flags = $(flags.cpp) -DHIRO_GTK=2 $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0) - hiro.options = $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0) + hiro.flags = $(flags.cpp) -DHIRO_GTK=2 $(shell pkg-config --cflags gtk+-2.0) + hiro.options = $(shell pkg-config --libs gtk+-2.0) endif ifeq ($(hiro),gtk3) - hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0) -Wno-deprecated-declarations - hiro.options = $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0) + hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0) -Wno-deprecated-declarations + hiro.options = $(shell pkg-config --libs gtk+-3.0) endif endif @@ -36,13 +36,13 @@ ifneq ($(filter $(platform),linux bsd),) endif ifeq ($(hiro),gtk2) - hiro.flags = $(flags.cpp) -DHIRO_GTK=2 $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0) - hiro.options = -L/usr/local/lib -lX11 $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0) + hiro.flags = $(flags.cpp) -DHIRO_GTK=2 $(shell pkg-config --cflags gtk+-2.0) + hiro.options = -L/usr/local/lib -lX11 $(shell pkg-config --libs gtk+-2.0) endif ifeq ($(hiro),gtk3) - hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0 gtksourceview-3.0) -Wno-deprecated-declarations - hiro.options = -L/usr/local/lib -lX11 $(shell pkg-config --libs gtk+-3.0 gtksourceview-3.0) + hiro.flags = $(flags.cpp) -DHIRO_GTK=3 $(shell pkg-config --cflags gtk+-3.0) -Wno-deprecated-declarations + hiro.options = -L/usr/local/lib -lX11 $(shell pkg-config --libs gtk+-3.0) endif ifeq ($(hiro),qt4) diff --git a/hiro/components.hpp b/hiro/components.hpp index 3f387181..5e675f02 100644 --- a/hiro/components.hpp +++ b/hiro/components.hpp @@ -66,7 +66,7 @@ #define Hiro_ProgressBar #define Hiro_RadioButton #define Hiro_RadioLabel -#define Hiro_SourceEdit +//define Hiro_SourceEdit #define Hiro_TabFrame #define Hiro_TableView #define Hiro_TextEdit