diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 0326ba99..2ba64a7a 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -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/"; diff --git a/higan/ms/interface/interface.cpp b/higan/ms/interface/interface.cpp index 61b27498..5f21b0cd 100644 --- a/higan/ms/interface/interface.cpp +++ b/higan/ms/interface/interface.cpp @@ -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 { diff --git a/higan/ms/vdp/background.cpp b/higan/ms/vdp/background.cpp new file mode 100644 index 00000000..96a91f2c --- /dev/null +++ b/higan/ms/vdp/background.cpp @@ -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)); +} diff --git a/higan/ms/vdp/io.cpp b/higan/ms/vdp/io.cpp index bce2c07f..6e271baf 100644 --- a/higan/ms/vdp/io.cpp +++ b/higan/ms/vdp/io.cpp @@ -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; } } diff --git a/higan/ms/vdp/sprite.cpp b/higan/ms/vdp/sprite.cpp new file mode 100644 index 00000000..cb64beba --- /dev/null +++ b/higan/ms/vdp/sprite.cpp @@ -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)); +} diff --git a/higan/ms/vdp/vdp.cpp b/higan/ms/vdp/vdp.cpp index ecd1d270..fd5885f1 100644 --- a/higan/ms/vdp/vdp.cpp +++ b/higan/ms/vdp/vdp.cpp @@ -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(); } } diff --git a/higan/ms/vdp/vdp.hpp b/higan/ms/vdp/vdp.hpp index 79d5d03a..e72da2a8 100644 --- a/higan/ms/vdp/vdp.hpp +++ b/higan/ms/vdp/vdp.hpp @@ -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 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 diff --git a/higan/target-tomoko/GNUmakefile b/higan/target-tomoko/GNUmakefile index dbcb4f4b..d518f062 100644 --- a/higan/target-tomoko/GNUmakefile +++ b/higan/target-tomoko/GNUmakefile @@ -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 diff --git a/icarus/GNUmakefile b/icarus/GNUmakefile index fc201db4..4cf51b68 100644 --- a/icarus/GNUmakefile +++ b/icarus/GNUmakefile @@ -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) diff --git a/nall/GNUmakefile b/nall/GNUmakefile index 59f07f6b..283335a8 100644 --- a/nall/GNUmakefile +++ b/nall/GNUmakefile @@ -70,6 +70,7 @@ endif # windows settings ifeq ($(platform),windows) link += -lws2_32 -lole32 + windres := windres endif # macosx settings