#include namespace GameBoyAdvance { Interface* interface = nullptr; Settings settings; Interface::Interface() { interface = this; information.manufacturer = "Nintendo"; information.name = "Game Boy Advance"; information.overscan = false; information.resettable = false; information.capability.states = true; information.capability.cheats = false; media.append({ID::GameBoyAdvance, "Game Boy Advance", "gba"}); Port hardwarePort{ID::Port::Hardware, "Hardware"}; { Device device{ID::Device::Controls, "Controls"}; device.inputs.append({0, "Up" }); device.inputs.append({0, "Down" }); device.inputs.append({0, "Left" }); device.inputs.append({0, "Right" }); device.inputs.append({0, "B" }); device.inputs.append({0, "A" }); device.inputs.append({0, "L" }); device.inputs.append({0, "R" }); device.inputs.append({0, "Select"}); device.inputs.append({0, "Start" }); device.inputs.append({2, "Rumble"}); hardwarePort.devices.append(device); } ports.append(move(hardwarePort)); } auto Interface::manifest() -> string { return cartridge.manifest(); } auto Interface::title() -> string { return cartridge.title(); } auto Interface::videoSize() -> VideoSize { return {240, 160}; } auto Interface::videoSize(uint width, uint height, bool arc) -> VideoSize { uint w = 240; uint h = 160; uint m = min(width / w, height / h); return {w * m, h * m}; } auto Interface::videoFrequency() -> double { return 16777216.0 / (228.0 * 1232.0); } auto Interface::videoColors() -> uint32 { return 1 << 15; } auto Interface::videoColor(uint32 color) -> uint64 { uint R = color.bits( 0, 4); uint G = color.bits( 5, 9); uint B = color.bits(10,14); uint64 r = image::normalize(R, 5, 16); uint64 g = image::normalize(G, 5, 16); uint64 b = image::normalize(B, 5, 16); if(settings.colorEmulation) { double lcdGamma = 4.0, outGamma = 2.2; double lb = pow(B / 31.0, lcdGamma); double lg = pow(G / 31.0, lcdGamma); double lr = pow(R / 31.0, lcdGamma); r = pow(( 0 * lb + 50 * lg + 255 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); g = pow(( 30 * lb + 230 * lg + 10 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); b = pow((220 * lb + 10 * lg + 50 * lr) / 255, 1 / outGamma) * (0xffff * 255 / 280); } return r << 32 | g << 16 | b << 0; } auto Interface::audioFrequency() -> double { return 16777216.0 / 512.0; } auto Interface::loaded() -> bool { return system.loaded(); } auto Interface::load(uint id) -> bool { return system.load(); } auto Interface::save() -> void { system.save(); } auto Interface::unload() -> void { save(); system.unload(); } auto Interface::power() -> void { system.power(); } auto Interface::reset() -> void { system.power(); } 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::cap(const string& name) -> bool { if(name == "Blur Emulation") return true; if(name == "Color Emulation") return true; return false; } auto Interface::get(const string& name) -> any { if(name == "Blur Emulation") return settings.blurEmulation; if(name == "Color Emulation") return settings.colorEmulation; return {}; } auto Interface::set(const string& name, const any& value) -> bool { if(name == "Blur Emulation" && value.is()) { settings.blurEmulation = value.get(); system.configureVideoEffects(); return true; } if(name == "Color Emulation" && value.is()) { settings.colorEmulation = value.get(); system.configureVideoPalette(); return true; } return false; } }