beta 10.6

This commit is contained in:
DerKoun 2021-06-17 23:03:05 +02:00
parent d2d7815c25
commit de27b9ea85
19 changed files with 288 additions and 92 deletions

View file

@ -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

View file

@ -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

View file

@ -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";

View file

@ -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 {

View file

@ -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);

View file

@ -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;

View file

@ -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*/];
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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; }

View file

@ -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 @@ public:
Latch latch;
IO io;
uint16 vram[32 * 1024] = {};
uint16 vram[32 * 1024 * 2] = {}; //0-ffff
uint16 cgram[256] = {};
Object objects[128] = {};

View file

@ -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")))) {

View file

@ -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;

View file

@ -8,29 +8,29 @@ auto Program::appliedPatch() const -> bool {
);
}
auto Program::applyPatchIPS(vector<uint8_t>& data, string location) -> bool {
auto Program::applyPatchIPS(vector<uint8_t>& data, string location, string suffix) -> bool {
vector<uint8_t> 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<uint8_t>& data, string location) -> bool {
#include <nall/beat/single/apply.hpp>
auto Program::applyPatchBPS(vector<uint8_t>& input, string location) -> bool {
auto Program::applyPatchBPS(vector<uint8_t>& input, string location, string suffix) -> bool {
vector<uint8_t> 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;

View file

@ -124,8 +124,8 @@ struct Program : Lock, Emulator::Platform {
//patch.cpp
auto appliedPatch() const -> bool;
auto applyPatchIPS(vector<uint8_t>& data, string location) -> bool;
auto applyPatchBPS(vector<uint8_t>& data, string location) -> bool;
auto applyPatchIPS(vector<uint8_t>& data, string location, string suffix) -> bool;
auto applyPatchBPS(vector<uint8_t>& data, string location, string suffix) -> bool;
//hacks.cpp
auto hackCompatibility() -> void;

View file

@ -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<retro_variable *>(vars));

View file

@ -48,7 +48,9 @@ struct Program : Emulator::Platform
auto hackPatchMemory(vector<uint8_t>& data) -> void;
auto applyPatchBPS(vector<uint8_t>& data, string location) -> bool;
auto applyPatchBPS(vector<uint8_t>& data, string location, string suffix) -> bool;
auto applyPatchIPS(vector<uint8_t>& data, string location, string suffix) -> bool;
auto applySettingOverrides() -> void;
vector<uint8_t> 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<string> 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<uint8_t>& input, string location) -> bool {
auto Program::applyPatchBPS(vector<uint8_t>& input, string location, string suffix) -> bool {
vector<uint8_t> 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<uint8_t>& input, string location) -> bool {
return false;
}
auto Program::applyPatchIPS(vector<uint8_t>& data, string location, string suffix) -> bool {
vector<uint8_t> 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)

View file

@ -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)

View file

@ -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