mirror of https://github.com/bsnes-emu/bsnes.git
213 lines
5.3 KiB
C++
213 lines
5.3 KiB
C++
#include <fc/fc.hpp>
|
|
|
|
namespace Famicom {
|
|
|
|
Settings settings;
|
|
|
|
auto Interface::information() -> Information {
|
|
Information information;
|
|
information.manufacturer = "Nintendo";
|
|
information.name = "Famicom";
|
|
information.extension = "fc";
|
|
information.resettable = true;
|
|
return information;
|
|
}
|
|
|
|
auto Interface::displays() -> vector<Display> {
|
|
Display display;
|
|
display.type = Display::Type::CRT;
|
|
display.colors = 1 << 9;
|
|
display.width = 256;
|
|
display.height = 240;
|
|
display.internalWidth = 256;
|
|
display.internalHeight = 240;
|
|
display.aspectCorrection = 8.0 / 7.0;
|
|
display.refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
|
|
return {display};
|
|
}
|
|
|
|
auto Interface::color(uint32 n) -> uint64 {
|
|
double saturation = 2.0;
|
|
double hue = 0.0;
|
|
double contrast = 1.0;
|
|
double brightness = 1.0;
|
|
double gamma = settings.colorEmulation ? 1.8 : 2.2;
|
|
|
|
int color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1;
|
|
|
|
static const double black = 0.518, white = 1.962, attenuation = 0.746;
|
|
static const double levels[8] = {
|
|
0.350, 0.518, 0.962, 1.550,
|
|
1.094, 1.506, 1.962, 1.962,
|
|
};
|
|
|
|
double lo_and_hi[2] = {
|
|
levels[level + 4 * (color == 0x0)],
|
|
levels[level + 4 * (color < 0xd)],
|
|
};
|
|
|
|
double y = 0.0, i = 0.0, q = 0.0;
|
|
auto wave = [](int p, int color) { return (color + p + 8) % 12 < 6; };
|
|
for(int p : range(12)) {
|
|
double spot = lo_and_hi[wave(p, color)];
|
|
|
|
if(((n & 0x040) && wave(p, 12))
|
|
|| ((n & 0x080) && wave(p, 4))
|
|
|| ((n & 0x100) && wave(p, 8))
|
|
) spot *= attenuation;
|
|
|
|
double v = (spot - black) / (white - black);
|
|
|
|
v = (v - 0.5) * contrast + 0.5;
|
|
v *= brightness / 12.0;
|
|
|
|
y += v;
|
|
i += v * cos((Math::Pi / 6.0) * (p + hue));
|
|
q += v * sin((Math::Pi / 6.0) * (p + hue));
|
|
}
|
|
|
|
i *= saturation;
|
|
q *= saturation;
|
|
|
|
auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : pow(f, 2.2 / gamma); };
|
|
uint64 r = uclamp<16>(65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q));
|
|
uint64 g = uclamp<16>(65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q));
|
|
uint64 b = uclamp<16>(65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q));
|
|
|
|
return r << 32 | g << 16 | b << 0;
|
|
}
|
|
|
|
auto Interface::loaded() -> bool {
|
|
return system.loaded();
|
|
}
|
|
|
|
auto Interface::hashes() -> vector<string> {
|
|
return {cartridge.hash()};
|
|
}
|
|
|
|
auto Interface::manifests() -> vector<string> {
|
|
return {cartridge.manifest()};
|
|
}
|
|
|
|
auto Interface::titles() -> vector<string> {
|
|
return {cartridge.title()};
|
|
}
|
|
|
|
auto Interface::load() -> bool {
|
|
return system.load(this);
|
|
}
|
|
|
|
auto Interface::save() -> void {
|
|
system.save();
|
|
}
|
|
|
|
auto Interface::unload() -> void {
|
|
save();
|
|
system.unload();
|
|
}
|
|
|
|
auto Interface::ports() -> vector<Port> { return {
|
|
{ID::Port::Controller1, "Controller Port 1"},
|
|
{ID::Port::Controller2, "Controller Port 2"},
|
|
{ID::Port::Expansion, "Expansion Port" }};
|
|
}
|
|
|
|
auto Interface::devices(uint port) -> vector<Device> {
|
|
if(port == ID::Port::Controller1) return {
|
|
{ID::Device::None, "None" },
|
|
{ID::Device::Gamepad, "Gamepad"}
|
|
};
|
|
|
|
if(port == ID::Port::Controller2) return {
|
|
{ID::Device::None, "None" },
|
|
{ID::Device::Gamepad, "Gamepad"}
|
|
};
|
|
|
|
if(port == ID::Port::Expansion) return {
|
|
{ID::Device::None, "None"}
|
|
};
|
|
|
|
return {};
|
|
}
|
|
|
|
auto Interface::inputs(uint device) -> vector<Input> {
|
|
using Type = Input::Type;
|
|
|
|
if(device == ID::Device::None) return {
|
|
};
|
|
|
|
if(device == ID::Device::Gamepad) return {
|
|
{Type::Hat, "Up" },
|
|
{Type::Hat, "Down" },
|
|
{Type::Hat, "Left" },
|
|
{Type::Hat, "Right" },
|
|
{Type::Button, "B" },
|
|
{Type::Button, "A" },
|
|
{Type::Control, "Select"},
|
|
{Type::Control, "Start" }
|
|
};
|
|
|
|
return {};
|
|
}
|
|
|
|
auto Interface::connected(uint port) -> uint {
|
|
if(port == ID::Port::Controller1) return settings.controllerPort1;
|
|
if(port == ID::Port::Controller2) return settings.controllerPort2;
|
|
if(port == ID::Port::Expansion) return settings.expansionPort;
|
|
return 0;
|
|
}
|
|
|
|
auto Interface::connect(uint port, uint device) -> void {
|
|
if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
|
|
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);
|
|
}
|
|
|
|
auto Interface::power() -> void {
|
|
system.power(/* reset = */ false);
|
|
}
|
|
|
|
auto Interface::reset() -> void {
|
|
system.power(/* reset = */ true);
|
|
}
|
|
|
|
auto Interface::run() -> void {
|
|
system.run();
|
|
}
|
|
|
|
auto Interface::serialize() -> serializer {
|
|
system.runToSave();
|
|
return system.serialize();
|
|
}
|
|
|
|
auto Interface::unserialize(serializer& s) -> bool {
|
|
return system.unserialize(s);
|
|
}
|
|
|
|
auto Interface::cheats(const vector<string>& list) -> void {
|
|
cheat.assign(list);
|
|
}
|
|
|
|
auto Interface::cap(const string& name) -> bool {
|
|
if(name == "Color Emulation") return true;
|
|
if(name == "Scanline Emulation") return true;
|
|
return false;
|
|
}
|
|
|
|
auto Interface::get(const string& name) -> any {
|
|
if(name == "Color Emulation") return settings.colorEmulation;
|
|
if(name == "Scanline Emulation") return settings.scanlineEmulation;
|
|
return {};
|
|
}
|
|
|
|
auto Interface::set(const string& name, const any& value) -> bool {
|
|
if(name == "Color Emulation" && value.is<bool>()) {
|
|
settings.colorEmulation = value.get<bool>();
|
|
Emulator::video.setPalette();
|
|
return true;
|
|
}
|
|
if(name == "Scanline Emulation" && value.is<bool>()) return settings.scanlineEmulation = value.get<bool>(), true;
|
|
return false;
|
|
}
|
|
|
|
}
|