mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r25 release.
byuu says: Changelog: - SMS: emulated VDP mode 4 graphical output (background, sprites) - added $(windres) to icarus as well I'm sure the VDP emulation is still really, really buggy, but essentially I handle: - mode 4 rendering - background scrolling - background hscroll lock - background vscroll lock - background nametable relocation - sprite nametable relocation - sprite tiledata relocation - sprite 192-line y=0xd0 edge case (end sprite rendering) - sprite 8-pixel x-coordinate displacement - sprite extended size (height only in mode 4) - sprite overflow - sprite collision - left column masking - display disable - backdrop color - 192, 224, 240 height I do not support: - mode 2 rendering - sprite zoom - disallowing 240 height in NTSC mode - PAL mode - probably lots more
This commit is contained in:
parent
e30780bb72
commit
5bdf55f08f
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "101.25";
|
||||
static const string Version = "101.26";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -66,7 +66,15 @@ auto Interface::videoColors() -> uint32 {
|
|||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
return 0;
|
||||
uint2 B = color >> 4;
|
||||
uint2 G = color >> 2;
|
||||
uint2 R = color >> 0;
|
||||
|
||||
uint64 r = image::normalize(R, 2, 16);
|
||||
uint64 g = image::normalize(G, 2, 16);
|
||||
uint64 b = image::normalize(B, 2, 16);
|
||||
|
||||
return r << 32 | g << 16 | b << 0;
|
||||
}
|
||||
|
||||
auto Interface::audioFrequency() -> double {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
auto VDP::Background::scanline() -> void {
|
||||
state.x = 0;
|
||||
state.y = vdp.io.vcounter;
|
||||
}
|
||||
|
||||
auto VDP::Background::run() -> void {
|
||||
if(state.y >= vdp.vlines()) {
|
||||
output.color = 0;
|
||||
output.palette = 0;
|
||||
output.priority = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 hoffset = state.x;
|
||||
if(!vdp.io.horizontalScrollLock || hoffset >= 16) hoffset += vdp.io.hscroll;
|
||||
|
||||
uint8 voffset = state.y;
|
||||
if(!vdp.io.verticalScrollLock || hoffset <= 191) voffset += vdp.io.vscroll;
|
||||
|
||||
uint14 nameTableAddress;
|
||||
if(vdp.vlines() == 192) {
|
||||
nameTableAddress = vdp.io.nameTableAddress << 11;
|
||||
} else {
|
||||
nameTableAddress = (vdp.io.nameTableAddress & ~1) << 11 | 0x700;
|
||||
}
|
||||
nameTableAddress += ((voffset >> 3) << 6) + ((hoffset >> 3) << 1);
|
||||
|
||||
uint16 tiledata;
|
||||
tiledata = vdp.vram[nameTableAddress + 0] << 0;
|
||||
tiledata |= vdp.vram[nameTableAddress + 1] << 8;
|
||||
|
||||
uint14 patternAddress = tiledata.bits(0,8) << 5;
|
||||
if(tiledata.bit(9)) hoffset ^= 7;
|
||||
if(tiledata.bit(10)) voffset ^= 7;
|
||||
output.palette = tiledata.bit(11);
|
||||
output.priority = tiledata.bit(12);
|
||||
|
||||
auto index = hoffset & 7;
|
||||
patternAddress += (voffset & 7) << 2;
|
||||
output.color.bit(0) = vdp.vram[patternAddress + 0].bit(index);
|
||||
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);
|
||||
|
||||
state.x++;
|
||||
}
|
||||
|
||||
auto VDP::Background::power() -> void {
|
||||
}
|
||||
|
||||
auto VDP::Background::reset() -> void {
|
||||
memory::fill(&state, sizeof(State));
|
||||
memory::fill(&output, sizeof(Output));
|
||||
}
|
|
@ -50,7 +50,7 @@ auto VDP::data(uint8 data) -> void {
|
|||
if(io.code <= 2) {
|
||||
vram[io.address++] = data;
|
||||
} else {
|
||||
cram[io.address++ & 0x3f] = data;
|
||||
cram[io.address++ & 0x1f] = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
auto VDP::Sprite::scanline() -> void {
|
||||
state.x = 0;
|
||||
state.y = vdp.io.vcounter;
|
||||
objects.reset();
|
||||
|
||||
bool large = vdp.io.extendedHeight;
|
||||
uint14 attributeAddress = vdp.io.spriteAttributeTableAddress << 8;
|
||||
for(uint index : range(64)) {
|
||||
uint8 y = vdp.vram[attributeAddress + index];
|
||||
uint8 x = vdp.vram[attributeAddress + 0x80 + (index << 1)];
|
||||
uint8 pattern = vdp.vram[attributeAddress + 0x81 + (index << 1)];
|
||||
if(vdp.vlines() == 192 && y == 0xd0) break;
|
||||
|
||||
if(vdp.io.spriteShift) x -= 8;
|
||||
y += 1;
|
||||
if(state.y < y) continue;
|
||||
if(state.y > y + (large ? 15 : 7)) continue;
|
||||
|
||||
if(large) pattern.bit(0) = 0;
|
||||
|
||||
objects.append({x, y, pattern});
|
||||
if(objects.size() == 8) {
|
||||
vdp.io.spriteOverflow = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::Sprite::run() -> void {
|
||||
output.color = 0;
|
||||
|
||||
if(state.y >= vdp.vlines()) return;
|
||||
|
||||
bool large = vdp.io.extendedHeight;
|
||||
for(auto& o : objects) {
|
||||
if(state.x < o.x) continue;
|
||||
if(state.x > o.x + 7) continue;
|
||||
|
||||
uint x = o.x - state.x;
|
||||
uint y = o.y - state.y;
|
||||
|
||||
uint14 address = vdp.io.spritePatternTableAddress << 13;
|
||||
address += o.pattern << 5;
|
||||
address += (y & (large ? 15 : 7)) << 2;
|
||||
|
||||
uint4 color;
|
||||
color.bit(0) = vdp.vram[address + 0].bit(x & 7);
|
||||
color.bit(1) = vdp.vram[address + 1].bit(x & 7);
|
||||
color.bit(2) = vdp.vram[address + 2].bit(x & 7);
|
||||
color.bit(3) = vdp.vram[address + 3].bit(x & 7);
|
||||
if(color == 0) continue;
|
||||
|
||||
if(output.color) {
|
||||
vdp.io.spriteCollision = true;
|
||||
break;
|
||||
}
|
||||
|
||||
output.color = color;
|
||||
}
|
||||
|
||||
state.x++;
|
||||
}
|
||||
|
||||
auto VDP::Sprite::power() -> void {
|
||||
}
|
||||
|
||||
auto VDP::Sprite::reset() -> void {
|
||||
memory::fill(&state, sizeof(State));
|
||||
memory::fill(&output, sizeof(Output));
|
||||
}
|
|
@ -4,6 +4,8 @@ namespace MasterSystem {
|
|||
|
||||
VDP vdp;
|
||||
#include "io.cpp"
|
||||
#include "background.cpp"
|
||||
#include "sprite.cpp"
|
||||
|
||||
auto VDP::Enter() -> void {
|
||||
while(true) scheduler.synchronize(), vdp.main();
|
||||
|
@ -15,16 +17,34 @@ auto VDP::main() -> void {
|
|||
io.lcounter = io.lineCounter;
|
||||
io.intLine = 1;
|
||||
}
|
||||
} else {
|
||||
io.lcounter = io.lineCounter;
|
||||
}
|
||||
|
||||
if(io.vcounter == vlines() + 1) {
|
||||
io.lcounter = io.lineCounter;
|
||||
io.intFrame = 1;
|
||||
}
|
||||
|
||||
for(uint x : range(684)) {
|
||||
step(1);
|
||||
background.scanline();
|
||||
sprite.scanline();
|
||||
|
||||
//684 clocks/scanline
|
||||
for(uint x : range(256)) {
|
||||
background.run();
|
||||
sprite.run();
|
||||
step(2);
|
||||
|
||||
uint5 color = cram[16 | io.backdropColor];
|
||||
if(background.output.color && (background.output.priority || !sprite.output.color)) {
|
||||
color = cram[background.output.palette << 4 | background.output.color];
|
||||
} else if(sprite.output.color) {
|
||||
color = cram[16 | sprite.output.color];
|
||||
}
|
||||
if(x <= 7 && io.leftClip) color = cram[7];
|
||||
if(!io.displayEnable) color = 0;
|
||||
buffer[io.vcounter * 256 + x] = color;
|
||||
}
|
||||
step(172);
|
||||
|
||||
if(io.vcounter == 240) scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
|
@ -59,12 +79,17 @@ auto VDP::vblank() -> bool {
|
|||
}
|
||||
|
||||
auto VDP::power() -> void {
|
||||
background.power();
|
||||
sprite.power();
|
||||
}
|
||||
|
||||
auto VDP::reset() -> void {
|
||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||
|
||||
memory::fill(&io, sizeof(IO));
|
||||
|
||||
background.reset();
|
||||
sprite.reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,10 +22,56 @@ struct VDP : Thread {
|
|||
auto control(uint8) -> void;
|
||||
auto registerWrite(uint4 addr, uint8 data) -> void;
|
||||
|
||||
//background.cpp
|
||||
struct Background {
|
||||
auto scanline() -> void;
|
||||
auto run() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
struct State {
|
||||
uint x;
|
||||
uint y;
|
||||
} state;
|
||||
|
||||
struct Output {
|
||||
uint4 color;
|
||||
uint1 palette;
|
||||
uint1 priority;
|
||||
} output;
|
||||
} background;
|
||||
|
||||
//sprite.cpp
|
||||
struct Sprite {
|
||||
auto scanline() -> void;
|
||||
auto run() -> void;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
struct Object {
|
||||
uint8 x;
|
||||
uint8 y;
|
||||
uint8 pattern;
|
||||
};
|
||||
|
||||
struct State {
|
||||
uint x;
|
||||
uint y;
|
||||
} state;
|
||||
|
||||
struct Output {
|
||||
uint4 color;
|
||||
} output;
|
||||
|
||||
array<Object, 8> objects;
|
||||
} sprite;
|
||||
|
||||
private:
|
||||
uint32 buffer[256 * 240];
|
||||
uint32 buffer[256 * 262];
|
||||
uint8 vram[0x4000];
|
||||
uint8 cram[0x40];
|
||||
uint8 cram[0x20];
|
||||
|
||||
struct IO {
|
||||
uint vcounter; //vertical counter
|
||||
|
|
|
@ -20,7 +20,6 @@ ifeq ($(platform),windows)
|
|||
ruby += video.direct3d video.wgl video.directdraw video.gdi
|
||||
ruby += audio.wasapi audio.xaudio2 audio.directsound
|
||||
ruby += input.windows
|
||||
windres := windres
|
||||
else ifeq ($(platform),macosx)
|
||||
ruby += video.cgl
|
||||
ruby += audio.openal
|
||||
|
|
|
@ -29,7 +29,7 @@ obj/icarus.o: icarus.cpp $(call rwildcard,core/) $(call rwildcard,heuristics/) $
|
|||
$(compiler) $(cppflags) $(flags) -o obj/icarus.o -c icarus.cpp
|
||||
|
||||
obj/resource.o:
|
||||
windres ../hiro/windows/hiro.rc obj/resource.o
|
||||
$(windres) ../hiro/windows/hiro.rc obj/resource.o
|
||||
|
||||
clean:
|
||||
ifeq ($(platform),macosx)
|
||||
|
|
|
@ -70,6 +70,7 @@ endif
|
|||
# windows settings
|
||||
ifeq ($(platform),windows)
|
||||
link += -lws2_32 -lole32
|
||||
windres := windres
|
||||
endif
|
||||
|
||||
# macosx settings
|
||||
|
|
Loading…
Reference in New Issue