mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r70 release.
byuu says: Changelog: - Interface::displays() -> vector<Display> → Interface::display() -> Display - <Platform::videoRefresh(display>, ...) → <Platform::videoFrame>(...) - <Platform::audioSample>(...) → <Platform::audioFrame>(...) - higan, icarus: use AboutDialog class instead of ad-hoc implementations - about dialog is now modal, but now has a clickable website URL - icarus: reverted if constexpr for now - MSX: implemented basic CPU, VDP support I took out the multiple displays support thing because it was never really implemented fully (Emulator::Video and the GUIs both ignored it) or used anyway. If it ends up necessary in the future, I'll worry about it then. There's enough MSX emulation now to run Mr. Do! without sound or input. I'm shipping higan with C-BIOS 0.29a, although it likely won't be good enough in the future (eg it can't do BASIC, floppy disk, or cassette loading.) I have keyboard and (not working) AY-3-8910 support in a different branch, so that won't take too long to implement. Main problem is naming all the darned keyboard keys. I think I need to change settings.bml's input mapping lines so that the key names are values instead of node names, so that any characters can appear inside of them. It turns out my MSX set uses .rom for the file extensions ... gods. So, icarus can't really import them like this. I may have to re-design icarus' importer to stop caring about the file extension and instead ask you what kind of games you are importing. There's no way icarus can heuristically guess what systems the images belong to, because many systems don't have any standardized magic bytes. I'm struggling with where to put SG-1000, SC-3000, ColecoVision, Coleco Adam stuff. I think they need to be split to two separate higan subfolders (sg and cv, most likely ...) The MS/GG share a very customized and extended VDP that the other systems don't have. The Sega and Coleco older hardware share the same TMS9918 as the MSX, yet have very different memory maps and peripherals that I don't want to mix together. Especially if we start getting into the computer-variants more.
This commit is contained in:
parent
cac3858f65
commit
79be6f2355
|
@ -64,7 +64,7 @@ auto Audio::process() -> void {
|
|||
if(balance > 0.0) samples[0] *= 1.0 - balance;
|
||||
}
|
||||
|
||||
platform->audioSample(samples, channels);
|
||||
platform->audioFrame(samples, channels);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.69";
|
||||
static const string Version = "106.70";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -54,7 +54,7 @@ struct Interface {
|
|||
//information
|
||||
virtual auto information() -> Information { return {}; }
|
||||
|
||||
virtual auto displays() -> vector<Display> { return {}; }
|
||||
virtual auto display() -> Display { return {}; }
|
||||
virtual auto color(uint32 color) -> uint64 { return 0; }
|
||||
|
||||
//game interface
|
||||
|
|
|
@ -16,8 +16,8 @@ struct Platform {
|
|||
virtual auto path(uint id) -> string { return ""; }
|
||||
virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; }
|
||||
virtual auto load(uint id, string name, string type, vector<string> options = {}) -> Load { return {}; }
|
||||
virtual auto videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void {}
|
||||
virtual auto audioSample(const double* samples, uint channels) -> void {}
|
||||
virtual auto videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void {}
|
||||
virtual auto audioFrame(const double* samples, uint channels) -> void {}
|
||||
virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; }
|
||||
virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {}
|
||||
virtual auto dipSettings(Markup::Node node) -> uint { return 0; }
|
||||
|
|
|
@ -28,7 +28,7 @@ auto Video::setPalette() -> void {
|
|||
if(!interface) return;
|
||||
|
||||
delete palette;
|
||||
colors = interface->displays()[0].colors;
|
||||
colors = interface->display().colors;
|
||||
palette = new uint32[colors];
|
||||
for(auto index : range(colors)) {
|
||||
uint64 color = interface->color(index);
|
||||
|
@ -185,7 +185,7 @@ auto Video::refresh(uint32* input, uint pitch, uint width, uint height) -> void
|
|||
}
|
||||
}
|
||||
|
||||
platform->videoRefresh(0, output, width * sizeof(uint32), width, height);
|
||||
platform->videoFrame(output, width * sizeof(uint32), width, height);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ auto Interface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 9;
|
||||
|
@ -23,7 +23,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
display.internalHeight = 240;
|
||||
display.aspectCorrection = 8.0 / 7.0;
|
||||
display.refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::color(uint32 n) -> uint64 {
|
||||
|
|
|
@ -23,7 +23,7 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
|
|
|
@ -7,7 +7,7 @@ Settings settings;
|
|||
#include "game-boy.cpp"
|
||||
#include "game-boy-color.cpp"
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::LCD;
|
||||
display.colors = Model::GameBoyColor() ? 1 << 15 : 1 << 2;
|
||||
|
@ -17,7 +17,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
display.internalHeight = 144;
|
||||
display.aspectCorrection = 1.0;
|
||||
display.refreshRate = (4.0 * 1024.0 * 1024.0) / (154.0 * 456.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
|
|
|
@ -23,7 +23,7 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto hashes() -> vector<string> override;
|
||||
|
|
|
@ -12,7 +12,7 @@ auto Interface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::LCD;
|
||||
display.colors = 1 << 15;
|
||||
|
@ -26,7 +26,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
swap(display.width, display.height);
|
||||
swap(display.internalWidth, display.internalHeight);
|
||||
}
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -20,7 +20,7 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
|
|
|
@ -13,7 +13,7 @@ auto Interface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 3 * (1 << 9);
|
||||
|
@ -23,7 +23,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
display.internalHeight = 480;
|
||||
display.aspectCorrection = 1.0;
|
||||
display.refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -24,7 +24,7 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
|
|
|
@ -6,7 +6,7 @@ auto ColecoVisionInterface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto ColecoVisionInterface::displays() -> vector<Display> {
|
||||
auto ColecoVisionInterface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 4;
|
||||
|
@ -17,7 +17,7 @@ auto ColecoVisionInterface::displays() -> vector<Display> {
|
|||
display.aspectCorrection = 1.0;
|
||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto ColecoVisionInterface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -6,7 +6,7 @@ auto GameGearInterface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto GameGearInterface::displays() -> vector<Display> {
|
||||
auto GameGearInterface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::LCD;
|
||||
display.colors = 1 << 12;
|
||||
|
@ -16,7 +16,7 @@ auto GameGearInterface::displays() -> vector<Display> {
|
|||
display.internalHeight = 144;
|
||||
display.aspectCorrection = 1.0;
|
||||
display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto GameGearInterface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -53,7 +53,7 @@ struct Interface : Emulator::Interface {
|
|||
struct ColecoVisionInterface : Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
|
@ -69,7 +69,7 @@ struct ColecoVisionInterface : Interface {
|
|||
struct SG1000Interface : Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
|
@ -85,7 +85,7 @@ struct SG1000Interface : Interface {
|
|||
struct SC3000Interface : Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
|
@ -101,7 +101,7 @@ struct SC3000Interface : Interface {
|
|||
struct MasterSystemInterface : Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
|
@ -117,7 +117,7 @@ struct MasterSystemInterface : Interface {
|
|||
struct GameGearInterface : Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
|
|
|
@ -6,7 +6,7 @@ auto MasterSystemInterface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto MasterSystemInterface::displays() -> vector<Display> {
|
||||
auto MasterSystemInterface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 6;
|
||||
|
@ -17,7 +17,7 @@ auto MasterSystemInterface::displays() -> vector<Display> {
|
|||
display.aspectCorrection = 8.0 / 7.0;
|
||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto MasterSystemInterface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -6,7 +6,7 @@ auto SC3000Interface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto SC3000Interface::displays() -> vector<Display> {
|
||||
auto SC3000Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 4;
|
||||
|
@ -17,7 +17,7 @@ auto SC3000Interface::displays() -> vector<Display> {
|
|||
display.aspectCorrection = 1.0;
|
||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto SC3000Interface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -6,7 +6,7 @@ auto SG1000Interface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto SG1000Interface::displays() -> vector<Display> {
|
||||
auto SG1000Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 4;
|
||||
|
@ -17,7 +17,7 @@ auto SG1000Interface::displays() -> vector<Display> {
|
|||
display.aspectCorrection = 1.0;
|
||||
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto SG1000Interface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -57,13 +57,8 @@ auto VDP::Background::graphics2(uint8 hoffset, uint9 voffset) -> void {
|
|||
patternAddress.bits(3,10) = pattern;
|
||||
if(voffset >= 64 && voffset <= 127) patternAddress.bit(11) = vdp.io.patternTableAddress.bit(0);
|
||||
if(voffset >= 128 && voffset <= 191) patternAddress.bit(12) = vdp.io.patternTableAddress.bit(1);
|
||||
uint14 colorAddress = patternAddress;
|
||||
patternAddress.bit(13) = vdp.io.patternTableAddress.bit(2);
|
||||
|
||||
uint14 colorAddress;
|
||||
colorAddress.bits(0, 2) = voffset.bits(0,2);
|
||||
colorAddress.bits(3,10) = pattern;
|
||||
if(voffset >= 64 && voffset <= 127) colorAddress.bit(11) = vdp.io.patternTableAddress.bit(0);
|
||||
if(voffset >= 128 && voffset <= 191) colorAddress.bit(12) = vdp.io.patternTableAddress.bit(1);
|
||||
colorAddress.bit(13) = vdp.io.colorTableAddress.bit(7);
|
||||
|
||||
uint8 colorMask = vdp.io.colorTableAddress.bits(0,6) << 1 | 1;
|
||||
|
|
|
@ -58,4 +58,11 @@ auto Cartridge::unload() -> void {
|
|||
auto Cartridge::power() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::read(uint16 address) -> uint8 {
|
||||
return rom.read(address);
|
||||
}
|
||||
|
||||
auto Cartridge::write(uint16 address, uint8 data) -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ struct Cartridge {
|
|||
|
||||
auto power() -> void;
|
||||
|
||||
auto read(uint16 address) -> uint8;
|
||||
auto write(uint16 address, uint8 data) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
|
|
|
@ -11,11 +11,14 @@ auto CPU::Enter() -> void {
|
|||
}
|
||||
|
||||
auto CPU::main() -> void {
|
||||
if(io.irqLine) irq(1, 0x0038, 0xff);
|
||||
instruction();
|
||||
}
|
||||
|
||||
auto CPU::step(uint clocks) -> void {
|
||||
Thread::step(clocks);
|
||||
synchronize(vdp);
|
||||
synchronize(psg);
|
||||
}
|
||||
|
||||
auto CPU::synchronizing() const -> bool {
|
||||
|
@ -23,6 +26,19 @@ auto CPU::synchronizing() const -> bool {
|
|||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
Z80::bus = this;
|
||||
Z80::power();
|
||||
create(CPU::Enter, system.colorburst());
|
||||
|
||||
r.pc = 0x0000; //reset vector address
|
||||
|
||||
ram.allocate(0x10000);
|
||||
|
||||
io = {};
|
||||
}
|
||||
|
||||
auto CPU::setIRQ(bool line) -> void {
|
||||
io.irqLine = line;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
|
|||
auto synchronizing() const -> bool override;
|
||||
|
||||
auto power() -> void;
|
||||
auto setIRQ(bool) -> void;
|
||||
|
||||
//memory.cpp
|
||||
auto read(uint16 address) -> uint8 override;
|
||||
|
@ -16,6 +17,14 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
|
|||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
Emulator::Memory::Writable<uint8> ram;
|
||||
|
||||
struct IO {
|
||||
uint1 irqLine;
|
||||
uint2 slot[4];
|
||||
} io;
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
|
|
@ -1,13 +1,65 @@
|
|||
auto CPU::read(uint16 address) -> uint8 {
|
||||
uint2 slot = io.slot[address.bits(14,15)];
|
||||
|
||||
if(slot == 0) {
|
||||
if(!address.bit(15)) return system.bios.read(address);
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
if(slot == 1) {
|
||||
return cartridge.read(address);
|
||||
}
|
||||
|
||||
if(slot == 2) {
|
||||
return ram.read(address);
|
||||
}
|
||||
|
||||
if(slot == 3) {
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
auto CPU::write(uint16 address, uint8 data) -> void {
|
||||
uint2 slot = io.slot[address.bits(14,15)];
|
||||
|
||||
if(slot == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(slot == 1) {
|
||||
return cartridge.write(address, data);
|
||||
}
|
||||
|
||||
if(slot == 2) {
|
||||
return ram.write(address, data);
|
||||
}
|
||||
|
||||
if(slot == 3) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto CPU::in(uint8 address) -> uint8 {
|
||||
switch(address) {
|
||||
case 0x98: return vdp.data();
|
||||
case 0x99: return vdp.status();
|
||||
case 0xa8: return io.slot[0] << 0
|
||||
| io.slot[1] << 2
|
||||
| io.slot[2] << 4
|
||||
| io.slot[3] << 6;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
auto CPU::out(uint8 address, uint8 data) -> void {
|
||||
switch(address) {
|
||||
case 0x98: return vdp.data(data);
|
||||
case 0x99: return vdp.control(data);
|
||||
case 0xa8: io.slot[0] = data.bits(0,1);
|
||||
io.slot[1] = data.bits(2,3);
|
||||
io.slot[2] = data.bits(4,5);
|
||||
io.slot[3] = data.bits(6,7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ auto Interface::information() -> Information {
|
|||
Information information;
|
||||
information.manufacturer = "";
|
||||
information.name = "MSX";
|
||||
information.extension = ".msx";
|
||||
information.extension = "msx";
|
||||
return information;
|
||||
}
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 4;
|
||||
|
@ -20,40 +20,58 @@ auto Interface::displays() -> vector<Display> {
|
|||
display.internalHeight = 192;
|
||||
display.aspectCorrection = 1.0;
|
||||
display.refreshRate = 60.0; //todo: PAL
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
switch(color.bits(0,3)) {
|
||||
case 0: return 0x0000'0000'0000ull; //transparent
|
||||
case 1: return 0x0000'0000'0000ull; //black
|
||||
case 2: return 0x2121'c8c8'4242ull; //medium green
|
||||
case 3: return 0x5e5e'dcdc'7878ull; //light green
|
||||
case 4: return 0x5454'5555'ededull; //dark blue
|
||||
case 5: return 0x7d7d'7676'fcfcull; //light blue
|
||||
case 6: return 0xd4d4'5252'4d4dull; //dark red
|
||||
case 7: return 0x4242'ebeb'f5f5ull; //cyan
|
||||
case 8: return 0xfcfc'5555'5454ull; //medium red
|
||||
case 9: return 0xffff'7979'7878ull; //light red
|
||||
case 10: return 0xd4d4'c1c1'5454ull; //dark yellow
|
||||
case 11: return 0xe6e6'cece'8080ull; //light yellow
|
||||
case 12: return 0x2121'b0b0'3b3bull; //dark green
|
||||
case 13: return 0xc9c9'5b5b'babaull; //magenta
|
||||
case 14: return 0xcccc'cccc'ccccull; //gray
|
||||
case 15: return 0xffff'ffff'ffffull; //white
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return false;
|
||||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::hashes() -> vector<string> {
|
||||
return {};
|
||||
return {cartridge.hash()};
|
||||
}
|
||||
|
||||
auto Interface::manifests() -> vector<string> {
|
||||
return {};
|
||||
return {cartridge.manifest()};
|
||||
}
|
||||
|
||||
auto Interface::titles() -> vector<string> {
|
||||
return {};
|
||||
return {cartridge.title()};
|
||||
}
|
||||
|
||||
auto Interface::load() -> bool {
|
||||
return false;
|
||||
return system.load(this, System::Model::MSX);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
system.save();
|
||||
}
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
save();
|
||||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::ports() -> vector<Port> { return {
|
||||
|
@ -91,17 +109,20 @@ auto Interface::inputs(uint device) -> vector<Input> {
|
|||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
||||
auto Interface::run() -> void {
|
||||
system.run();
|
||||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
return {};
|
||||
system.runToSave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
auto Interface::unserialize(serializer& s) -> bool {
|
||||
return false;
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
auto information() -> Information override;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
|
|
|
@ -29,6 +29,13 @@ auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
|||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
|
||||
if(auto memory = document["system/memory(type=ROM,content=BIOS)"]) {
|
||||
bios.allocate(memory["size"].natural());
|
||||
if(auto fp = platform->open(ID::System, "bios.rom", File::Read, File::Required)) {
|
||||
bios.load(fp);
|
||||
} else return false;
|
||||
} else return false;
|
||||
|
||||
if(!cartridge.load()) return false;
|
||||
|
||||
if(cartridge.region() == "NTSC") {
|
||||
|
|
|
@ -24,6 +24,8 @@ struct System {
|
|||
auto serializeAll(serializer&) -> void;
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
Emulator::Memory::Readable<uint8> bios;
|
||||
|
||||
private:
|
||||
Emulator::Interface* interface = nullptr;
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
auto VDP::background(uint8 hoffset, uint8 voffset) -> void {
|
||||
if(!io.displayEnable) {
|
||||
output.color = io.colorBackground;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(io.videoMode) {
|
||||
case 0: return graphics1(hoffset, voffset);
|
||||
//case 1: return text1(hoffset, voffset);
|
||||
case 2: return graphics2(hoffset, voffset);
|
||||
case 3: return multicolor(hoffset, voffset);
|
||||
default: output.color = 8; return; //medium red color to identify unimplemented modes
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::text1(uint8 hoffset, uint8 voffset) -> void {
|
||||
}
|
||||
|
||||
auto VDP::graphics1(uint8 hoffset, uint8 voffset) -> void {
|
||||
uint14 nameAddress;
|
||||
nameAddress.bits( 0, 4) = hoffset.bits(3,7);
|
||||
nameAddress.bits( 5, 9) = voffset.bits(3,7);
|
||||
nameAddress.bits(10,13) = io.nameTableAddress;
|
||||
|
||||
uint8 pattern = vram.read(nameAddress);
|
||||
|
||||
uint14 patternAddress;
|
||||
patternAddress.bits( 0, 2) = voffset.bits(0,2);
|
||||
patternAddress.bits( 3,10) = pattern;
|
||||
patternAddress.bits(11,13) = io.patternTableAddress;
|
||||
|
||||
uint14 colorAddress; //d5 = 0
|
||||
colorAddress.bits(0, 4) = pattern.bits(3,7);
|
||||
colorAddress.bits(6,13) = io.colorTableAddress;
|
||||
|
||||
uint8 color = vram.read(colorAddress);
|
||||
uint3 index = hoffset ^ 7;
|
||||
if(!vram.read(patternAddress).bit(index)) {
|
||||
output.color = color.bits(0,3);
|
||||
} else {
|
||||
output.color = color.bits(4,7);
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::graphics2(uint8 hoffset, uint8 voffset) -> void {
|
||||
uint14 nameAddress;
|
||||
nameAddress.bits( 0, 4) = hoffset.bits(3,7);
|
||||
nameAddress.bits( 5, 9) = voffset.bits(3,7);
|
||||
nameAddress.bits(10,13) = io.nameTableAddress;
|
||||
|
||||
uint8 pattern = vram.read(nameAddress);
|
||||
|
||||
uint14 patternAddress;
|
||||
patternAddress.bits(0, 2) = voffset.bits(0,2);
|
||||
patternAddress.bits(3,10) = pattern;
|
||||
if(voffset >= 64 && voffset <= 127) patternAddress.bit(11) = io.patternTableAddress.bit(0);
|
||||
if(voffset >= 128 && voffset <= 191) patternAddress.bit(12) = io.patternTableAddress.bit(1);
|
||||
uint14 colorAddress = patternAddress;
|
||||
patternAddress.bit(13) = io.patternTableAddress.bit(2);
|
||||
colorAddress.bit(13) = io.colorTableAddress.bit(7);
|
||||
|
||||
uint8 colorMask = io.colorTableAddress.bits(0,6) << 1 | 1;
|
||||
uint8 color = vram.read(colorAddress);
|
||||
uint3 index = hoffset ^ 7;
|
||||
if(!vram.read(patternAddress).bit(index)) {
|
||||
output.color = color.bits(0,3);
|
||||
} else {
|
||||
output.color = color.bits(4,7);
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::multicolor(uint8 hoffset, uint8 voffset) -> void {
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
auto VDP::status() -> uint8 {
|
||||
io.controlLatch = 0;
|
||||
uint8 data = 0x00;
|
||||
data.bits(0,4) = io.spriteOverflowIndex;
|
||||
data.bit(5) = io.spriteCollision;
|
||||
data.bit(6) = io.spriteOverflow;
|
||||
data.bit(7) = io.irqLine;
|
||||
io.irqLine = 0;
|
||||
return data;
|
||||
}
|
||||
|
||||
auto VDP::data() -> uint8 {
|
||||
io.controlLatch = 0;
|
||||
uint8 data = io.vramLatch;
|
||||
uint14 address = io.controlValue.bits(0,13)++;
|
||||
io.vramLatch = vram.read(address);
|
||||
return data;
|
||||
}
|
||||
|
||||
auto VDP::data(uint8 data) -> void {
|
||||
io.controlLatch = 0;
|
||||
uint14 address = io.controlValue.bits(0,13)++;
|
||||
vram.write(address, data);
|
||||
}
|
||||
|
||||
auto VDP::control(uint8 data) -> void {
|
||||
if(io.controlLatch == 0) {
|
||||
io.controlLatch = 1;
|
||||
io.controlValue.byte(0) = data;
|
||||
return;
|
||||
} else {
|
||||
io.controlLatch = 0;
|
||||
io.controlValue.byte(1) = data;
|
||||
}
|
||||
|
||||
if(!io.controlValue.bit(15)) {
|
||||
if(!io.controlValue.bit(14)) {
|
||||
uint14 address = io.controlValue.bits(0,13)++;
|
||||
io.vramLatch = vram.read(address);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
data = io.controlValue.bits(0,7);
|
||||
switch(io.controlValue.bits(8,10)) {
|
||||
case 0:
|
||||
io.externalInput = data.bit(0);
|
||||
io.videoMode.bit(1) = data.bit(1);
|
||||
break;
|
||||
case 1:
|
||||
io.spriteZoom = data.bit(0);
|
||||
io.spriteSize = data.bit(1);
|
||||
io.videoMode.bit(2) = data.bit(3);
|
||||
io.videoMode.bit(0) = data.bit(4);
|
||||
io.irqEnable = data.bit(5);
|
||||
io.displayEnable = data.bit(6);
|
||||
io.ramMode = data.bit(7);
|
||||
break;
|
||||
case 2:
|
||||
io.nameTableAddress = data.bits(0,3);
|
||||
break;
|
||||
case 3:
|
||||
io.colorTableAddress = data.bits(0,7);
|
||||
break;
|
||||
case 4:
|
||||
io.patternTableAddress = data.bits(0,2);
|
||||
break;
|
||||
case 5:
|
||||
io.spriteAttributeTableAddress = data.bits(0,6);
|
||||
break;
|
||||
case 6:
|
||||
io.spritePatternTableAddress = data.bits(0,2);
|
||||
break;
|
||||
case 7:
|
||||
io.colorBackground = data.bits(0,3);
|
||||
io.colorForeground = data.bits(4,7);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
auto VDP::sprite(uint8 voffset) -> void {
|
||||
uint valid = 0;
|
||||
uint limit = io.spriteSize ? 15 : 7;
|
||||
for(uint index : range(4)) sprites[index].y = 0xd0;
|
||||
|
||||
uint14 attributeAddress;
|
||||
attributeAddress.bits(7,13) = io.spriteAttributeTableAddress;
|
||||
for(uint index : range(32)) {
|
||||
uint8 y = vram.read(attributeAddress++);
|
||||
if(y == 0xd0) break;
|
||||
|
||||
uint8 x = vram.read(attributeAddress++);
|
||||
uint8 pattern = vram.read(attributeAddress++);
|
||||
uint8 extra = vram.read(attributeAddress++);
|
||||
|
||||
if(extra.bit(7)) x -= 32;
|
||||
y += 1;
|
||||
if(voffset < y) continue;
|
||||
if(voffset > y + limit) continue;
|
||||
|
||||
if(limit == 15) pattern.bits(0,1) = 0;
|
||||
|
||||
if(valid == 4) {
|
||||
io.spriteOverflow = true;
|
||||
io.spriteOverflowIndex = index;
|
||||
break;
|
||||
}
|
||||
|
||||
sprites[valid++] = {x, y, pattern, extra.bits(0,3)};
|
||||
}
|
||||
}
|
||||
|
||||
auto VDP::sprite(uint8 hoffset, uint8 voffset) -> void {
|
||||
uint4 color;
|
||||
uint limit = io.spriteSize ? 15 : 7;
|
||||
|
||||
for(uint n : range(4)) {
|
||||
auto& o = sprites[n];
|
||||
if(o.y == 0xd0) continue;
|
||||
if(hoffset < o.x) continue;
|
||||
if(hoffset > o.x + limit) continue;
|
||||
|
||||
uint x = hoffset - o.x;
|
||||
uint y = voffset - o.y;
|
||||
|
||||
uint14 address;
|
||||
address.bits( 0,10) = (o.pattern << 3) + (x >> 3 << 4) + (y & limit);
|
||||
address.bits(11,13) = io.spritePatternTableAddress;
|
||||
|
||||
uint3 index = x ^ 7;
|
||||
if(vram.read(address).bit(index)) {
|
||||
if(color) { io.spriteCollision = true; break; }
|
||||
color = o.color;
|
||||
}
|
||||
}
|
||||
|
||||
if(color) output.color = color;
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
#include <msx/msx.hpp>
|
||||
|
||||
//228 clocks/scanline
|
||||
//456 clocks/scanline
|
||||
|
||||
namespace MSX {
|
||||
|
||||
VDP vdp;
|
||||
#include "io.cpp"
|
||||
#include "background.cpp"
|
||||
#include "sprites.cpp"
|
||||
#include "serialization.cpp"
|
||||
|
||||
auto VDP::Enter() -> void {
|
||||
|
@ -12,11 +15,30 @@ auto VDP::Enter() -> void {
|
|||
}
|
||||
|
||||
auto VDP::main() -> void {
|
||||
step(1);
|
||||
if(io.vcounter < 192) {
|
||||
uint8 y = io.vcounter;
|
||||
sprite(y);
|
||||
auto line = buffer + y * 256;
|
||||
for(uint8 x : range(256)) {
|
||||
background(x, y);
|
||||
sprite(x, y);
|
||||
line[x] = output.color;
|
||||
step(1);
|
||||
}
|
||||
step(200);
|
||||
} else {
|
||||
step(456);
|
||||
}
|
||||
|
||||
io.vcounter++;
|
||||
if(io.vcounter == 262) io.vcounter = 0;
|
||||
if(io.vcounter == 0) io.irqLine = 0;
|
||||
if(io.vcounter == 192) io.irqLine = 1, scheduler.exit(Scheduler::Event::Frame);
|
||||
}
|
||||
|
||||
auto VDP::step(uint clocks) -> void {
|
||||
Thread::step(clocks);
|
||||
synchronize(cpu);
|
||||
}
|
||||
|
||||
auto VDP::refresh() -> void {
|
||||
|
@ -24,7 +46,10 @@ auto VDP::refresh() -> void {
|
|||
}
|
||||
|
||||
auto VDP::power() -> void {
|
||||
create(VDP::Enter, system.colorburst());
|
||||
create(VDP::Enter, system.colorburst() * 2);
|
||||
vram.allocate(0x4000);
|
||||
|
||||
io = {};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,11 +9,70 @@ struct VDP : Thread {
|
|||
|
||||
auto power() -> void;
|
||||
|
||||
//io.cpp
|
||||
auto status() -> uint8;
|
||||
auto data() -> uint8;
|
||||
|
||||
auto data(uint8) -> void;
|
||||
auto control(uint8) -> void;
|
||||
|
||||
//background.cpp
|
||||
auto background(uint8 hoffset, uint8 voffset) -> void;
|
||||
auto text1(uint8 hoffset, uint8 voffset) -> void;
|
||||
auto graphics1(uint8 hoffset, uint8 voffset) -> void;
|
||||
auto graphics2(uint8 hoffset, uint8 voffset) -> void;
|
||||
auto multicolor(uint8 hoffset, uint8 voffset) -> void;
|
||||
|
||||
//sprites.cpp
|
||||
auto sprite(uint8 voffset) -> void;
|
||||
auto sprite(uint8 hoffset, uint8 voffset) -> void;
|
||||
|
||||
//serialization.cpp
|
||||
auto serialize(serializer&) -> void;
|
||||
|
||||
private:
|
||||
uint32 buffer[256 * 192];
|
||||
Emulator::Memory::Writable<uint8> vram;
|
||||
|
||||
struct IO {
|
||||
uint vcounter = 0;
|
||||
uint hcounter = 0;
|
||||
|
||||
uint1 controlLatch;
|
||||
uint16 controlValue;
|
||||
uint8 vramLatch;
|
||||
|
||||
uint5 spriteOverflowIndex;
|
||||
uint1 spriteCollision;
|
||||
uint1 spriteOverflow;
|
||||
uint1 irqLine;
|
||||
|
||||
uint1 externalInput;
|
||||
uint3 videoMode;
|
||||
uint1 spriteZoom;
|
||||
uint1 spriteSize;
|
||||
uint1 irqEnable;
|
||||
uint1 displayEnable;
|
||||
uint1 ramMode = 1; //0 = 4KB; 1 = 16KB
|
||||
uint4 nameTableAddress;
|
||||
uint8 colorTableAddress;
|
||||
uint3 patternTableAddress;
|
||||
uint7 spriteAttributeTableAddress;
|
||||
uint3 spritePatternTableAddress;
|
||||
uint4 colorBackground;
|
||||
uint4 colorForeground;
|
||||
} io;
|
||||
|
||||
struct Sprite {
|
||||
uint8 x;
|
||||
uint8 y;
|
||||
uint8 pattern;
|
||||
uint4 color;
|
||||
} sprites[4];
|
||||
|
||||
struct Output {
|
||||
uint4 color;
|
||||
} output;
|
||||
};
|
||||
|
||||
extern VDP vdp;
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace NeoGeoPocket {
|
|||
#include "neo-geo-pocket-color.cpp"
|
||||
|
||||
//todo: add correct values
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::LCD;
|
||||
display.colors = 1;
|
||||
|
@ -16,7 +16,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
display.internalHeight = 240;
|
||||
display.aspectCorrection = 1.0;
|
||||
display.refreshRate = 60.0;
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -19,7 +19,7 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
|
|
|
@ -7,7 +7,7 @@ Settings settings;
|
|||
#include "pc-engine.cpp"
|
||||
#include "supergrafx.cpp"
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 9;
|
||||
|
@ -17,7 +17,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
display.internalHeight = 240;
|
||||
display.aspectCorrection = 8.0 / 7.0;
|
||||
display.refreshRate = (system.colorburst() * 6.0) / (262.0 * 1365.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -20,7 +20,7 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
|
|
|
@ -14,7 +14,7 @@ auto Interface::information() -> Information {
|
|||
return information;
|
||||
}
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::CRT;
|
||||
display.colors = 1 << 19;
|
||||
|
@ -25,7 +25,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
display.aspectCorrection = 8.0 / 7.0;
|
||||
if(Region::NTSC()) display.refreshRate = system.cpuFrequency() / (262.0 * 1364.0);
|
||||
if(Region::PAL()) display.refreshRate = system.cpuFrequency() / (312.0 * 1364.0);
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
|
|
|
@ -35,7 +35,7 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
auto information() -> Information;
|
||||
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
|
|
Binary file not shown.
|
@ -1 +1,5 @@
|
|||
system name:MSX
|
||||
memory
|
||||
type: ROM
|
||||
size: 0x8000
|
||||
content: BIOS
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
auto AboutWindow::create() -> void {
|
||||
setTitle({tr("About {0}", "bsnes"), " ..."});
|
||||
setBackgroundColor({255, 255, 240});
|
||||
layout.setPadding(10);
|
||||
auto logo = image{Resource::Logo};
|
||||
logo.alphaBlend(0xfffff0);
|
||||
canvas.setIcon(logo);
|
||||
tableLayout.setFont(Font().setBold());
|
||||
tableLayout.setSize({2, 4});
|
||||
tableLayout.column(0).setSpacing(4);
|
||||
tableLayout.row(0).setSpacing(2);
|
||||
tableLayout.row(1).setSpacing(2);
|
||||
tableLayout.row(2).setSpacing(2);
|
||||
versionLabel.setText({tr("Version"), ":"}).setAlignment(1.0);
|
||||
versionValue.setText(Emulator::Version);
|
||||
authorLabel.setText({tr("Author"), ":"}).setAlignment(1.0);
|
||||
authorValue.setText(Emulator::Author).setToolTip("ビュウ");
|
||||
licenseLabel.setText({tr("License"), ":"}).setAlignment(1.0);
|
||||
licenseValue.setText(Emulator::License);
|
||||
websiteLabel.setText({tr("Website"), ":"}).setAlignment(1.0);
|
||||
websiteValue.setText(Emulator::Website);
|
||||
|
||||
setResizable(false);
|
||||
setSize(layout.minimumSize());
|
||||
setDismissable();
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
#include "../bsnes.hpp"
|
||||
#include "about.cpp"
|
||||
AboutWindow aboutWindow;
|
||||
Presentation presentation;
|
||||
|
||||
auto Presentation::create() -> void {
|
||||
|
@ -137,7 +135,14 @@ auto Presentation::create() -> void {
|
|||
invoke("https://doc.byuu.org/bsnes/");
|
||||
});
|
||||
about.setIcon(Icon::Prompt::Question).setText({tr("About"), " ..."}).onActivate([&] {
|
||||
aboutWindow.setCentered(*this).setVisible().setFocused();
|
||||
AboutDialog()
|
||||
.setLogo(Resource::Logo)
|
||||
.setVersion(Emulator::Version)
|
||||
.setAuthor("byuu")
|
||||
.setLicense("GPLv3")
|
||||
.setWebsite("https://byuu.org/")
|
||||
.setParent(*this)
|
||||
.show();
|
||||
});
|
||||
|
||||
viewport.setDroppable().onDrop([&](vector<string> locations) {
|
||||
|
|
|
@ -1,23 +1,3 @@
|
|||
struct AboutWindow : Window {
|
||||
Application::Namespace tr{"AboutWindow"};
|
||||
auto create() -> void;
|
||||
|
||||
VerticalLayout layout{this};
|
||||
Canvas canvas{&layout, Size{400, 85}, 0};
|
||||
TableLayout tableLayout{&layout, Size{~0, 0}};
|
||||
Label versionLabel{&tableLayout, Size{~0, 0}};
|
||||
Label versionValue{&tableLayout, Size{~0, 0}};
|
||||
//
|
||||
Label authorLabel{&tableLayout, Size{~0, 0}};
|
||||
Label authorValue{&tableLayout, Size{~0, 0}};
|
||||
//
|
||||
Label licenseLabel{&tableLayout, Size{~0, 0}};
|
||||
Label licenseValue{&tableLayout, Size{~0, 0}};
|
||||
//
|
||||
Label websiteLabel{&tableLayout, Size{~0, 0}};
|
||||
Label websiteValue{&tableLayout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct Presentation : Window {
|
||||
Application::Namespace tr{"Presentation"};
|
||||
auto create() -> void;
|
||||
|
@ -117,5 +97,4 @@ struct Presentation : Window {
|
|||
Label spacerRight{&statusLayout, Size{8, ~0}, 0};
|
||||
};
|
||||
|
||||
extern AboutWindow aboutWindow;
|
||||
extern Presentation presentation;
|
||||
|
|
|
@ -207,7 +207,7 @@ auto Program::load(uint id, string name, string type, vector<string> options) ->
|
|||
return {};
|
||||
}
|
||||
|
||||
auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void {
|
||||
auto Program::videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void {
|
||||
uint32_t* output;
|
||||
uint length;
|
||||
|
||||
|
@ -255,7 +255,7 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi
|
|||
}
|
||||
}
|
||||
|
||||
auto Program::audioSample(const double* samples, uint channels) -> void {
|
||||
auto Program::audioFrame(const double* samples, uint channels) -> void {
|
||||
audio.output(samples);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ auto Program::create() -> void {
|
|||
|
||||
presentation.create();
|
||||
presentation.setVisible();
|
||||
aboutWindow.create();
|
||||
|
||||
settingsWindow.create();
|
||||
videoSettings.create();
|
||||
|
|
|
@ -9,8 +9,8 @@ struct Program : Lock, Emulator::Platform {
|
|||
//platform.cpp
|
||||
auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override;
|
||||
auto load(uint id, string name, string type, vector<string> options = {}) -> Emulator::Platform::Load override;
|
||||
auto videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void override;
|
||||
auto audioSample(const double* samples, uint channels) -> void override;
|
||||
auto videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void override;
|
||||
auto audioFrame(const double* samples, uint channels) -> void override;
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 override;
|
||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override;
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
AboutWindow::AboutWindow() {
|
||||
aboutWindow = this;
|
||||
|
||||
setTitle("About higan ...");
|
||||
setBackgroundColor({255, 255, 240});
|
||||
layout.setPadding(10);
|
||||
auto logo = image{Resource::Logo};
|
||||
logo.alphaBlend(0xfffff0);
|
||||
canvas.setIcon(logo);
|
||||
informationLeft.setFont(Font().setBold()).setAlignment(1.0).setText({
|
||||
"Version:\n",
|
||||
"Author:\n",
|
||||
"License:\n",
|
||||
"Website:"
|
||||
});
|
||||
informationRight.setFont(Font().setBold()).setAlignment(0.0).setText({
|
||||
Emulator::Version, "\n",
|
||||
Emulator::Author, "\n",
|
||||
Emulator::License, "\n",
|
||||
Emulator::Website
|
||||
});
|
||||
|
||||
setResizable(false);
|
||||
setSize(layout.minimumSize());
|
||||
setCentered();
|
||||
setDismissable();
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
#include "../higan.hpp"
|
||||
#include "about.cpp"
|
||||
unique_pointer<AboutWindow> aboutWindow;
|
||||
unique_pointer<Presentation> presentation;
|
||||
|
||||
Presentation::Presentation() {
|
||||
|
@ -131,7 +129,14 @@ Presentation::Presentation() {
|
|||
invoke("https://doc.byuu.org/higan/credits/");
|
||||
});
|
||||
about.setIcon(Icon::Prompt::Question).setText("About ...").onActivate([&] {
|
||||
aboutWindow->setCentered(*this).setVisible().setFocused();
|
||||
AboutDialog()
|
||||
.setLogo(Resource::Logo)
|
||||
.setVersion(Emulator::Version)
|
||||
.setAuthor("byuu")
|
||||
.setLicense("GPLv3")
|
||||
.setWebsite("https://byuu.org/")
|
||||
.setParent(*this)
|
||||
.show();
|
||||
});
|
||||
|
||||
viewport.setDroppable().onDrop([&](vector<string> locations) {
|
||||
|
@ -345,7 +350,7 @@ auto Presentation::resizeViewport() -> void {
|
|||
uint height = 240;
|
||||
|
||||
if(emulator) {
|
||||
auto display = emulator->displays().first();
|
||||
auto display = emulator->display();
|
||||
width = display.width;
|
||||
height = display.height;
|
||||
if(settings["View/AspectCorrection"].boolean()) width *= display.aspectCorrection;
|
||||
|
@ -412,7 +417,7 @@ auto Presentation::resizeWindow() -> void {
|
|||
uint statusHeight = settings["View/StatusBar"].boolean() ? StatusHeight : 0;
|
||||
|
||||
if(emulator) {
|
||||
auto display = emulator->displays().first();
|
||||
auto display = emulator->display();
|
||||
width = display.width;
|
||||
height = display.height;
|
||||
if(settings["View/AspectCorrection"].boolean()) width *= display.aspectCorrection;
|
||||
|
|
|
@ -1,13 +1,3 @@
|
|||
struct AboutWindow : Window {
|
||||
AboutWindow();
|
||||
|
||||
VerticalLayout layout{this};
|
||||
Canvas canvas{&layout, Size{399, 95}, 15};
|
||||
HorizontalLayout informationLayout{&layout, Size{~0, 0}};
|
||||
Label informationLeft{&informationLayout, Size{~0, 0}, 3};
|
||||
Label informationRight{&informationLayout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
struct Presentation : Window {
|
||||
enum : uint { StatusHeight = 24 };
|
||||
|
||||
|
@ -104,5 +94,4 @@ struct Presentation : Window {
|
|||
Label spacerRight{&statusLayout, Size{8, ~0}, 0};
|
||||
};
|
||||
|
||||
extern unique_pointer<AboutWindow> aboutWindow;
|
||||
extern unique_pointer<Presentation> presentation;
|
||||
|
|
|
@ -50,14 +50,14 @@ auto Program::load(uint id, string name, string type, vector<string> options) ->
|
|||
return {pathID, option};
|
||||
}
|
||||
|
||||
auto Program::videoRefresh(uint displayID, const uint32* data, uint pitch, uint width, uint height) -> void {
|
||||
auto Program::videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void {
|
||||
uint32_t* output;
|
||||
uint length;
|
||||
|
||||
pitch >>= 2;
|
||||
|
||||
if(!settings["View/Overscan"].boolean()) {
|
||||
auto display = emulator->displays()[displayID];
|
||||
auto display = emulator->display();
|
||||
if(display.type == Emulator::Interface::Display::Type::CRT) {
|
||||
uint overscanHorizontal = settings["View/Overscan/Horizontal"].natural();
|
||||
uint overscanVertical = settings["View/Overscan/Vertical"].natural();
|
||||
|
@ -92,7 +92,7 @@ auto Program::videoRefresh(uint displayID, const uint32* data, uint pitch, uint
|
|||
}
|
||||
}
|
||||
|
||||
auto Program::audioSample(const double* samples, uint channels) -> void {
|
||||
auto Program::audioFrame(const double* samples, uint channels) -> void {
|
||||
if(channels == 1) {
|
||||
double stereo[] = {samples[0], samples[0]};
|
||||
audio->output(stereo);
|
||||
|
|
|
@ -103,7 +103,6 @@ Program::Program(Arguments arguments) {
|
|||
new SettingsManager;
|
||||
new CheatDatabase;
|
||||
new ToolsManager;
|
||||
new AboutWindow;
|
||||
|
||||
updateVideoShader();
|
||||
updateAudioDriver();
|
||||
|
|
|
@ -8,8 +8,8 @@ struct Program : Emulator::Platform {
|
|||
auto path(uint id) -> string override;
|
||||
auto open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file override;
|
||||
auto load(uint id, string name, string type, vector<string> options = {}) -> Emulator::Platform::Load override;
|
||||
auto videoRefresh(uint display, const uint32* data, uint pitch, uint width, uint height) -> void override;
|
||||
auto audioSample(const double* samples, uint channels) -> void override;
|
||||
auto videoFrame(const uint32* data, uint pitch, uint width, uint height) -> void override;
|
||||
auto audioFrame(const double* samples, uint channels) -> void override;
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 override;
|
||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override;
|
||||
auto dipSettings(Markup::Node node) -> uint override;
|
||||
|
|
|
@ -7,7 +7,7 @@ Settings settings;
|
|||
#include "wonderswan-color.cpp"
|
||||
#include "pocket-challenge-v2.cpp"
|
||||
|
||||
auto Interface::displays() -> vector<Display> {
|
||||
auto Interface::display() -> Display {
|
||||
Display display;
|
||||
display.type = Display::Type::LCD;
|
||||
display.colors = 1 << 12;
|
||||
|
@ -21,7 +21,7 @@ auto Interface::displays() -> vector<Display> {
|
|||
swap(display.width, display.height);
|
||||
swap(display.internalWidth, display.internalHeight);
|
||||
}
|
||||
return {display};
|
||||
return display;
|
||||
}
|
||||
|
||||
//todo: the WonderSwan and PocketChallengeV2 interfaces should be generating grayscale shades
|
||||
|
|
|
@ -20,7 +20,7 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
auto displays() -> vector<Display> override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
|
|
|
@ -49,7 +49,9 @@ auto MessageDialog::_run() -> string {
|
|||
Window window;
|
||||
VerticalLayout layout{&window};
|
||||
HorizontalLayout messageLayout{&layout, Size{~0, 0}, 5};
|
||||
Canvas messageIcon{&messageLayout, Size{16, 16}, 5};
|
||||
VerticalLayout messageIconLayout{&messageLayout, Size{16, ~0}, 5};
|
||||
Canvas messageIcon{&messageIconLayout, Size{16, 16}, 0};
|
||||
Widget messageIconSpacer{&messageIconLayout, Size{16, ~0}};
|
||||
Label messageText{&messageLayout, Size{~0, 0}};
|
||||
HorizontalLayout controlLayout{&layout, Size{~0, 0}};
|
||||
Widget controlSpacer{&controlLayout, Size{~0, 0}};
|
||||
|
|
|
@ -131,22 +131,22 @@ auto nall::main(Arguments arguments) -> void {
|
|||
new ImportDialog;
|
||||
new ErrorDialog;
|
||||
|
||||
if constexpr(platform() == Platform::MacOS) {
|
||||
Application::Cocoa::onAbout([&] {
|
||||
MessageDialog().setTitle("About icarus").setText({
|
||||
"icarus\n\n"
|
||||
"Author: byuu\n"
|
||||
"License: GPLv3\n"
|
||||
"Website: https://byuu.org/\n"
|
||||
}).information();
|
||||
});
|
||||
Application::Cocoa::onPreferences([&] {
|
||||
scanDialog->settingsButton.doActivate();
|
||||
});
|
||||
Application::Cocoa::onQuit([&] {
|
||||
Application::quit();
|
||||
});
|
||||
}
|
||||
#if defined(PLATFORM_MACOS)
|
||||
Application::Cocoa::onAbout([&] {
|
||||
MessageDialog().setTitle("About icarus").setText({
|
||||
"icarus\n\n"
|
||||
"Author: byuu\n"
|
||||
"License: GPLv3\n"
|
||||
"Website: https://byuu.org/\n"
|
||||
}).information();
|
||||
});
|
||||
Application::Cocoa::onPreferences([&] {
|
||||
scanDialog->settingsButton.doActivate();
|
||||
});
|
||||
Application::Cocoa::onQuit([&] {
|
||||
Application::quit();
|
||||
});
|
||||
#endif
|
||||
|
||||
scanDialog->show();
|
||||
Application::run();
|
||||
|
|
Loading…
Reference in New Issue