mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-23 08:59:40 +00:00
Update to v104r01 release.
byuu says: Changelog: - gba/cpu: synchronize to the PPU, not oneself, when the CPU is stopped - this bug was patched in the official v104 release; but not in the .tar.xz archive - ms/vdp: backdrop color is on the second 16-entry palette, not the first [hex\_usr] - ms/vdp: fix background color 0 priority; fixes Alex Kidd in High Tech World text boxes [hex\_usr] - tomoko: choose first option when loading files via the command-line [hex\_usr] - icarus: lo/hi RAM addressing was backwards; M68K is big endian; fixes save files in Sonic 3 Many thanks to hex\_usr for the Master System / Game Gear VDP fix. That's a tricky system to get good technical information on. The fix should be correct, but please report if you spot any regressions just in case.
This commit is contained in:
parent
58d70c7c9a
commit
366e9cebff
@ -12,7 +12,7 @@ using namespace nall;
|
||||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "104";
|
||||
static const string Version = "104.01";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
@ -48,6 +48,8 @@ auto VDP::Background::run() -> void {
|
||||
output.color.bit(1) = vdp.vram[patternAddress + 1].bit(index);
|
||||
output.color.bit(2) = vdp.vram[patternAddress + 2].bit(index);
|
||||
output.color.bit(3) = vdp.vram[patternAddress + 3].bit(index);
|
||||
|
||||
if(output.color == 0) output.priority = 0;
|
||||
}
|
||||
|
||||
auto VDP::Background::power() -> void {
|
||||
|
@ -38,13 +38,14 @@ auto VDP::main() -> void {
|
||||
sprite.run();
|
||||
step(2);
|
||||
|
||||
uint12 color = palette(io.backdropColor);
|
||||
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
||||
color = palette(background.output.palette << 4 | background.output.color);
|
||||
} else if(sprite.output.color) {
|
||||
color = palette(16 | sprite.output.color);
|
||||
uint12 color = palette(16 | io.backdropColor);
|
||||
if(!io.leftClip || x >= 8) {
|
||||
if(background.output.priority || !sprite.output.color) {
|
||||
color = palette(background.output.palette << 4 | background.output.color);
|
||||
} else if(sprite.output.color) {
|
||||
color = palette(16 | sprite.output.color);
|
||||
}
|
||||
}
|
||||
if(x <= 7 && io.leftClip) color = palette(io.backdropColor);
|
||||
if(!io.displayEnable) color = 0;
|
||||
*screen++ = color;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
auto Cartridge::loadCartridge(Markup::Node node) -> void {
|
||||
information.title.cartridge = node["information/title"].text();
|
||||
auto board = node["board"];
|
||||
if(!region() || region() == "Auto") {
|
||||
if(region() == "Auto") {
|
||||
if(board["region"].text() == "ntsc") information.region = "NTSC";
|
||||
if(board["region"].text() == "pal") information.region = "PAL";
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ auto Program::load(uint id, string name, string type, string_vector options) ->
|
||||
if(mediumQueue) {
|
||||
auto entry = mediumQueue.takeLeft().split("|", 1L);
|
||||
location = entry.right();
|
||||
if(entry.size() == 1) option = options(0);
|
||||
if(entry.size() == 2) option = entry.left();
|
||||
} else {
|
||||
BrowserDialog dialog;
|
||||
|
@ -25,13 +25,13 @@ MegaDriveCartridge::MegaDriveCartridge(string location, uint8_t* data, uint size
|
||||
ramTo |= data[0x01ba] << 8;
|
||||
ramTo |= data[0x01bb] << 0;
|
||||
|
||||
if(!(ramFrom & 1) && !(ramTo & 1)) ramMode = "lo";
|
||||
if( (ramFrom & 1) && (ramTo & 1)) ramMode = "hi";
|
||||
if(!(ramFrom & 1) && !(ramTo & 1)) ramMode = "hi";
|
||||
if( (ramFrom & 1) && (ramTo & 1)) ramMode = "lo";
|
||||
if(!(ramFrom & 1) && (ramTo & 1)) ramMode = "word";
|
||||
|
||||
uint32_t ramSize = ramTo - ramFrom + 1;
|
||||
if(ramMode == "lo") ramSize = (ramTo >> 1) - (ramFrom >> 1) + 1;
|
||||
if(ramMode == "hi") ramSize = (ramTo >> 1) - (ramFrom >> 1) + 1;
|
||||
if(ramMode == "lo") ramSize = (ramTo >> 1) - (ramFrom >> 1) + 1;
|
||||
if(ramMode == "word") ramSize = ramTo - ramFrom + 1;
|
||||
if(ramMode != "none") ramSize = bit::round(min(0x20000, ramSize));
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <nall/mosaic/bitstream.hpp>
|
||||
#include <nall/mosaic/context.hpp>
|
||||
#include <nall/mosaic/parser.hpp>
|
@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace nall { namespace mosaic {
|
||||
|
||||
struct bitstream {
|
||||
~bitstream() {
|
||||
close();
|
||||
}
|
||||
|
||||
auto read(uint64_t addr) const -> bool {
|
||||
if(data == nullptr || (addr >> 3) >= size) return 0;
|
||||
uint mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||
return data[addr >> 3] & mask;
|
||||
}
|
||||
|
||||
auto write(uint64_t addr, bool value) -> void {
|
||||
if(data == nullptr || readonly == true || (addr >> 3) >= size) return;
|
||||
uint mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
|
||||
if(value == 0) data[addr >> 3] &= ~mask;
|
||||
if(value == 1) data[addr >> 3] |= mask;
|
||||
}
|
||||
|
||||
auto open(const string& filename) -> bool {
|
||||
readonly = false;
|
||||
if(fp.open(filename, filemap::mode::readwrite) == false) {
|
||||
readonly = true;
|
||||
if(fp.open(filename, filemap::mode::read) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
data = fp.data();
|
||||
size = fp.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto close() -> void {
|
||||
fp.close();
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
filemap fp;
|
||||
uint8_t* data = nullptr;
|
||||
uint size = 0;
|
||||
bool readonly = false;
|
||||
bool endian = 1;
|
||||
};
|
||||
|
||||
}}
|
@ -1,221 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace nall { namespace mosaic {
|
||||
|
||||
struct context {
|
||||
context() {
|
||||
reset();
|
||||
}
|
||||
|
||||
auto objectWidth() const -> uint { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
|
||||
auto objectHeight() const -> uint { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
|
||||
auto objectSize() const -> uint {
|
||||
uint size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
|
||||
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
|
||||
+ tileStride * mosaicWidth * mosaicHeight
|
||||
+ tileOffset * mosaicHeight;
|
||||
return max(1u, size);
|
||||
}
|
||||
|
||||
auto reset() -> void {
|
||||
offset = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
count = 0;
|
||||
|
||||
endian = 1;
|
||||
order = 0;
|
||||
depth = 1;
|
||||
|
||||
blockWidth = 1;
|
||||
blockHeight = 1;
|
||||
blockStride = 0;
|
||||
blockOffset = 0;
|
||||
block.reset();
|
||||
|
||||
tileWidth = 1;
|
||||
tileHeight = 1;
|
||||
tileStride = 0;
|
||||
tileOffset = 0;
|
||||
tile.reset();
|
||||
|
||||
mosaicWidth = 1;
|
||||
mosaicHeight = 1;
|
||||
mosaicStride = 0;
|
||||
mosaicOffset = 0;
|
||||
mosaic.reset();
|
||||
|
||||
paddingWidth = 0;
|
||||
paddingHeight = 0;
|
||||
paddingColor = 0;
|
||||
palette.reset();
|
||||
}
|
||||
|
||||
auto eval(const string& expression) -> uint {
|
||||
if(auto result = Eval::integer(expression)) return result();
|
||||
return 0u;
|
||||
}
|
||||
|
||||
auto eval(vector<uint>& buffer, const string& expression_) -> void {
|
||||
string expression = expression_;
|
||||
bool function = false;
|
||||
for(auto& c : expression) {
|
||||
if(c == '(') function = true;
|
||||
if(c == ')') function = false;
|
||||
if(c == ',' && function == true) c = ';';
|
||||
}
|
||||
|
||||
auto list = expression.split(",");
|
||||
for(auto& item : list) {
|
||||
item.strip();
|
||||
if(item.match("f(?*) ?*")) {
|
||||
item.trimLeft("f(", 1L);
|
||||
auto part = item.split(") ", 1L);
|
||||
auto args = part[0].split(";", 3L).strip();
|
||||
|
||||
uint length = eval(args(0, "0"));
|
||||
uint offset = eval(args(1, "0"));
|
||||
uint stride = eval(args(2, "0"));
|
||||
if(args.size() < 2) offset = buffer.size();
|
||||
if(args.size() < 3) stride = 1;
|
||||
|
||||
for(uint n = 0; n < length; n++) {
|
||||
string fn = part[1];
|
||||
fn.replace("n", string{n});
|
||||
fn.replace("o", string{offset});
|
||||
fn.replace("p", string{buffer.size()});
|
||||
buffer.resize(offset + 1);
|
||||
buffer[offset] = eval(fn);
|
||||
offset += stride;
|
||||
}
|
||||
} else if(item.match("base64*")) {
|
||||
uint offset = 0;
|
||||
item.trimLeft("base64", 1L);
|
||||
if(item.match("(?*) *")) {
|
||||
item.trimLeft("(", 1L);
|
||||
auto part = item.split(") ", 1L);
|
||||
offset = eval(part[0]);
|
||||
item = part(1, "");
|
||||
}
|
||||
item.strip();
|
||||
for(auto& c : item) {
|
||||
if(c >= 'A' && c <= 'Z') buffer.append(offset + c - 'A' + 0);
|
||||
if(c >= 'a' && c <= 'z') buffer.append(offset + c - 'a' + 26);
|
||||
if(c >= '0' && c <= '9') buffer.append(offset + c - '0' + 52);
|
||||
if(c == '-') buffer.append(offset + 62);
|
||||
if(c == '_') buffer.append(offset + 63);
|
||||
}
|
||||
} else if(item.match("file *")) {
|
||||
item.trimLeft("file ", 1L);
|
||||
item.strip();
|
||||
//...
|
||||
} else if(item) {
|
||||
buffer.append(eval(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto parse(const string& data) -> void {
|
||||
reset();
|
||||
|
||||
auto lines = data.split("\n");
|
||||
for(auto& line : lines) {
|
||||
auto part = line.split(":", 1L).strip();
|
||||
if(part.size() != 2) continue;
|
||||
|
||||
if(part[0] == "offset") offset = eval(part[1]);
|
||||
if(part[0] == "width") width = eval(part[1]);
|
||||
if(part[0] == "height") height = eval(part[1]);
|
||||
if(part[0] == "count") count = eval(part[1]);
|
||||
|
||||
if(part[0] == "endian") endian = eval(part[1]);
|
||||
if(part[0] == "order") order = eval(part[1]);
|
||||
if(part[0] == "depth") depth = eval(part[1]);
|
||||
|
||||
if(part[0] == "blockWidth") blockWidth = eval(part[1]);
|
||||
if(part[0] == "blockHeight") blockHeight = eval(part[1]);
|
||||
if(part[0] == "blockStride") blockStride = eval(part[1]);
|
||||
if(part[0] == "blockOffset") blockOffset = eval(part[1]);
|
||||
if(part[0] == "block") eval(block, part[1]);
|
||||
|
||||
if(part[0] == "tileWidth") tileWidth = eval(part[1]);
|
||||
if(part[0] == "tileHeight") tileHeight = eval(part[1]);
|
||||
if(part[0] == "tileStride") tileStride = eval(part[1]);
|
||||
if(part[0] == "tileOffset") tileOffset = eval(part[1]);
|
||||
if(part[0] == "tile") eval(tile, part[1]);
|
||||
|
||||
if(part[0] == "mosaicWidth") mosaicWidth = eval(part[1]);
|
||||
if(part[0] == "mosaicHeight") mosaicHeight = eval(part[1]);
|
||||
if(part[0] == "mosaicStride") mosaicStride = eval(part[1]);
|
||||
if(part[0] == "mosaicOffset") mosaicOffset = eval(part[1]);
|
||||
if(part[0] == "mosaic") eval(mosaic, part[1]);
|
||||
|
||||
if(part[0] == "paddingWidth") paddingWidth = eval(part[1]);
|
||||
if(part[0] == "paddingHeight") paddingHeight = eval(part[1]);
|
||||
if(part[0] == "paddingColor") paddingColor = eval(part[1]);
|
||||
if(part[0] == "palette") eval(palette, part[1]);
|
||||
}
|
||||
|
||||
sanitize();
|
||||
}
|
||||
|
||||
auto load(const string& filename) -> bool {
|
||||
if(auto filedata = string::read(filename)) {
|
||||
parse(filedata);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sanitize() -> void {
|
||||
if(depth < 1) depth = 1;
|
||||
if(depth > 24) depth = 24;
|
||||
|
||||
if(blockWidth < 1) blockWidth = 1;
|
||||
if(blockHeight < 1) blockHeight = 1;
|
||||
|
||||
if(tileWidth < 1) tileWidth = 1;
|
||||
if(tileHeight < 1) tileHeight = 1;
|
||||
|
||||
if(mosaicWidth < 1) mosaicWidth = 1;
|
||||
if(mosaicHeight < 1) mosaicHeight = 1;
|
||||
|
||||
//set alpha to full opacity
|
||||
paddingColor |= 255u << 24;
|
||||
for(auto& color : palette) color |= 255u << 24;
|
||||
}
|
||||
|
||||
uint offset;
|
||||
uint width;
|
||||
uint height;
|
||||
uint count;
|
||||
|
||||
bool endian; //0 = lsb, 1 = msb
|
||||
bool order; //0 = linear, 1 = planar
|
||||
uint depth; //1 - 24bpp
|
||||
|
||||
uint blockWidth;
|
||||
uint blockHeight;
|
||||
uint blockStride;
|
||||
uint blockOffset;
|
||||
vector<uint> block;
|
||||
|
||||
uint tileWidth;
|
||||
uint tileHeight;
|
||||
uint tileStride;
|
||||
uint tileOffset;
|
||||
vector<uint> tile;
|
||||
|
||||
uint mosaicWidth;
|
||||
uint mosaicHeight;
|
||||
uint mosaicStride;
|
||||
uint mosaicOffset;
|
||||
vector<uint> mosaic;
|
||||
|
||||
uint paddingWidth;
|
||||
uint paddingHeight;
|
||||
uint paddingColor;
|
||||
vector<uint> palette;
|
||||
};
|
||||
|
||||
}}
|
@ -1,119 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace nall { namespace mosaic {
|
||||
|
||||
struct parser {
|
||||
//export from bitstream to canvas
|
||||
auto load(bitstream& stream, uint64_t offset, context& ctx, uint width, uint height) -> void {
|
||||
canvas.allocate(width, height);
|
||||
canvas.fill(ctx.paddingColor);
|
||||
parse(1, stream, offset, ctx, width, height);
|
||||
}
|
||||
|
||||
//import from canvas to bitstream
|
||||
auto save(bitstream& stream, uint64_t offset, context& ctx) -> bool {
|
||||
if(stream.readonly) return false;
|
||||
parse(0, stream, offset, ctx, canvas.width(), canvas.height());
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
auto read(uint x, uint y) const -> uint32_t {
|
||||
uint addr = y * canvas.width() + x;
|
||||
if(addr >= canvas.width() * canvas.height()) return 0u;
|
||||
auto buffer = (uint32_t*)canvas.data();
|
||||
return buffer[addr];
|
||||
}
|
||||
|
||||
auto write(uint x, uint y, uint32_t data) -> void {
|
||||
uint addr = y * canvas.width() + x;
|
||||
if(addr >= canvas.width() * canvas.height()) return;
|
||||
auto buffer = (uint32_t*)canvas.data();
|
||||
buffer[addr] = data;
|
||||
}
|
||||
|
||||
auto parse(bool load, bitstream& stream, uint64_t offset, context& ctx, uint width, uint height) -> void {
|
||||
stream.endian = ctx.endian;
|
||||
uint canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
|
||||
uint canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
|
||||
uint bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
|
||||
|
||||
uint objectOffset = 0;
|
||||
for(uint objectY = 0; objectY < canvasHeight; objectY++) {
|
||||
for(uint objectX = 0; objectX < canvasWidth; objectX++) {
|
||||
if(objectOffset >= ctx.count && ctx.count > 0) break;
|
||||
uint objectIX = objectX * ctx.objectWidth();
|
||||
uint objectIY = objectY * ctx.objectHeight();
|
||||
objectOffset++;
|
||||
|
||||
uint mosaicOffset = 0;
|
||||
for(uint mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
|
||||
for(uint mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
|
||||
uint mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
|
||||
uint mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
|
||||
uint mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
|
||||
mosaicOffset++;
|
||||
|
||||
uint tileOffset = 0;
|
||||
for(uint tileY = 0; tileY < ctx.tileHeight; tileY++) {
|
||||
for(uint tileX = 0; tileX < ctx.tileWidth; tileX++) {
|
||||
uint tileData = ctx.tile(tileOffset, tileOffset);
|
||||
uint tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
|
||||
uint tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
|
||||
tileOffset++;
|
||||
|
||||
uint blockOffset = 0;
|
||||
for(uint blockY = 0; blockY < ctx.blockHeight; blockY++) {
|
||||
for(uint blockX = 0; blockX < ctx.blockWidth; blockX++) {
|
||||
if(load) {
|
||||
uint palette = 0;
|
||||
for(uint n = 0; n < ctx.depth; n++) {
|
||||
uint index = blockOffset++;
|
||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||||
palette |= stream.read(offset + ctx.block(index, index)) << n;
|
||||
}
|
||||
|
||||
write(
|
||||
objectIX + mosaicIX + tileIX + blockX,
|
||||
objectIY + mosaicIY + tileIY + blockY,
|
||||
ctx.palette(palette, palette)
|
||||
);
|
||||
} else /* save */ {
|
||||
uint32_t palette = read(
|
||||
objectIX + mosaicIX + tileIX + blockX,
|
||||
objectIY + mosaicIY + tileIY + blockY
|
||||
);
|
||||
|
||||
for(uint n = 0; n < ctx.depth; n++) {
|
||||
uint index = blockOffset++;
|
||||
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
|
||||
stream.write(offset + ctx.block(index, index), palette & 1);
|
||||
palette >>= 1;
|
||||
}
|
||||
}
|
||||
} //blockX
|
||||
} //blockY
|
||||
|
||||
offset += ctx.blockStride;
|
||||
} //tileX
|
||||
|
||||
offset += ctx.blockOffset;
|
||||
} //tileY
|
||||
|
||||
offset += ctx.tileStride;
|
||||
} //mosaicX
|
||||
|
||||
offset += ctx.tileOffset;
|
||||
} //mosaicY
|
||||
|
||||
offset += ctx.mosaicStride;
|
||||
} //objectX
|
||||
|
||||
offset += ctx.mosaicOffset;
|
||||
} //objectY
|
||||
}
|
||||
|
||||
image canvas;
|
||||
};
|
||||
|
||||
}}
|
Loading…
Reference in New Issue
Block a user