mirror of https://github.com/bsnes-emu/bsnes.git
Update to 20180724 release.
byuu says: I failed to complete a WIP, have five of eight cores updated with some major changes to Emulator::Interface. I'll just post a quick temporary WIP in the off chance someone wants to look over the new interface and comment on it. Also implemented screen saver suppression into hiro/GTK. I should also add ... a plan of mine is to develop target-bsnes into a more generic user interface, with the general idea being that target-higan is for multiple Emulator::Interface cores at the same time, and target-bsnes is for just one Emulator::Interface core. The idea being that if one were to compile target-bsnes with the GBA core, it'd become bgba, for instance. I don't plan on releasing single-core emulators like this, but ... I don't see any downsides to being more flexible.
This commit is contained in:
parent
0aedb3430c
commit
f1a4576ac4
|
@ -1,4 +1,4 @@
|
|||
target := bsnes
|
||||
target := higan
|
||||
binary := application
|
||||
build := performance
|
||||
openmp := true
|
||||
|
|
|
@ -13,7 +13,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "106.51";
|
||||
static const string Version = "106.52";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org/";
|
||||
|
|
|
@ -3,42 +3,24 @@
|
|||
namespace Emulator {
|
||||
|
||||
struct Interface {
|
||||
//information
|
||||
struct Information {
|
||||
string manufacturer;
|
||||
string name;
|
||||
bool overscan = false;
|
||||
string extension;
|
||||
bool resettable = false;
|
||||
} information;
|
||||
|
||||
struct Medium {
|
||||
uint id;
|
||||
string name;
|
||||
string type; //extension
|
||||
};
|
||||
vector<Medium> media;
|
||||
|
||||
struct Device {
|
||||
uint id;
|
||||
string name;
|
||||
struct Input {
|
||||
uint type; //0 = digital, 1 = analog (relative), 2 = rumble
|
||||
string name;
|
||||
};
|
||||
vector<Input> inputs;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
uint id;
|
||||
string name;
|
||||
vector<Device> devices;
|
||||
};
|
||||
vector<Port> ports;
|
||||
|
||||
//information
|
||||
virtual auto information() -> Information = 0;
|
||||
virtual auto manifest() -> string = 0;
|
||||
virtual auto title() -> string = 0;
|
||||
|
||||
struct VideoInformation {
|
||||
struct Display {
|
||||
struct Type { enum : uint {
|
||||
CRT,
|
||||
LCD,
|
||||
};};
|
||||
uint type = 0;
|
||||
uint colors = 0;
|
||||
uint width = 0;
|
||||
uint height = 0;
|
||||
uint internalWidth = 0;
|
||||
|
@ -46,23 +28,48 @@ struct Interface {
|
|||
double aspectCorrection = 0;
|
||||
double refreshRate = 0;
|
||||
};
|
||||
virtual auto videoInformation() -> VideoInformation = 0;
|
||||
virtual auto videoColors() -> uint32 = 0;
|
||||
virtual auto videoColor(uint32 color) -> uint64 = 0;
|
||||
virtual auto display() -> Display = 0;
|
||||
virtual auto color(uint32 color) -> uint64 = 0;
|
||||
|
||||
//media interface
|
||||
virtual auto loaded() -> bool { return false; }
|
||||
//game interface
|
||||
virtual auto loaded() -> bool = 0;
|
||||
virtual auto sha256() -> string { return ""; }
|
||||
virtual auto load(uint id) -> bool { return false; }
|
||||
virtual auto save() -> void {}
|
||||
virtual auto unload() -> void {}
|
||||
virtual auto load() -> bool = 0;
|
||||
virtual auto save() -> void = 0;
|
||||
virtual auto unload() -> void = 0;
|
||||
|
||||
//system interface
|
||||
struct Port {
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
virtual auto ports() -> vector<Port> = 0;
|
||||
|
||||
struct Device {
|
||||
uint id;
|
||||
string name;
|
||||
};
|
||||
virtual auto devices(uint port) -> vector<Device> = 0;
|
||||
|
||||
struct Input {
|
||||
struct Type { enum : uint {
|
||||
Hat,
|
||||
Button,
|
||||
Trigger,
|
||||
Control,
|
||||
Axis,
|
||||
Rumble,
|
||||
};};
|
||||
uint type;
|
||||
string name;
|
||||
};
|
||||
virtual auto inputs(uint device) -> vector<Input> = 0;
|
||||
|
||||
virtual auto connected(uint port) -> uint { return 0; }
|
||||
virtual auto connect(uint port, uint device) -> void {}
|
||||
virtual auto power() -> void {}
|
||||
virtual auto power() -> void = 0;
|
||||
virtual auto reset() -> void {}
|
||||
virtual auto run() -> void {}
|
||||
virtual auto run() -> void = 0;
|
||||
|
||||
//time functions
|
||||
virtual auto rtc() -> bool { return false; }
|
||||
|
|
|
@ -2,40 +2,16 @@
|
|||
|
||||
namespace Famicom {
|
||||
|
||||
#define returns(T) T { return ([&] { struct With : T { With() {
|
||||
#define $ }}; return With(); })(); }
|
||||
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Famicom";
|
||||
information.overscan = true;
|
||||
information.resettable = true;
|
||||
|
||||
media.append({ID::Famicom, "Famicom", "fc"});
|
||||
|
||||
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
|
||||
Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
|
||||
|
||||
{ Device device{ID::Device::None, "None"};
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::Gamepad, "Gamepad"};
|
||||
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, "Select"});
|
||||
device.inputs.append({0, "Start" });
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
ports.append(move(controllerPort1));
|
||||
ports.append(move(controllerPort2));
|
||||
}
|
||||
auto Interface::information() -> returns(Information) {
|
||||
manufacturer = "Nintendo";
|
||||
name = "Famicom";
|
||||
resettable = true;
|
||||
}$
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
return cartridge.manifest();
|
||||
|
@ -45,22 +21,18 @@ auto Interface::title() -> string {
|
|||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 256;
|
||||
vi.height = 240;
|
||||
vi.internalWidth = 256;
|
||||
vi.internalHeight = 240;
|
||||
vi.aspectCorrection = 8.0 / 7.0;
|
||||
vi.refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
|
||||
return vi;
|
||||
}
|
||||
auto Interface::display() -> returns(Display) {
|
||||
type = Display::Type::CRT;
|
||||
colors = 1 << 9;
|
||||
width = 256;
|
||||
height = 240;
|
||||
internalWidth = 256;
|
||||
internalHeight = 240;
|
||||
aspectCorrection = 8.0 / 7.0;
|
||||
refreshRate = system.frequency() / (ppu.vlines() * ppu.rate() * 341.0);
|
||||
}$
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 1 << 9;
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 n) -> uint64 {
|
||||
auto Interface::color(uint32 n) -> uint64 {
|
||||
double saturation = 2.0;
|
||||
double hue = 0.0;
|
||||
double contrast = 1.0;
|
||||
|
@ -119,7 +91,7 @@ auto Interface::sha256() -> string {
|
|||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
auto Interface::load() -> bool {
|
||||
return system.load(this);
|
||||
}
|
||||
|
||||
|
@ -132,6 +104,50 @@ auto Interface::unload() -> void {
|
|||
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;
|
||||
|
@ -191,4 +207,7 @@ auto Interface::set(const string& name, const any& value) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
#undef returns
|
||||
#undef $
|
||||
|
||||
}
|
||||
|
|
|
@ -21,21 +21,24 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
Interface();
|
||||
auto information() -> Information override;
|
||||
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto sha256() -> string override;
|
||||
auto load(uint id) -> bool override;
|
||||
auto load() -> bool override;
|
||||
auto save() -> void override;
|
||||
auto unload() -> void override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
auto devices(uint port) -> vector<Device> override;
|
||||
auto inputs(uint device) -> vector<Input> override;
|
||||
|
||||
auto connected(uint port) -> uint override;
|
||||
auto connect(uint port, uint device) -> void override;
|
||||
auto power() -> void override;
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
GameBoyColorInterface::GameBoyColorInterface() {
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Game Boy Color";
|
||||
information.overscan = false;
|
||||
auto GameBoyColorInterface::information() -> returns(Information) {
|
||||
manufacturer = "Nintendo";
|
||||
name = "Game Boy Color";
|
||||
extension = "gbc";
|
||||
}$
|
||||
|
||||
media.append({ID::GameBoyColor, "Game Boy Color", "gbc"});
|
||||
}
|
||||
|
||||
auto GameBoyColorInterface::videoColors() -> uint32 {
|
||||
return 1 << 15;
|
||||
}
|
||||
|
||||
auto GameBoyColorInterface::videoColor(uint32 color) -> uint64 {
|
||||
auto GameBoyColorInterface::color(uint32 color) -> uint64 {
|
||||
uint r = color.bits( 0, 4);
|
||||
uint g = color.bits( 5, 9);
|
||||
uint b = color.bits(10,14);
|
||||
|
@ -31,7 +25,6 @@ auto GameBoyColorInterface::videoColor(uint32 color) -> uint64 {
|
|||
return R << 32 | G << 16 | B << 0;
|
||||
}
|
||||
|
||||
auto GameBoyColorInterface::load(uint id) -> bool {
|
||||
if(id == ID::GameBoyColor) return system.load(this, System::Model::GameBoyColor);
|
||||
return false;
|
||||
auto GameBoyColorInterface::load() -> bool {
|
||||
return system.load(this, System::Model::GameBoyColor);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
GameBoyInterface::GameBoyInterface() {
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Game Boy";
|
||||
information.overscan = false;
|
||||
auto GameBoyInterface::information() -> returns(Information) {
|
||||
manufacturer = "Nintendo";
|
||||
name = "Game Boy";
|
||||
extension = "gb";
|
||||
}$
|
||||
|
||||
media.append({ID::GameBoy, "Game Boy", "gb"});
|
||||
}
|
||||
|
||||
auto GameBoyInterface::videoColors() -> uint32 {
|
||||
return 1 << 2;
|
||||
}
|
||||
|
||||
auto GameBoyInterface::videoColor(uint32 color) -> uint64 {
|
||||
auto GameBoyInterface::color(uint32 color) -> uint64 {
|
||||
if(!settings.colorEmulation) {
|
||||
uint64 L = image::normalize(3 - color, 2, 16);
|
||||
return L << 32 | L << 16 | L << 0;
|
||||
|
@ -46,7 +40,6 @@ auto GameBoyInterface::videoColor(uint32 color) -> uint64 {
|
|||
}
|
||||
}
|
||||
|
||||
auto GameBoyInterface::load(uint id) -> bool {
|
||||
if(id == ID::GameBoy) return system.load(this, System::Model::GameBoy);
|
||||
return false;
|
||||
auto GameBoyInterface::load() -> bool {
|
||||
return system.load(this, System::Model::GameBoy);
|
||||
}
|
||||
|
|
|
@ -2,32 +2,14 @@
|
|||
|
||||
namespace GameBoy {
|
||||
|
||||
#define returns(T) T { return ([&] { struct With : T { With() {
|
||||
#define $ }}; return With(); })(); }
|
||||
|
||||
SuperGameBoyInterface* superGameBoy = nullptr;
|
||||
Settings settings;
|
||||
#include "game-boy.cpp"
|
||||
#include "game-boy-color.cpp"
|
||||
|
||||
Interface::Interface() {
|
||||
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, "Select"});
|
||||
device.inputs.append({0, "Start" });
|
||||
device.inputs.append({1, "X-axis"});
|
||||
device.inputs.append({1, "Y-axis"});
|
||||
device.inputs.append({2, "Rumble"});
|
||||
hardwarePort.devices.append(device);
|
||||
}
|
||||
|
||||
ports.append(move(hardwarePort));
|
||||
}
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
return cartridge.manifest();
|
||||
}
|
||||
|
@ -36,16 +18,16 @@ auto Interface::title() -> string {
|
|||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 160;
|
||||
vi.height = 144;
|
||||
vi.internalWidth = 160;
|
||||
vi.internalHeight = 144;
|
||||
vi.aspectCorrection = 1.0;
|
||||
vi.refreshRate = (4.0 * 1024.0 * 1024.0) / (154.0 * 456.0);
|
||||
return vi;
|
||||
}
|
||||
auto Interface::display() -> returns(Display) {
|
||||
type = Display::Type::LCD;
|
||||
colors = Model::GameBoyColor() ? 1 << 15 : 1 << 2;
|
||||
width = 160;
|
||||
height = 144;
|
||||
internalWidth = 160;
|
||||
internalHeight = 144;
|
||||
aspectCorrection = 1.0;
|
||||
refreshRate = (4.0 * 1024.0 * 1024.0) / (154.0 * 456.0);
|
||||
}$
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return system.loaded();
|
||||
|
@ -64,6 +46,38 @@ auto Interface::unload() -> void {
|
|||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::ports() -> vector<Port> { return {
|
||||
{ID::Port::Hardware, "Hardware"}};
|
||||
}
|
||||
|
||||
auto Interface::devices(uint port) -> vector<Device> {
|
||||
if(port == ID::Port::Hardware) return {
|
||||
{ID::Device::Controls, "Controls"}
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Interface::inputs(uint device) -> vector<Input> {
|
||||
using Type = Input::Type;
|
||||
|
||||
if(device == ID::Device::Controls) 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" },
|
||||
{Type::Axis, "X-axis"},
|
||||
{Type::Axis, "Y-axis"},
|
||||
{Type::Rumble, "Rumble"}
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
@ -115,4 +129,7 @@ auto Interface::set(const string& name, const any& value) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
#undef returns
|
||||
#undef $
|
||||
|
||||
}
|
||||
|
|
|
@ -18,12 +18,10 @@ struct ID {
|
|||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
Interface();
|
||||
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto display() -> Display override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto sha256() -> string override;
|
||||
|
@ -31,6 +29,10 @@ struct Interface : Emulator::Interface {
|
|||
auto save() -> void override;
|
||||
auto unload() -> void override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
auto devices(uint port) -> vector<Device> override;
|
||||
auto inputs(uint device) -> vector<Input> override;
|
||||
|
||||
auto power() -> void override;
|
||||
auto run() -> void override;
|
||||
|
||||
|
@ -47,23 +49,21 @@ struct Interface : Emulator::Interface {
|
|||
struct GameBoyInterface : Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
GameBoyInterface();
|
||||
auto information() -> Information override;
|
||||
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto load(uint id) -> bool override;
|
||||
auto load() -> bool override;
|
||||
};
|
||||
|
||||
struct GameBoyColorInterface : Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
GameBoyColorInterface();
|
||||
auto information() -> Information override;
|
||||
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto load(uint id) -> bool override;
|
||||
auto load() -> bool override;
|
||||
};
|
||||
|
||||
struct SuperGameBoyInterface {
|
||||
|
|
|
@ -2,34 +2,15 @@
|
|||
|
||||
namespace GameBoyAdvance {
|
||||
|
||||
#define returns(T) T { return ([&] { struct With : T { With() {
|
||||
#define $ }}; return With(); })(); }
|
||||
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Game Boy Advance";
|
||||
information.overscan = 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::information() -> returns(Information) {
|
||||
manufacturer = "Nintendo";
|
||||
name = "Game Boy Advance";
|
||||
}$
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
return cartridge.manifest();
|
||||
|
@ -39,26 +20,22 @@ auto Interface::title() -> string {
|
|||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 240;
|
||||
vi.height = 160;
|
||||
vi.internalWidth = 240;
|
||||
vi.internalHeight = 160;
|
||||
vi.aspectCorrection = 1.0;
|
||||
vi.refreshRate = system.frequency() / (228.0 * 1232.0);
|
||||
auto Interface::display() -> returns(Display) {
|
||||
type = Display::Type::LCD;
|
||||
colors = 1 << 15;
|
||||
width = 240;
|
||||
height = 160;
|
||||
internalWidth = 240;
|
||||
internalHeight = 160;
|
||||
aspectCorrection = 1.0;
|
||||
refreshRate = system.frequency() / (228.0 * 1232.0);
|
||||
if(settings.rotateLeft) {
|
||||
swap(vi.width, vi.height);
|
||||
swap(vi.internalWidth, vi.internalHeight);
|
||||
swap(width, height);
|
||||
swap(internalWidth, internalHeight);
|
||||
}
|
||||
return vi;
|
||||
}
|
||||
}$
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 1 << 15;
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
uint R = color.bits( 0, 4);
|
||||
uint G = color.bits( 5, 9);
|
||||
uint B = color.bits(10,14);
|
||||
|
@ -84,7 +61,7 @@ auto Interface::loaded() -> bool {
|
|||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
auto Interface::load() -> bool {
|
||||
return system.load(this);
|
||||
}
|
||||
|
||||
|
@ -97,6 +74,38 @@ auto Interface::unload() -> void {
|
|||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::ports() -> vector<Port> { return {
|
||||
{ID::Port::Hardware, "Hardware"}};
|
||||
}
|
||||
|
||||
auto Interface::devices(uint port) -> vector<Device> {
|
||||
if(port == ID::Port::Hardware) return {
|
||||
{ID::Device::Controls, "Controls"}
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Interface::inputs(uint device) -> vector<Input> {
|
||||
using Type = Input::Type;
|
||||
|
||||
if(device == ID::Device::Controls) return {
|
||||
{Type::Hat, "Up" },
|
||||
{Type::Hat, "Down" },
|
||||
{Type::Hat, "Left" },
|
||||
{Type::Hat, "Right" },
|
||||
{Type::Button, "B" },
|
||||
{Type::Button, "A" },
|
||||
{Type::Trigger, "L" },
|
||||
{Type::Trigger, "R" },
|
||||
{Type::Control, "Select"},
|
||||
{Type::Control, "Start" },
|
||||
{Type::Rumble, "Rumble"}
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
@ -150,4 +159,7 @@ auto Interface::set(const string& name, const any& value) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
#undef returns
|
||||
#undef $
|
||||
|
||||
}
|
||||
|
|
|
@ -18,20 +18,23 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
Interface();
|
||||
auto information() -> Information override;
|
||||
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto load(uint id) -> bool override;
|
||||
auto load() -> bool override;
|
||||
auto save() -> void override;
|
||||
auto unload() -> void override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
auto devices(uint port) -> vector<Device> override;
|
||||
auto inputs(uint device) -> vector<Input> override;
|
||||
|
||||
auto power() -> void override;
|
||||
auto run() -> void override;
|
||||
|
||||
|
|
|
@ -2,60 +2,16 @@
|
|||
|
||||
namespace MegaDrive {
|
||||
|
||||
#define returns(T) T { return ([&] { struct With : T { With() {
|
||||
#define $ }}; return With(); })(); }
|
||||
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
information.manufacturer = "Sega";
|
||||
information.name = "Mega Drive";
|
||||
information.overscan = true;
|
||||
information.resettable = true;
|
||||
|
||||
media.append({ID::MegaDrive, "Mega Drive", "md"});
|
||||
|
||||
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
|
||||
Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
|
||||
Port extensionPort{ID::Port::Extension, "Extension Port"};
|
||||
|
||||
{ Device device{ID::Device::None, "None"};
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
extensionPort.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::ControlPad, "Control Pad"};
|
||||
device.inputs.append({0, "Up" });
|
||||
device.inputs.append({0, "Down" });
|
||||
device.inputs.append({0, "Left" });
|
||||
device.inputs.append({0, "Right"});
|
||||
device.inputs.append({0, "A" });
|
||||
device.inputs.append({0, "B" });
|
||||
device.inputs.append({0, "C" });
|
||||
device.inputs.append({0, "Start"});
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::FightingPad, "Fighting Pad"};
|
||||
device.inputs.append({0, "Up" });
|
||||
device.inputs.append({0, "Down" });
|
||||
device.inputs.append({0, "Left" });
|
||||
device.inputs.append({0, "Right"});
|
||||
device.inputs.append({0, "A" });
|
||||
device.inputs.append({0, "B" });
|
||||
device.inputs.append({0, "C" });
|
||||
device.inputs.append({0, "X" });
|
||||
device.inputs.append({0, "Y" });
|
||||
device.inputs.append({0, "Z" });
|
||||
device.inputs.append({0, "Mode" });
|
||||
device.inputs.append({0, "Start"});
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
ports.append(move(controllerPort1));
|
||||
ports.append(move(controllerPort2));
|
||||
ports.append(move(extensionPort));
|
||||
}
|
||||
auto Interface::information() -> returns(Information) {
|
||||
manufacturer = "Sega";
|
||||
name = "Mega Drive";
|
||||
resettable = true;
|
||||
}$
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
return cartridge.manifest();
|
||||
|
@ -65,22 +21,18 @@ auto Interface::title() -> string {
|
|||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 320;
|
||||
vi.height = 240;
|
||||
vi.internalWidth = 1280;
|
||||
vi.internalHeight = 480;
|
||||
vi.aspectCorrection = 1.0;
|
||||
vi.refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0);
|
||||
return vi;
|
||||
}
|
||||
auto Interface::display() -> returns(Display) {
|
||||
type = Display::Type::CRT;
|
||||
colors = 3 * (1 << 9);
|
||||
width = 320;
|
||||
height = 240;
|
||||
internalWidth = 1280;
|
||||
internalHeight = 480;
|
||||
aspectCorrection = 1.0;
|
||||
refreshRate = (system.frequency() / 2.0) / (vdp.frameHeight() * 1710.0);
|
||||
}$
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 3 * (1 << 9);
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
uint R = color.bits(0, 2);
|
||||
uint G = color.bits(3, 5);
|
||||
uint B = color.bits(6, 8);
|
||||
|
@ -103,7 +55,7 @@ auto Interface::loaded() -> bool {
|
|||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
auto Interface::load() -> bool {
|
||||
return system.load(this);
|
||||
}
|
||||
|
||||
|
@ -116,6 +68,67 @@ auto Interface::unload() -> void {
|
|||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::ports() -> vector<Port> { return {
|
||||
{ID::Port::Controller1, "Controller Port 1"},
|
||||
{ID::Port::Controller2, "Controller Port 2"},
|
||||
{ID::Port::Extension, "Extension Port" }};
|
||||
}
|
||||
|
||||
auto Interface::devices(uint port) -> vector<Device> {
|
||||
if(port == ID::Port::Controller1) return {
|
||||
{ID::Device::None, "None" },
|
||||
{ID::Device::ControlPad, "Control Pad" },
|
||||
{ID::Device::FightingPad, "Fighting Pad"}
|
||||
};
|
||||
|
||||
if(port == ID::Port::Controller2) return {
|
||||
{ID::Device::None, "None" },
|
||||
{ID::Device::ControlPad, "Control Pad" },
|
||||
{ID::Device::FightingPad, "Fighting Pad"}
|
||||
};
|
||||
|
||||
if(port == ID::Port::Extension) 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::ControlPad) return {
|
||||
{Type::Hat, "Up" },
|
||||
{Type::Hat, "Down" },
|
||||
{Type::Hat, "Left" },
|
||||
{Type::Hat, "Right"},
|
||||
{Type::Button, "A" },
|
||||
{Type::Button, "B" },
|
||||
{Type::Button, "C" },
|
||||
{Type::Control, "Start"}
|
||||
};
|
||||
|
||||
if(device == ID::Device::FightingPad) return {
|
||||
{Type::Hat, "Up" },
|
||||
{Type::Hat, "Down" },
|
||||
{Type::Hat, "Left" },
|
||||
{Type::Hat, "Right"},
|
||||
{Type::Button, "A" },
|
||||
{Type::Button, "B" },
|
||||
{Type::Button, "C" },
|
||||
{Type::Button, "X" },
|
||||
{Type::Button, "Y" },
|
||||
{Type::Button, "Z" },
|
||||
{Type::Control, "Mode" },
|
||||
{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;
|
||||
|
@ -166,4 +179,7 @@ auto Interface::set(const string& name, const any& value) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
#undef returns
|
||||
#undef $
|
||||
|
||||
}
|
||||
|
|
|
@ -22,20 +22,23 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
Interface();
|
||||
auto information() -> Information override;
|
||||
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto load(uint id) -> bool override;
|
||||
auto load() -> bool override;
|
||||
auto save() -> void override;
|
||||
auto unload() -> void override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
auto devices(uint port) -> vector<Device> override;
|
||||
auto inputs(uint device) -> vector<Input> override;
|
||||
|
||||
auto connected(uint port) -> uint override;
|
||||
auto connect(uint port, uint device) -> void override;
|
||||
auto power() -> void override;
|
||||
|
|
|
@ -2,112 +2,17 @@
|
|||
|
||||
namespace SuperFamicom {
|
||||
|
||||
#define returns(T) T { return ([&] { struct With : T { With() {
|
||||
#define $ }}; return With(); })(); }
|
||||
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
information.manufacturer = "Nintendo";
|
||||
information.name = "Super Famicom";
|
||||
information.overscan = true;
|
||||
information.resettable = true;
|
||||
|
||||
media.append({ID::SuperFamicom, "Super Famicom", "sfc"});
|
||||
|
||||
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
|
||||
Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
|
||||
Port expansionPort{ID::Port::Expansion, "Expansion Port"};
|
||||
|
||||
{ Device device{ID::Device::None, "None"};
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
expansionPort.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::Gamepad, "Gamepad"};
|
||||
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, "Y" });
|
||||
device.inputs.append({0, "X" });
|
||||
device.inputs.append({0, "L" });
|
||||
device.inputs.append({0, "R" });
|
||||
device.inputs.append({0, "Select"});
|
||||
device.inputs.append({0, "Start" });
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::Mouse, "Mouse"};
|
||||
device.inputs.append({1, "X-axis"});
|
||||
device.inputs.append({1, "Y-axis"});
|
||||
device.inputs.append({0, "Left" });
|
||||
device.inputs.append({0, "Right" });
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::SuperMultitap, "Super Multitap"};
|
||||
for(uint p = 2; p <= 5; p++) {
|
||||
device.inputs.append({0, {"Port ", p, " - ", "Up" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "Down" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "Left" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "Right" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "B" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "A" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "Y" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "X" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "L" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "R" }});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "Select"}});
|
||||
device.inputs.append({0, {"Port ", p, " - ", "Start" }});
|
||||
}
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::SuperScope, "Super Scope"};
|
||||
device.inputs.append({1, "X-axis" });
|
||||
device.inputs.append({1, "Y-axis" });
|
||||
device.inputs.append({0, "Trigger"});
|
||||
device.inputs.append({0, "Cursor" });
|
||||
device.inputs.append({0, "Turbo" });
|
||||
device.inputs.append({0, "Pause" });
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::Justifier, "Justifier"};
|
||||
device.inputs.append({1, "X-axis" });
|
||||
device.inputs.append({1, "Y-axis" });
|
||||
device.inputs.append({0, "Trigger"});
|
||||
device.inputs.append({0, "Start" });
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::Justifiers, "Justifiers"};
|
||||
device.inputs.append({1, "Port 1 - X-axis" });
|
||||
device.inputs.append({1, "Port 1 - Y-axis" });
|
||||
device.inputs.append({0, "Port 1 - Trigger"});
|
||||
device.inputs.append({0, "Port 1 - Start" });
|
||||
device.inputs.append({1, "Port 2 - X-axis" });
|
||||
device.inputs.append({1, "Port 2 - Y-axis" });
|
||||
device.inputs.append({0, "Port 2 - Trigger"});
|
||||
device.inputs.append({0, "Port 2 - Start" });
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::Satellaview, "Satellaview"};
|
||||
expansionPort.devices.append(device);
|
||||
}
|
||||
|
||||
{ Device device{ID::Device::S21FX, "21fx"};
|
||||
expansionPort.devices.append(device);
|
||||
}
|
||||
|
||||
ports.append(move(controllerPort1));
|
||||
ports.append(move(controllerPort2));
|
||||
ports.append(move(expansionPort));
|
||||
}
|
||||
auto Interface::information() -> returns(Information) {
|
||||
manufacturer = "Nintendo";
|
||||
name = "Super Famicom";
|
||||
extension = "sfc";
|
||||
resettable = true;
|
||||
}$
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
return cartridge.manifest();
|
||||
|
@ -117,23 +22,19 @@ auto Interface::title() -> string {
|
|||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoInformation() -> VideoInformation {
|
||||
VideoInformation vi;
|
||||
vi.width = 256;
|
||||
vi.height = 240;
|
||||
vi.internalWidth = 512;
|
||||
vi.internalHeight = 480;
|
||||
vi.aspectCorrection = 8.0 / 7.0;
|
||||
if(Region::NTSC()) vi.refreshRate = system.cpuFrequency() / (262.0 * 1364.0);
|
||||
if(Region::PAL()) vi.refreshRate = system.cpuFrequency() / (312.0 * 1364.0);
|
||||
return vi;
|
||||
}
|
||||
auto Interface::display() -> returns(Display) {
|
||||
type = Display::Type::CRT;
|
||||
colors = 1 << 19;
|
||||
width = 256;
|
||||
height = 240;
|
||||
internalWidth = 512;
|
||||
internalHeight = 480;
|
||||
aspectCorrection = 8.0 / 7.0;
|
||||
if(Region::NTSC()) refreshRate = system.cpuFrequency() / (262.0 * 1364.0);
|
||||
if(Region::PAL()) refreshRate = system.cpuFrequency() / (312.0 * 1364.0);
|
||||
}$
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 1 << 19;
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
auto Interface::color(uint32 color) -> uint64 {
|
||||
uint r = color.bits( 0, 4);
|
||||
uint g = color.bits( 5, 9);
|
||||
uint b = color.bits(10,14);
|
||||
|
@ -169,12 +70,8 @@ auto Interface::sha256() -> string {
|
|||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
if(id == ID::SuperFamicom) return system.load(this);
|
||||
if(id == ID::BSMemory) return cartridge.loadBSMemory();
|
||||
if(id == ID::SufamiTurboA) return cartridge.loadSufamiTurboA();
|
||||
if(id == ID::SufamiTurboB) return cartridge.loadSufamiTurboB();
|
||||
return false;
|
||||
auto Interface::load() -> bool {
|
||||
return system.load(this);
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
|
@ -186,6 +83,121 @@ auto Interface::unload() -> void {
|
|||
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"},
|
||||
{ID::Device::Mouse, "Mouse" }
|
||||
};
|
||||
|
||||
if(port == ID::Port::Controller2) return {
|
||||
{ID::Device::None, "None" },
|
||||
{ID::Device::Gamepad, "Gamepad" },
|
||||
{ID::Device::Mouse, "Mouse" },
|
||||
{ID::Device::SuperMultitap, "Super Multitap"},
|
||||
{ID::Device::SuperScope, "Super Scope" },
|
||||
{ID::Device::Justifier, "Justifier" },
|
||||
{ID::Device::Justifiers, "Justifiers" }
|
||||
};
|
||||
|
||||
if(port == ID::Port::Expansion) return {
|
||||
{ID::Device::None, "None" },
|
||||
{ID::Device::Satellaview, "Satellaview"},
|
||||
{ID::Device::S21FX, "21fx" }
|
||||
};
|
||||
|
||||
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::Button, "Y" },
|
||||
{Type::Button, "X" },
|
||||
{Type::Trigger, "L" },
|
||||
{Type::Trigger, "R" },
|
||||
{Type::Control, "Select"},
|
||||
{Type::Control, "Start" }
|
||||
};
|
||||
|
||||
if(device == ID::Device::Mouse) return {
|
||||
{Type::Axis, "X-axis"},
|
||||
{Type::Axis, "Y-axis"},
|
||||
{Type::Button, "Left" },
|
||||
{Type::Button, "Right" }
|
||||
};
|
||||
|
||||
if(device == ID::Device::SuperMultitap) {
|
||||
vector<Input> inputs;
|
||||
for(uint p = 2; p <= 5; p++) inputs.append({
|
||||
{Type::Hat, {"Port ", p, " - ", "Up" }},
|
||||
{Type::Hat, {"Port ", p, " - ", "Down" }},
|
||||
{Type::Hat, {"Port ", p, " - ", "Left" }},
|
||||
{Type::Hat, {"Port ", p, " - ", "Right" }},
|
||||
{Type::Button, {"Port ", p, " - ", "B" }},
|
||||
{Type::Button, {"Port ", p, " - ", "A" }},
|
||||
{Type::Button, {"Port ", p, " - ", "Y" }},
|
||||
{Type::Button, {"Port ", p, " - ", "X" }},
|
||||
{Type::Trigger, {"Port ", p, " - ", "L" }},
|
||||
{Type::Trigger, {"Port ", p, " - ", "R" }},
|
||||
{Type::Control, {"Port ", p, " - ", "Select"}},
|
||||
{Type::Control, {"Port ", p, " - ", "Start" }}
|
||||
});
|
||||
return inputs;
|
||||
}
|
||||
|
||||
if(device == ID::Device::SuperScope) return {
|
||||
{Type::Axis, "X-axis" },
|
||||
{Type::Axis, "Y-axis" },
|
||||
{Type::Control, "Trigger"},
|
||||
{Type::Control, "Cursor" },
|
||||
{Type::Control, "Turbo" },
|
||||
{Type::Control, "Pause" }
|
||||
};
|
||||
|
||||
if(device == ID::Device::Justifier) return {
|
||||
{Type::Axis, "X-axis" },
|
||||
{Type::Axis, "Y-axis" },
|
||||
{Type::Control, "Trigger"},
|
||||
{Type::Control, "Start" }
|
||||
};
|
||||
|
||||
if(device == ID::Device::Justifiers) return {
|
||||
{Type::Axis, "Port 1 - X-axis" },
|
||||
{Type::Axis, "Port 1 - Y-axis" },
|
||||
{Type::Control, "Port 1 - Trigger"},
|
||||
{Type::Control, "Port 1 - Start" },
|
||||
{Type::Axis, "Port 2 - X-axis" },
|
||||
{Type::Axis, "Port 2 - Y-axis" },
|
||||
{Type::Control, "Port 2 - Trigger"},
|
||||
{Type::Control, "Port 2 - Start" }
|
||||
};
|
||||
|
||||
if(device == ID::Device::Satellaview) return {
|
||||
};
|
||||
|
||||
if(device == ID::Device::S21FX) return {
|
||||
};
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Interface::connected(uint port) -> uint {
|
||||
if(port == ID::Port::Controller1) return settings.controllerPort1;
|
||||
if(port == ID::Port::Controller2) return settings.controllerPort2;
|
||||
|
@ -295,4 +307,7 @@ auto Interface::set(const string& name, const any& value) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
#undef returns
|
||||
#undef $
|
||||
|
||||
}
|
||||
|
|
|
@ -33,21 +33,23 @@ struct ID {
|
|||
struct Interface : Emulator::Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
Interface();
|
||||
|
||||
auto information() -> Information;
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
|
||||
auto videoInformation() -> VideoInformation override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
auto display() -> Display override;
|
||||
auto color(uint32 color) -> uint64 override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto sha256() -> string override;
|
||||
auto load(uint id) -> bool override;
|
||||
auto load() -> bool override;
|
||||
auto save() -> void override;
|
||||
auto unload() -> void override;
|
||||
|
||||
auto ports() -> vector<Port> override;
|
||||
auto devices(uint port) -> vector<Device> override;
|
||||
auto inputs(uint device) -> vector<Input> override;
|
||||
|
||||
auto connected(uint port) -> uint override;
|
||||
auto connect(uint port, uint device) -> void override;
|
||||
auto power() -> void override;
|
||||
|
|
|
@ -27,6 +27,7 @@ auto nall::main(string_vector arguments) -> void {
|
|||
}
|
||||
}
|
||||
Application::setName("bsnes");
|
||||
Application::setScreenSaver(false);
|
||||
Application::locale().scan(locate("locales/"));
|
||||
Application::locale().select(locale);
|
||||
emulator = new SuperFamicom::Interface;
|
||||
|
|
|
@ -187,11 +187,11 @@ auto InputManager::initialize() -> void {
|
|||
input->onChange({&InputManager::onChange, this});
|
||||
frequency = max(1u, settings["Input/Frequency"].natural());
|
||||
|
||||
for(auto& port : emulator->ports) {
|
||||
for(auto& port : emulator->ports()) {
|
||||
InputPort inputPort{port.id, port.name};
|
||||
for(auto& device : port.devices) {
|
||||
for(auto& device : emulator->devices(port.id)) {
|
||||
InputDevice inputDevice{device.id, device.name};
|
||||
for(auto& input : device.inputs) {
|
||||
for(auto& input : emulator->inputs(device.id)) {
|
||||
InputMapping inputMapping;
|
||||
inputMapping.name = input.name;
|
||||
inputMapping.type = input.type;
|
||||
|
|
|
@ -7,9 +7,16 @@ struct InputMapping {
|
|||
auto rumble(bool enable) -> void;
|
||||
auto displayName() -> string;
|
||||
|
||||
auto isDigital() const -> bool { return type == 0; }
|
||||
auto isAnalog() const -> bool { return type == 1; }
|
||||
auto isRumble() const -> bool { return type == 2; }
|
||||
using Type = Emulator::Interface::Input::Type;
|
||||
auto isDigital() const -> bool {
|
||||
return type == Type::Hat || type == Type::Button || type == Type::Trigger || type == Type::Control;
|
||||
}
|
||||
auto isAnalog() const -> bool {
|
||||
return type == Type::Axis;
|
||||
}
|
||||
auto isRumble() const -> bool {
|
||||
return type == Type::Rumble;
|
||||
}
|
||||
|
||||
string path; //configuration file key path
|
||||
string name; //input name (human readable)
|
||||
|
|
|
@ -183,14 +183,6 @@ Presentation::Presentation() {
|
|||
Application::Windows::onModalChange([&](bool modal) {
|
||||
if(modal && audio) audio->clear();
|
||||
});
|
||||
Application::Windows::onScreenSaver([&]() -> bool {
|
||||
if(emulator->loaded()) {
|
||||
if(pauseEmulation.checked()) return true;
|
||||
if(!program->focused() && settingsWindow->input.pauseEmulation.checked()) return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_MACOS)
|
||||
|
@ -346,7 +338,7 @@ auto Presentation::updateDeviceMenu() -> void {
|
|||
controllerPort2.reset();
|
||||
expansionPort.reset();
|
||||
|
||||
for(auto& port : emulator->ports) {
|
||||
for(auto& port : emulator->ports()) {
|
||||
Menu* menu = nullptr;
|
||||
if(port.name == "Controller Port 1") menu = &controllerPort1;
|
||||
if(port.name == "Controller Port 2") menu = &controllerPort2;
|
||||
|
@ -358,7 +350,7 @@ auto Presentation::updateDeviceMenu() -> void {
|
|||
auto deviceID = emulator->connected(port.id);
|
||||
|
||||
Group devices;
|
||||
for(auto& device : port.devices) {
|
||||
for(auto& device : emulator->devices(port.id)) {
|
||||
if(port.name == "Expansion Port" && device.name == "21fx") continue;
|
||||
|
||||
MenuRadioItem item{menu};
|
||||
|
@ -380,7 +372,7 @@ auto Presentation::updateDeviceMenu() -> void {
|
|||
}
|
||||
|
||||
auto Presentation::updateDeviceSelections() -> void {
|
||||
for(auto& port : emulator->ports) {
|
||||
for(auto& port : emulator->ports()) {
|
||||
Menu* menu = nullptr;
|
||||
if(port.name == "Controller Port 1") menu = &controllerPort1;
|
||||
if(port.name == "Controller Port 2") menu = &controllerPort2;
|
||||
|
|
|
@ -1,60 +1,52 @@
|
|||
auto Program::load() -> void {
|
||||
unload();
|
||||
|
||||
for(auto& media : emulator->media) {
|
||||
if(media.type != "sfc") continue;
|
||||
|
||||
if(emulator->load(media.id)) {
|
||||
screenshot = {};
|
||||
frameAdvance = false;
|
||||
if(!verified() && settingsWindow->advanced.warnOnUnverifiedGames.checked()) {
|
||||
//todo: MessageDialog crashes with GTK+; unsure the reason why this happens
|
||||
//once MessageDialog functions, add an "Always" option
|
||||
if(MessageWindow(
|
||||
"Warning: this game image is unverified. Running it *may* be a security risk.\n\n"
|
||||
"Do you wish to run the game anyway?"
|
||||
).setParent(*presentation).question() == MessageWindow::Response::No) {
|
||||
emulator->unload();
|
||||
return showMessage("Game loading cancelled");
|
||||
}
|
||||
}
|
||||
hackCompatibility();
|
||||
emulator->power();
|
||||
if(settingsWindow->advanced.autoLoadStateOnLoad.checked()) {
|
||||
program->loadState("quick/undo");
|
||||
}
|
||||
showMessage({
|
||||
verified() ? "Verified game loaded" : "Game loaded",
|
||||
appliedPatch() ? " and patch applied" : ""
|
||||
});
|
||||
presentation->setTitle(emulator->title());
|
||||
presentation->resetSystem.setEnabled(true);
|
||||
presentation->unloadGame.setEnabled(true);
|
||||
presentation->toolsMenu.setVisible(true);
|
||||
presentation->speedNormal.setChecked();
|
||||
presentation->pauseEmulation.setChecked(false);
|
||||
presentation->updateStatusIcon();
|
||||
presentation->resizeViewport();
|
||||
toolsWindow->cheatEditor.loadCheats();
|
||||
toolsWindow->stateManager.loadStates();
|
||||
toolsWindow->manifestViewer.loadManifest();
|
||||
|
||||
string locations = superFamicom.location;
|
||||
if(auto location = gameBoy.location) locations.append("|", location);
|
||||
if(auto location = bsMemory.location) locations.append("|", location);
|
||||
if(auto location = sufamiTurboA.location) locations.append("|", location);
|
||||
if(auto location = sufamiTurboB.location) locations.append("|", location);
|
||||
presentation->addRecentGame(locations);
|
||||
|
||||
updateVideoPalette();
|
||||
updateAudioEffects();
|
||||
updateAudioFrequency();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if(!emulator->load()) return;
|
||||
|
||||
gameQueue = {};
|
||||
screenshot = {};
|
||||
frameAdvance = false;
|
||||
if(!verified() && settingsWindow->advanced.warnOnUnverifiedGames.checked()) {
|
||||
//todo: MessageDialog crashes with GTK+; unsure the reason why this happens
|
||||
//once MessageDialog functions, add an "Always" option
|
||||
if(MessageWindow(
|
||||
"Warning: this game image is unverified. Running it *may* be a security risk.\n\n"
|
||||
"Do you wish to run the game anyway?"
|
||||
).setParent(*presentation).question() == MessageWindow::Response::No) {
|
||||
emulator->unload();
|
||||
return showMessage("Game loading cancelled");
|
||||
}
|
||||
}
|
||||
hackCompatibility();
|
||||
emulator->power();
|
||||
if(settingsWindow->advanced.autoLoadStateOnLoad.checked()) {
|
||||
program->loadState("quick/undo");
|
||||
}
|
||||
showMessage({
|
||||
verified() ? "Verified game loaded" : "Game loaded",
|
||||
appliedPatch() ? " and patch applied" : ""
|
||||
});
|
||||
presentation->setTitle(emulator->title());
|
||||
presentation->resetSystem.setEnabled(true);
|
||||
presentation->unloadGame.setEnabled(true);
|
||||
presentation->toolsMenu.setVisible(true);
|
||||
presentation->speedNormal.setChecked();
|
||||
presentation->pauseEmulation.setChecked(false);
|
||||
presentation->updateStatusIcon();
|
||||
presentation->resizeViewport();
|
||||
toolsWindow->cheatEditor.loadCheats();
|
||||
toolsWindow->stateManager.loadStates();
|
||||
toolsWindow->manifestViewer.loadManifest();
|
||||
|
||||
string locations = superFamicom.location;
|
||||
if(auto location = gameBoy.location) locations.append("|", location);
|
||||
if(auto location = bsMemory.location) locations.append("|", location);
|
||||
if(auto location = sufamiTurboA.location) locations.append("|", location);
|
||||
if(auto location = sufamiTurboB.location) locations.append("|", location);
|
||||
presentation->addRecentGame(locations);
|
||||
|
||||
updateVideoPalette();
|
||||
updateAudioEffects();
|
||||
updateAudioFrequency();
|
||||
}
|
||||
|
||||
auto Program::loadFile(string location) -> vector<uint8_t> {
|
||||
|
|
|
@ -3,12 +3,12 @@ flags += -DSFC_SUPERGAMEBOY
|
|||
|
||||
include fc/GNUmakefile
|
||||
include sfc/GNUmakefile
|
||||
include ms/GNUmakefile
|
||||
#include ms/GNUmakefile
|
||||
include md/GNUmakefile
|
||||
include pce/GNUmakefile
|
||||
#include pce/GNUmakefile
|
||||
include gb/GNUmakefile
|
||||
include gba/GNUmakefile
|
||||
include ws/GNUmakefile
|
||||
#include ws/GNUmakefile
|
||||
include processor/GNUmakefile
|
||||
|
||||
hiro.path := ../hiro
|
||||
|
|
|
@ -15,6 +15,7 @@ auto locate(string name) -> string {
|
|||
#include <nall/main.hpp>
|
||||
auto nall::main(string_vector args) -> void {
|
||||
Application::setName("higan");
|
||||
Application::setScreenSaver(false);
|
||||
new Program(args);
|
||||
Application::run();
|
||||
}
|
||||
|
|
|
@ -192,12 +192,12 @@ InputManager::InputManager() {
|
|||
for(auto& emulator : program->emulators) {
|
||||
InputEmulator inputEmulator;
|
||||
inputEmulator.interface = emulator;
|
||||
inputEmulator.name = emulator->information.name;
|
||||
for(auto& port : emulator->ports) {
|
||||
inputEmulator.name = emulator->information().name;
|
||||
for(auto& port : emulator->ports()) {
|
||||
InputPort inputPort{port.id, port.name};
|
||||
for(auto& device : port.devices) {
|
||||
for(auto& device : emulator->devices(port.id)) {
|
||||
InputDevice inputDevice{device.id, device.name};
|
||||
for(auto& input : device.inputs) {
|
||||
for(auto& input : emulator->inputs(device.id)) {
|
||||
InputMapping inputMapping;
|
||||
inputMapping.name = input.name;
|
||||
inputMapping.type = input.type;
|
||||
|
|
|
@ -6,9 +6,16 @@ struct InputMapping {
|
|||
auto poll() -> int16;
|
||||
auto rumble(bool enable) -> void;
|
||||
|
||||
auto isDigital() const -> bool { return type == 0; }
|
||||
auto isAnalog() const -> bool { return type == 1; }
|
||||
auto isRumble() const -> bool { return type == 2; }
|
||||
using Type = Emulator::Interface::Input::Type;
|
||||
auto isDigital() const -> bool {
|
||||
return type == Type::Hat || type == Type::Button || type == Type::Trigger || type == Type::Control;
|
||||
}
|
||||
auto isAnalog() const -> bool {
|
||||
return type == Type::Axis;
|
||||
}
|
||||
auto isRumble() const -> bool {
|
||||
return type == Type::Rumble;
|
||||
}
|
||||
|
||||
auto displayName() -> string;
|
||||
|
||||
|
|
|
@ -122,8 +122,8 @@ Presentation::Presentation() {
|
|||
|
||||
viewport.setDroppable().onDrop([&](auto locations) {
|
||||
if(!directory::exists(locations(0))) return;
|
||||
program->mediumQueue.append(locations(0));
|
||||
program->loadMedium();
|
||||
program->gameQueue.append(locations(0));
|
||||
program->load();
|
||||
});
|
||||
|
||||
onSize([&] {
|
||||
|
@ -143,14 +143,6 @@ Presentation::Presentation() {
|
|||
Application::Windows::onModalChange([&](bool modal) {
|
||||
if(modal && audio) audio->clear();
|
||||
});
|
||||
Application::Windows::onScreenSaver([&]() -> bool {
|
||||
if(emulator && emulator->loaded()) {
|
||||
if(program->pause) return true;
|
||||
if(!program->focused() && settingsManager->input.pauseEmulation.checked()) return true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
#endif
|
||||
|
||||
#if defined(PLATFORM_MACOS)
|
||||
|
@ -164,9 +156,10 @@ Presentation::Presentation() {
|
|||
|
||||
auto Presentation::updateEmulatorMenu() -> void {
|
||||
if(!emulator) return;
|
||||
auto information = emulator->information();
|
||||
|
||||
systemMenu.reset();
|
||||
for(auto& port : emulator->ports) {
|
||||
for(auto& port : emulator->ports()) {
|
||||
Menu menu{&systemMenu};
|
||||
menu.setProperty("portID", port.id);
|
||||
menu.setText(port.name);
|
||||
|
@ -176,12 +169,12 @@ auto Presentation::updateEmulatorMenu() -> void {
|
|||
menu.setIcon(Icon::Device::Joypad);
|
||||
}
|
||||
|
||||
auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
|
||||
auto path = string{information.name, "/", port.name}.replace(" ", "");
|
||||
auto deviceName = settings(path).text();
|
||||
auto deviceID = emulator->connected(port.id);
|
||||
|
||||
Group devices;
|
||||
for(auto& device : port.devices) {
|
||||
for(auto& device : emulator->devices(port.id)) {
|
||||
MenuRadioItem item{&menu};
|
||||
item.setProperty("deviceID", device.id);
|
||||
item.setText(device.name);
|
||||
|
@ -205,7 +198,7 @@ auto Presentation::updateEmulatorMenu() -> void {
|
|||
systemMenu.append(MenuSeparator());
|
||||
}
|
||||
|
||||
if(emulator->information.resettable) {
|
||||
if(information.resettable) {
|
||||
systemMenu.append(MenuItem().setText("Soft Reset").setIcon(Icon::Action::Refresh).onActivate([&] {
|
||||
program->softReset();
|
||||
}));
|
||||
|
@ -216,7 +209,7 @@ auto Presentation::updateEmulatorMenu() -> void {
|
|||
}));
|
||||
|
||||
systemMenu.append(MenuItem().setText("Unload").setIcon(Icon::Media::Eject).onActivate([&] {
|
||||
program->unloadMedium();
|
||||
program->unload();
|
||||
}));
|
||||
|
||||
updateEmulatorDeviceSelections();
|
||||
|
@ -225,7 +218,7 @@ auto Presentation::updateEmulatorMenu() -> void {
|
|||
auto Presentation::updateEmulatorDeviceSelections() -> void {
|
||||
if(!emulator) return;
|
||||
|
||||
for(auto& port : emulator->ports) {
|
||||
for(auto& port : emulator->ports()) {
|
||||
for(auto& action : systemMenu->actions()) {
|
||||
auto portID = action.property("portID");
|
||||
if(portID && portID.natural() == port.id) {
|
||||
|
@ -293,11 +286,11 @@ auto Presentation::resizeViewport(bool resizeWindow) -> void {
|
|||
double emulatorHeight = 240;
|
||||
double aspectCorrection = 1.0;
|
||||
if(emulator) {
|
||||
auto information = emulator->videoInformation();
|
||||
emulatorWidth = information.width;
|
||||
emulatorHeight = information.height;
|
||||
aspectCorrection = information.aspectCorrection;
|
||||
if(emulator->information.overscan) {
|
||||
auto display = emulator->display();
|
||||
emulatorWidth = display.width;
|
||||
emulatorHeight = display.height;
|
||||
aspectCorrection = display.aspectCorrection;
|
||||
if(display.type == Emulator::Interface::Display::Type::CRT) {
|
||||
uint overscanHorizontal = settings["Video/Overscan/Horizontal"].natural();
|
||||
uint overscanVertical = settings["Video/Overscan/Vertical"].natural();
|
||||
emulatorWidth -= overscanHorizontal * 2;
|
||||
|
@ -387,37 +380,38 @@ auto Presentation::loadSystems() -> void {
|
|||
systemsMenu.reset();
|
||||
for(auto system : settings.find("Systems/System")) {
|
||||
if(!system["Visible"].boolean()) continue;
|
||||
MenuItem item;
|
||||
MenuItem item{&systemsMenu};
|
||||
string name = system.text();
|
||||
string filename = system["Load"].text();
|
||||
string load = Location::base(filename).trimRight("/", 1L);
|
||||
string alias = system["Alias"].text();
|
||||
item
|
||||
.setIcon(load ? Icon::Emblem::Folder : Icon::Device::Storage)
|
||||
.setText({alias ? alias : load ? load : name, " ..."}).onActivate([=] {
|
||||
item.setIcon(load ? Icon::Emblem::Folder : Icon::Device::Storage);
|
||||
item.setText({alias ? alias : load ? load : name, " ..."});
|
||||
item.onActivate([=] {
|
||||
for(auto& emulator : program->emulators) {
|
||||
if(name == emulator->information.name) {
|
||||
if(filename) program->mediumQueue.append(filename);
|
||||
program->loadMedium(*emulator, emulator->media(0));
|
||||
auto information = emulator->information();
|
||||
if(name == information.name) {
|
||||
if(filename) program->gameQueue.append(filename);
|
||||
program->load(*emulator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
systemsMenu.append(item);
|
||||
}
|
||||
|
||||
//add icarus menu option -- but only if icarus binary is present
|
||||
if(execute("icarus", "--name").output.strip() == "icarus") {
|
||||
if(systemsMenu.actionCount()) systemsMenu.append(MenuSeparator());
|
||||
systemsMenu.append(MenuItem()
|
||||
.setIcon(Icon::Emblem::File)
|
||||
.setText("Load ROM File ...").onActivate([&] {
|
||||
MenuItem item{&systemsMenu};
|
||||
item.setIcon(Icon::Emblem::File);
|
||||
item.setText("Load ROM File ...");
|
||||
item.onActivate([&] {
|
||||
audio->clear();
|
||||
if(auto location = execute("icarus", "--import")) {
|
||||
program->mediumQueue.append(location.output.strip());
|
||||
program->loadMedium();
|
||||
program->gameQueue.append(location.output.strip());
|
||||
program->load();
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,28 @@
|
|||
auto Program::loadMedium() -> void {
|
||||
if(!mediumQueue) return;
|
||||
auto Program::load() -> void {
|
||||
if(!gameQueue) return;
|
||||
|
||||
string location = mediumQueue.left();
|
||||
string type = Location::suffix(location).trimLeft(".", 1L);
|
||||
string location = gameQueue.left();
|
||||
string extension = Location::suffix(location).trimLeft(".", 1L);
|
||||
|
||||
for(auto& emulator : emulators) {
|
||||
for(auto& medium : emulator->media) {
|
||||
if(medium.type != type) continue;
|
||||
return loadMedium(*emulator, medium);
|
||||
}
|
||||
auto information = emulator->information();
|
||||
if(information.extension == extension) return load(*emulator);
|
||||
}
|
||||
|
||||
mediumQueue.reset();
|
||||
gameQueue.reset();
|
||||
}
|
||||
|
||||
auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interface::Medium& medium) -> void {
|
||||
unloadMedium();
|
||||
auto Program::load(Emulator::Interface& interface) -> void {
|
||||
unload();
|
||||
|
||||
mediumPaths.append(locate({"systems/", medium.name, ".sys/"}));
|
||||
auto information = interface.information();
|
||||
gamePaths.append(locate({"systems/", information.name, ".sys/"}));
|
||||
|
||||
inputManager->bind(emulator = &interface);
|
||||
presentation->updateEmulatorMenu();
|
||||
if(!emulator->load(medium.id)) {
|
||||
if(!emulator->load()) {
|
||||
emulator = nullptr;
|
||||
mediumPaths.reset();
|
||||
gamePaths.reset();
|
||||
return;
|
||||
}
|
||||
emulator->power();
|
||||
|
@ -35,7 +34,7 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
|
|||
|
||||
presentation->resizeViewport();
|
||||
presentation->setTitle(emulator->title());
|
||||
presentation->systemMenu.setText(medium.name).setVisible(true);
|
||||
presentation->systemMenu.setText(information.name).setVisible(true);
|
||||
presentation->toolsMenu.setVisible(true);
|
||||
toolsManager->cheatEditor.loadCheats();
|
||||
toolsManager->stateManager.doRefresh();
|
||||
|
@ -43,7 +42,7 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
|
|||
toolsManager->gameNotes.loadNotes();
|
||||
}
|
||||
|
||||
auto Program::unloadMedium() -> void {
|
||||
auto Program::unload() -> void {
|
||||
if(!emulator) return;
|
||||
|
||||
presentation->clearViewport();
|
||||
|
@ -51,7 +50,7 @@ auto Program::unloadMedium() -> void {
|
|||
toolsManager->gameNotes.saveNotes();
|
||||
emulator->unload();
|
||||
emulator = nullptr;
|
||||
mediumPaths.reset();
|
||||
gamePaths.reset();
|
||||
|
||||
presentation->resizeViewport();
|
||||
presentation->setTitle({"higan v", Emulator::Version});
|
|
@ -1,5 +1,5 @@
|
|||
auto Program::path(uint id) -> string {
|
||||
return mediumPaths(id);
|
||||
return gamePaths(id);
|
||||
}
|
||||
|
||||
auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> vfs::shared::file {
|
||||
|
@ -25,8 +25,8 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
|
|||
|
||||
auto Program::load(uint id, string name, string type, string_vector options) -> Emulator::Platform::Load {
|
||||
string location, option;
|
||||
if(mediumQueue) {
|
||||
auto entry = mediumQueue.takeLeft().split("|", 1L);
|
||||
if(gameQueue) {
|
||||
auto entry = gameQueue.takeLeft().split("|", 1L);
|
||||
location = entry.right();
|
||||
if(entry.size() == 1) option = options(0);
|
||||
if(entry.size() == 2) option = entry.left();
|
||||
|
@ -41,12 +41,12 @@ auto Program::load(uint id, string name, string type, string_vector options) ->
|
|||
option = dialog.option();
|
||||
}
|
||||
if(!directory::exists(location)) {
|
||||
mediumQueue.reset();
|
||||
gameQueue.reset();
|
||||
return {};
|
||||
}
|
||||
|
||||
uint pathID = mediumPaths.size();
|
||||
mediumPaths.append(location);
|
||||
uint pathID = gamePaths.size();
|
||||
gamePaths.append(location);
|
||||
return {pathID, option};
|
||||
}
|
||||
|
||||
|
@ -56,12 +56,12 @@ auto Program::videoRefresh(const uint32* data, uint pitch, uint width, uint heig
|
|||
|
||||
pitch >>= 2;
|
||||
|
||||
if(emulator->information.overscan) {
|
||||
auto display = emulator->display();
|
||||
if(display.type == Emulator::Interface::Display::Type::CRT) {
|
||||
uint overscanHorizontal = settings["Video/Overscan/Horizontal"].natural();
|
||||
uint overscanVertical = settings["Video/Overscan/Vertical"].natural();
|
||||
auto information = emulator->videoInformation();
|
||||
overscanHorizontal *= information.internalWidth / information.width;
|
||||
overscanVertical *= information.internalHeight / information.height;
|
||||
overscanHorizontal *= display.internalWidth / display.width;
|
||||
overscanVertical *= display.internalHeight / display.height;
|
||||
data += overscanVertical * pitch + overscanHorizontal;
|
||||
width -= overscanHorizontal * 2;
|
||||
height -= overscanVertical * 2;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include "../higan.hpp"
|
||||
#include <fc/interface/interface.hpp>
|
||||
#include <sfc/interface/interface.hpp>
|
||||
#include <ms/interface/interface.hpp>
|
||||
//#include <ms/interface/interface.hpp>
|
||||
#include <md/interface/interface.hpp>
|
||||
#include <pce/interface/interface.hpp>
|
||||
//#include <pce/interface/interface.hpp>
|
||||
#include <gb/interface/interface.hpp>
|
||||
#include <gba/interface/interface.hpp>
|
||||
#include <ws/interface/interface.hpp>
|
||||
//#include <ws/interface/interface.hpp>
|
||||
#include "platform.cpp"
|
||||
#include "medium.cpp"
|
||||
#include "game.cpp"
|
||||
#include "state.cpp"
|
||||
#include "utility.cpp"
|
||||
unique_pointer<Program> program;
|
||||
|
@ -19,17 +19,17 @@ Program::Program(string_vector args) {
|
|||
Emulator::platform = this;
|
||||
emulators.append(new Famicom::Interface);
|
||||
emulators.append(new SuperFamicom::Interface);
|
||||
emulators.append(new MasterSystem::MasterSystemInterface);
|
||||
// emulators.append(new MasterSystem::MasterSystemInterface);
|
||||
emulators.append(new MegaDrive::Interface);
|
||||
emulators.append(new PCEngine::PCEngineInterface);
|
||||
emulators.append(new PCEngine::SuperGrafxInterface);
|
||||
// emulators.append(new PCEngine::PCEngineInterface);
|
||||
// emulators.append(new PCEngine::SuperGrafxInterface);
|
||||
emulators.append(new GameBoy::GameBoyInterface);
|
||||
emulators.append(new GameBoy::GameBoyColorInterface);
|
||||
emulators.append(new GameBoyAdvance::Interface);
|
||||
emulators.append(new MasterSystem::GameGearInterface);
|
||||
emulators.append(new WonderSwan::WonderSwanInterface);
|
||||
emulators.append(new WonderSwan::WonderSwanColorInterface);
|
||||
emulators.append(new WonderSwan::PocketChallengeV2Interface);
|
||||
// emulators.append(new MasterSystem::GameGearInterface);
|
||||
// emulators.append(new WonderSwan::WonderSwanInterface);
|
||||
// emulators.append(new WonderSwan::WonderSwanColorInterface);
|
||||
// emulators.append(new WonderSwan::PocketChallengeV2Interface);
|
||||
|
||||
new Presentation;
|
||||
presentation->setVisible();
|
||||
|
@ -68,14 +68,14 @@ Program::Program(string_vector args) {
|
|||
presentation->toggleFullScreen();
|
||||
} else if(directory::exists(argument.split("|", 1L).right())) {
|
||||
if(!argument.transform("\\", "/").endsWith("/")) argument.append("/");
|
||||
mediumQueue.append(argument);
|
||||
gameQueue.append(argument);
|
||||
} else if(file::exists(argument)) {
|
||||
if(auto result = execute("icarus", "--import", argument)) {
|
||||
mediumQueue.append(result.output.strip());
|
||||
gameQueue.append(result.output.strip());
|
||||
}
|
||||
}
|
||||
}
|
||||
loadMedium();
|
||||
if(gameQueue) load();
|
||||
|
||||
Application::onMain({&Program::main, this});
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ auto Program::main() -> void {
|
|||
|
||||
auto Program::quit() -> void {
|
||||
hasQuit = true;
|
||||
unloadMedium();
|
||||
unload();
|
||||
settings.save();
|
||||
inputManager->quit();
|
||||
video.reset();
|
||||
|
|
|
@ -15,10 +15,10 @@ struct Program : Emulator::Platform {
|
|||
auto dipSettings(Markup::Node node) -> uint override;
|
||||
auto notify(string text) -> void override;
|
||||
|
||||
//medium.cpp
|
||||
auto loadMedium() -> void;
|
||||
auto loadMedium(Emulator::Interface& interface, const Emulator::Interface::Medium& medium) -> void;
|
||||
auto unloadMedium() -> void;
|
||||
//game.cpp
|
||||
auto load() -> void;
|
||||
auto load(Emulator::Interface& interface) -> void;
|
||||
auto unload() -> void;
|
||||
|
||||
//state.cpp
|
||||
auto stateName(uint slot, bool managed = false) -> string;
|
||||
|
@ -47,8 +47,8 @@ struct Program : Emulator::Platform {
|
|||
|
||||
vector<Emulator::Interface*> emulators;
|
||||
|
||||
vector<string> mediumQueue; //for command-line and drag-and-drop loading
|
||||
vector<string> mediumPaths; //for keeping track of loaded folder locations
|
||||
vector<string> gameQueue; //for command-line and drag-and-drop loading
|
||||
vector<string> gamePaths; //for keeping track of loaded folder locations
|
||||
|
||||
time_t autoSaveTime = 0; //for automatically saving RAM periodically
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
auto Program::stateName(uint slot, bool managed) -> string {
|
||||
return {
|
||||
mediumPaths(1), "higan/states/",
|
||||
gamePaths(1), "higan/states/",
|
||||
managed ? "managed/" : "quick/",
|
||||
"slot-", slot, ".bst"
|
||||
};
|
||||
|
|
|
@ -63,8 +63,7 @@ auto Program::initializeInputDriver() -> void {
|
|||
}
|
||||
|
||||
auto Program::softReset() -> void {
|
||||
if(!emulator) return;
|
||||
if(!emulator->information.resettable) return;
|
||||
if(!emulator || !emulator->information().resettable) return;
|
||||
emulator->reset();
|
||||
showMessage("System has been soft reset");
|
||||
}
|
||||
|
|
|
@ -4,15 +4,13 @@ SystemProperties::SystemProperties() {
|
|||
layout.setPadding(5);
|
||||
systemLabel.setAlignment(1.0).setText("System:");
|
||||
for(auto& emulator : program->emulators) {
|
||||
systemOption.append(ComboButtonItem().setText(emulator->information.name));
|
||||
systemOption.append(ComboButtonItem().setText(emulator->information().name));
|
||||
}
|
||||
loadLabel.setAlignment(1.0).setText("Load:");
|
||||
loadBrowse.setText("Browse ...").onActivate([&] {
|
||||
string filters = "Games|";
|
||||
for(auto& emulator : program->emulators) {
|
||||
for(auto& media : emulator->media) {
|
||||
filters.append("*.", media.type, ":");
|
||||
}
|
||||
filters.append("*.", emulator->information().extension, ":");
|
||||
}
|
||||
filters.trimRight(":", 1L);
|
||||
if(auto location = BrowserDialog()
|
||||
|
@ -21,17 +19,13 @@ SystemProperties::SystemProperties() {
|
|||
.setFilters(filters)
|
||||
.openFolder()) {
|
||||
loadEdit.setText(location);
|
||||
//change system option to match the media selected
|
||||
auto suffix = Location::suffix(location).trimLeft(".", 1L);
|
||||
//change system option to match the game selected
|
||||
auto extension = Location::suffix(location).trimLeft(".", 1L);
|
||||
for(auto& emulator : program->emulators) {
|
||||
for(auto& media : emulator->media) {
|
||||
if(media.type == suffix) {
|
||||
for(auto item : systemOption.items()) {
|
||||
if(item.text() == emulator->information.name) {
|
||||
item.setSelected();
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto information = emulator->information();
|
||||
if(information.extension == extension) {
|
||||
for(auto item : systemOption.items()) {
|
||||
if(item.text() == information.name) return item.setSelected(), void();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ auto CheatEditor::addCode(const string& code, const string& description, bool en
|
|||
|
||||
auto CheatEditor::loadCheats() -> void {
|
||||
doReset(true);
|
||||
auto contents = string::read({program->mediumPaths(1), "higan/cheats.bml"});
|
||||
auto contents = string::read({program->gamePaths(1), "higan/cheats.bml"});
|
||||
auto document = BML::unserialize(contents);
|
||||
for(auto cheat : document["cartridge"].find("cheat")) {
|
||||
if(!addCode(cheat["code"].text(), cheat["description"].text(), (bool)cheat["enabled"])) break;
|
||||
|
@ -146,10 +146,10 @@ auto CheatEditor::saveCheats() -> void {
|
|||
count++;
|
||||
}
|
||||
if(count) {
|
||||
directory::create({program->mediumPaths(1), "higan/"});
|
||||
file::write({program->mediumPaths(1), "higan/cheats.bml"}, document);
|
||||
directory::create({program->gamePaths(1), "higan/"});
|
||||
file::write({program->gamePaths(1), "higan/cheats.bml"}, document);
|
||||
} else {
|
||||
file::remove({program->mediumPaths(1), "higan/cheats.bml"});
|
||||
file::remove({program->gamePaths(1), "higan/cheats.bml"});
|
||||
}
|
||||
doReset(true);
|
||||
}
|
||||
|
|
|
@ -7,16 +7,16 @@ GameNotes::GameNotes(TabFrame* parent) : TabFrameItem(parent) {
|
|||
}
|
||||
|
||||
auto GameNotes::loadNotes() -> void {
|
||||
auto contents = string::read({program->mediumPaths(1), "higan/notes.txt"});
|
||||
auto contents = string::read({program->gamePaths(1), "higan/notes.txt"});
|
||||
notes.setText(contents);
|
||||
}
|
||||
|
||||
auto GameNotes::saveNotes() -> void {
|
||||
auto contents = notes.text();
|
||||
if(contents) {
|
||||
directory::create({program->mediumPaths(1), "higan/"});
|
||||
file::write({program->mediumPaths(1), "higan/notes.txt"}, contents);
|
||||
directory::create({program->gamePaths(1), "higan/"});
|
||||
file::write({program->gamePaths(1), "higan/notes.txt"}, contents);
|
||||
} else {
|
||||
file::remove({program->mediumPaths(1), "higan/notes.txt"});
|
||||
file::remove({program->gamePaths(1), "higan/notes.txt"});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,10 @@ auto Video::setPalette() -> void {
|
|||
if(!interface) return;
|
||||
|
||||
delete palette;
|
||||
colors = interface->videoColors();
|
||||
colors = interface->display().colors;
|
||||
palette = new uint32[colors];
|
||||
for(auto index : range(colors)) {
|
||||
uint64 color = interface->videoColor(index);
|
||||
uint64 color = interface->color(index);
|
||||
uint16 b = color.bits( 0,15);
|
||||
uint16 g = color.bits(16,31);
|
||||
uint16 r = color.bits(32,47);
|
||||
|
|
|
@ -82,6 +82,10 @@ auto pApplication::quit() -> void {
|
|||
}
|
||||
}
|
||||
|
||||
auto pApplication::setScreenSaver(bool screenSaver) -> void {
|
||||
//TODO: not implemented
|
||||
}
|
||||
|
||||
auto pApplication::initialize() -> void {
|
||||
@autoreleasepool {
|
||||
[NSApplication sharedApplication];
|
||||
|
|
|
@ -15,6 +15,7 @@ struct pApplication {
|
|||
static auto pendingEvents() -> bool;
|
||||
static auto processEvents() -> void;
|
||||
static auto quit() -> void;
|
||||
static auto setScreenSaver(bool screenSaver) -> void;
|
||||
|
||||
static auto initialize() -> void;
|
||||
};
|
||||
|
|
|
@ -51,6 +51,10 @@ auto Application::scale(float value) -> float {
|
|||
return value * state.scale;
|
||||
}
|
||||
|
||||
auto Application::screenSaver() -> bool {
|
||||
return state.screenSaver;
|
||||
}
|
||||
|
||||
auto Application::setFont(const Font& font) -> void {
|
||||
state.font = font;
|
||||
}
|
||||
|
@ -63,6 +67,11 @@ auto Application::setScale(float scale) -> void {
|
|||
state.scale = scale;
|
||||
}
|
||||
|
||||
auto Application::setScreenSaver(bool screenSaver) -> void {
|
||||
state.screenSaver = screenSaver;
|
||||
pApplication::setScreenSaver(screenSaver);
|
||||
}
|
||||
|
||||
auto Application::unscale(float value) -> float {
|
||||
return value * (1.0 / state.scale);
|
||||
}
|
||||
|
@ -74,19 +83,10 @@ auto Application::Windows::doModalChange(bool modal) -> void {
|
|||
if(state.windows.onModalChange) return state.windows.onModalChange(modal);
|
||||
}
|
||||
|
||||
auto Application::Windows::doScreenSaver() -> bool {
|
||||
if(state.windows.onScreenSaver) return state.windows.onScreenSaver();
|
||||
return true; //true = allow screen saver (default); false = suppress screen saver
|
||||
}
|
||||
|
||||
auto Application::Windows::onModalChange(const function<void (bool)>& callback) -> void {
|
||||
state.windows.onModalChange = callback;
|
||||
}
|
||||
|
||||
auto Application::Windows::onScreenSaver(const function<bool ()>& callback) -> void {
|
||||
state.windows.onScreenSaver = callback;
|
||||
}
|
||||
|
||||
//Cocoa
|
||||
//=====
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#if defined(Hiro_Application)
|
||||
struct Application {
|
||||
Application() = delete;
|
||||
|
||||
static auto doMain() -> void;
|
||||
static auto font() -> Font;
|
||||
static auto locale() -> Locale&;
|
||||
static auto modal() -> bool;
|
||||
static auto name() -> string;
|
||||
static auto onMain(const function<void ()>& callback = {}) -> void;
|
||||
static auto run() -> void;
|
||||
static auto scale() -> float;
|
||||
static auto scale(float value) -> float;
|
||||
static auto pendingEvents() -> bool;
|
||||
static auto processEvents() -> void;
|
||||
static auto quit() -> void;
|
||||
static auto screenSaver() -> bool;
|
||||
static auto setFont(const Font& font = {}) -> void;
|
||||
static auto setName(const string& name = "") -> void;
|
||||
static auto setScale(float scale = 1.0) -> void;
|
||||
static auto setScreenSaver(bool screenSaver = true) -> void;
|
||||
static auto unscale(float value) -> float;
|
||||
|
||||
struct Windows {
|
||||
static auto doModalChange(bool modal) -> void;
|
||||
static auto onModalChange(const function<void (bool)>& callback = {}) -> void;
|
||||
};
|
||||
|
||||
struct Cocoa {
|
||||
static auto doAbout() -> void;
|
||||
static auto doActivate() -> void;
|
||||
static auto doPreferences() -> void;
|
||||
static auto doQuit() -> void;
|
||||
static auto onAbout(const function<void ()>& callback = {}) -> void;
|
||||
static auto onActivate(const function<void ()>& callback = {}) -> void;
|
||||
static auto onPreferences(const function<void ()>& callback = {}) -> void;
|
||||
static auto onQuit(const function<void ()>& callback = {}) -> void;
|
||||
};
|
||||
|
||||
struct Namespace : Locale::Namespace {
|
||||
Namespace(const string& value) : Locale::Namespace(Application::locale(), value) {}
|
||||
};
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
Font font;
|
||||
Locale locale;
|
||||
int modal = 0;
|
||||
string name;
|
||||
function<void ()> onMain;
|
||||
bool quit = false;
|
||||
float scale = 1.0;
|
||||
bool screenSaver = true;
|
||||
|
||||
struct Windows {
|
||||
function<void (bool)> onModalChange;
|
||||
function<bool ()> onScreenSaver;
|
||||
} windows;
|
||||
|
||||
struct Cocoa {
|
||||
function<void ()> onAbout;
|
||||
function<void ()> onActivate;
|
||||
function<void ()> onPreferences;
|
||||
function<void ()> onQuit;
|
||||
} cocoa;
|
||||
};
|
||||
static State state;
|
||||
static auto initialize() -> void;
|
||||
};
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
#include <nall/maybe.hpp>
|
||||
#include <nall/path.hpp>
|
||||
#include <nall/range.hpp>
|
||||
#include <nall/run.hpp>
|
||||
#include <nall/set.hpp>
|
||||
#include <nall/shared-pointer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
|
@ -369,84 +370,8 @@ struct Hotkey {
|
|||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Application)
|
||||
struct Application {
|
||||
Application() = delete;
|
||||
|
||||
static auto doMain() -> void;
|
||||
static auto font() -> Font;
|
||||
static auto locale() -> Locale&;
|
||||
static auto modal() -> bool;
|
||||
static auto name() -> string;
|
||||
static auto onMain(const function<void ()>& callback = {}) -> void;
|
||||
static auto run() -> void;
|
||||
static auto scale() -> float;
|
||||
static auto scale(float value) -> float;
|
||||
static auto pendingEvents() -> bool;
|
||||
static auto processEvents() -> void;
|
||||
static auto quit() -> void;
|
||||
static auto setFont(const Font& font = {}) -> void;
|
||||
static auto setName(const string& name = "") -> void;
|
||||
static auto setScale(float scale = 1.0) -> void;
|
||||
static auto unscale(float value) -> float;
|
||||
|
||||
struct Windows {
|
||||
static auto doModalChange(bool modal) -> void;
|
||||
static auto doScreenSaver() -> bool;
|
||||
static auto onModalChange(const function<void (bool)>& callback = {}) -> void;
|
||||
static auto onScreenSaver(const function<bool ()>& callback = {}) -> void;
|
||||
};
|
||||
|
||||
struct Cocoa {
|
||||
static auto doAbout() -> void;
|
||||
static auto doActivate() -> void;
|
||||
static auto doPreferences() -> void;
|
||||
static auto doQuit() -> void;
|
||||
static auto onAbout(const function<void ()>& callback = {}) -> void;
|
||||
static auto onActivate(const function<void ()>& callback = {}) -> void;
|
||||
static auto onPreferences(const function<void ()>& callback = {}) -> void;
|
||||
static auto onQuit(const function<void ()>& callback = {}) -> void;
|
||||
};
|
||||
|
||||
struct Namespace : Locale::Namespace {
|
||||
Namespace(const string& value) : Locale::Namespace(Application::locale(), value) {}
|
||||
};
|
||||
|
||||
//private:
|
||||
struct State {
|
||||
Font font;
|
||||
Locale locale;
|
||||
int modal = 0;
|
||||
string name;
|
||||
function<void ()> onMain;
|
||||
bool quit = false;
|
||||
float scale = 1.0;
|
||||
|
||||
struct Windows {
|
||||
function<void (bool)> onModalChange;
|
||||
function<bool ()> onScreenSaver;
|
||||
} windows;
|
||||
|
||||
struct Cocoa {
|
||||
function<void ()> onAbout;
|
||||
function<void ()> onActivate;
|
||||
function<void ()> onPreferences;
|
||||
function<void ()> onQuit;
|
||||
} cocoa;
|
||||
};
|
||||
static State state;
|
||||
static auto initialize() -> void;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(Hiro_Desktop)
|
||||
struct Desktop {
|
||||
Desktop() = delete;
|
||||
|
||||
static auto size() -> Size;
|
||||
static auto workspace() -> Geometry;
|
||||
};
|
||||
#endif
|
||||
#include "application.hpp"
|
||||
#include "desktop.hpp"
|
||||
|
||||
#if defined(Hiro_Monitor)
|
||||
struct Monitor {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#if defined(Hiro_Desktop)
|
||||
struct Desktop {
|
||||
Desktop() = delete;
|
||||
|
||||
static auto size() -> Size;
|
||||
static auto workspace() -> Geometry;
|
||||
};
|
||||
#endif
|
|
@ -6,6 +6,7 @@ vector<pWindow*> pApplication::windows;
|
|||
|
||||
#if defined(DISPLAY_XORG)
|
||||
XlibDisplay* pApplication::display = nullptr;
|
||||
bool pApplication::xdgScreenSaver = false;
|
||||
#endif
|
||||
|
||||
auto pApplication::run() -> void {
|
||||
|
@ -29,16 +30,21 @@ auto pApplication::quit() -> void {
|
|||
if(gtk_main_level()) gtk_main_quit();
|
||||
|
||||
#if defined(DISPLAY_XORG)
|
||||
//TODO: Keyboard::poll() is being called after Application::quit();
|
||||
//so if display is closed; this causes a segfault
|
||||
//XCloseDisplay(display);
|
||||
//display = nullptr;
|
||||
XCloseDisplay(display);
|
||||
display = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
auto pApplication::setScreenSaver(bool screenSaver) -> void {
|
||||
#if defined(DISPLAY_XORG)
|
||||
for(auto& window : windows) window->_setScreenSaver(screenSaver);
|
||||
#endif
|
||||
}
|
||||
|
||||
auto pApplication::initialize() -> void {
|
||||
#if defined(DISPLAY_XORG)
|
||||
display = XOpenDisplay(nullptr);
|
||||
xdgScreenSaver = (bool)execute("xdg-screensaver", "--version").output.find("xdg-screensaver");
|
||||
#endif
|
||||
|
||||
//set WM_CLASS to Application::name()
|
||||
|
|
|
@ -7,6 +7,7 @@ struct pApplication {
|
|||
static auto pendingEvents() -> bool;
|
||||
static auto processEvents() -> void;
|
||||
static auto quit() -> void;
|
||||
static auto setScreenSaver(bool screenSaver) -> void;
|
||||
|
||||
static auto initialize() -> void;
|
||||
|
||||
|
@ -14,6 +15,7 @@ struct pApplication {
|
|||
|
||||
#if defined(DISPLAY_XORG)
|
||||
static XlibDisplay* display;
|
||||
static bool xdgScreenSaver;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
namespace hiro {
|
||||
|
||||
auto pKeyboard::poll() -> vector<bool> {
|
||||
if(Application::state.quit) return {};
|
||||
|
||||
vector<bool> result;
|
||||
char state[256];
|
||||
#if defined(DISPLAY_XORG)
|
||||
|
|
|
@ -79,14 +79,16 @@ auto pViewport::destruct() -> void {
|
|||
gtkParent = nullptr;
|
||||
}
|
||||
|
||||
auto pViewport::handle() const -> uintptr_t {
|
||||
auto pViewport::handle() const -> uintptr {
|
||||
#if defined(DISPLAY_WINDOWS)
|
||||
return (uintptr_t)GDK_WINDOW_HWND(gtk_widget_get_window(gtkWidget));
|
||||
return (uintptr)GDK_WINDOW_HWND(gtk_widget_get_window(gtkWidget));
|
||||
#endif
|
||||
|
||||
#if defined(DISPLAY_XORG)
|
||||
return GDK_WINDOW_XID(gtk_widget_get_window(gtkWidget));
|
||||
#endif
|
||||
|
||||
return (uintptr)nullptr;
|
||||
}
|
||||
|
||||
auto pViewport::setDroppable(bool droppable) -> void {
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace hiro {
|
|||
struct pViewport : pWidget {
|
||||
Declare(Viewport, Widget)
|
||||
|
||||
auto handle() const -> uintptr_t;
|
||||
auto handle() const -> uintptr;
|
||||
auto setDroppable(bool droppable) -> void;
|
||||
};
|
||||
|
||||
|
|
|
@ -99,6 +99,10 @@ static auto Window_keyRelease(GtkWidget* widget, GdkEventKey* event, pWindow* p)
|
|||
return false;
|
||||
}
|
||||
|
||||
static auto Window_realize(GtkWidget* widget, pWindow* p) -> void {
|
||||
p->_setScreenSaver(Application::screenSaver());
|
||||
}
|
||||
|
||||
static auto Window_sizeAllocate(GtkWidget* widget, GtkAllocation* allocation, pWindow* p) -> void {
|
||||
p->_synchronizeState();
|
||||
p->_synchronizeGeometry();
|
||||
|
@ -125,6 +129,10 @@ static auto Window_stateEvent(GtkWidget* widget, GdkEvent* event, pWindow* p) ->
|
|||
}
|
||||
}
|
||||
|
||||
static auto Window_unrealize(GtkWidget* widget, pWindow* p) -> void {
|
||||
p->_setScreenSaver(true);
|
||||
}
|
||||
|
||||
auto pWindow::construct() -> void {
|
||||
widget = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_resizable(GTK_WINDOW(widget), true);
|
||||
|
@ -186,6 +194,7 @@ auto pWindow::construct() -> void {
|
|||
g_signal_connect(G_OBJECT(widget), "drag-data-received", G_CALLBACK(Window_drop), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(widget), "key-press-event", G_CALLBACK(Window_keyPress), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(widget), "key-release-event", G_CALLBACK(Window_keyRelease), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(widget), "realize", G_CALLBACK(Window_realize), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(formContainer), "size-allocate", G_CALLBACK(Window_sizeAllocate), (gpointer)this);
|
||||
#if HIRO_GTK==2
|
||||
g_signal_connect(G_OBJECT(formContainer), "size-request", G_CALLBACK(Window_sizeRequest), (gpointer)this);
|
||||
|
@ -194,6 +203,7 @@ auto pWindow::construct() -> void {
|
|||
widgetClass->get_preferred_width = Window_getPreferredWidth;
|
||||
widgetClass->get_preferred_height = Window_getPreferredHeight;
|
||||
#endif
|
||||
g_signal_connect(G_OBJECT(widget), "unrealize", G_CALLBACK(Window_unrealize), (gpointer)this);
|
||||
g_signal_connect(G_OBJECT(widget), "window-state-event", G_CALLBACK(Window_stateEvent), (gpointer)this);
|
||||
|
||||
g_object_set_data(G_OBJECT(widget), "hiro::window", (gpointer)this);
|
||||
|
@ -247,6 +257,18 @@ auto pWindow::frameMargin() const -> Geometry {
|
|||
};
|
||||
}
|
||||
|
||||
auto pWindow::handle() const -> uintptr {
|
||||
#if defined(DISPLAY_WINDOWS)
|
||||
return (uintptr)GDK_WINDOW_HWND(gtk_widget_get_window(widget));
|
||||
#endif
|
||||
|
||||
#if defined(DISPLAY_XORG)
|
||||
return GDK_WINDOW_XID(gtk_widget_get_window(widget));
|
||||
#endif
|
||||
|
||||
return (uintptr)nullptr;
|
||||
}
|
||||
|
||||
auto pWindow::remove(sMenuBar menuBar) -> void {
|
||||
_setMenuVisible(false);
|
||||
}
|
||||
|
@ -458,6 +480,19 @@ auto pWindow::_setMenuVisible(bool visible) -> void {
|
|||
gtk_widget_set_visible(gtkMenu, visible);
|
||||
}
|
||||
|
||||
auto pWindow::_setScreenSaver(bool screenSaver) -> void {
|
||||
if(!gtk_widget_get_realized(widget)) return;
|
||||
|
||||
#if defined(DISPLAY_XORG)
|
||||
if(pApplication::xdgScreenSaver) {
|
||||
if(this->screenSaver != screenSaver) {
|
||||
this->screenSaver = screenSaver;
|
||||
execute("xdg-screensaver", screenSaver ? "resume" : "suspend", string{"0x", hex(handle())});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
auto pWindow::_setStatusEnabled(bool enabled) -> void {
|
||||
gtk_widget_set_sensitive(gtkStatus, enabled);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ struct pWindow : pObject {
|
|||
auto append(sStatusBar statusBar) -> void;
|
||||
auto focused() const -> bool override;
|
||||
auto frameMargin() const -> Geometry;
|
||||
auto handle() const -> uintptr;
|
||||
auto remove(sMenuBar menuBar) -> void;
|
||||
auto remove(sSizable sizable) -> void;
|
||||
auto remove(sStatusBar statusBar) -> void;
|
||||
|
@ -33,6 +34,7 @@ struct pWindow : pObject {
|
|||
auto _append(mMenu& menu) -> void;
|
||||
auto _menuHeight() const -> int;
|
||||
auto _menuTextHeight() const -> int;
|
||||
auto _setScreenSaver(bool screenSaver) -> void;
|
||||
auto _setIcon(const string& basename) -> bool;
|
||||
auto _setMenuEnabled(bool enabled) -> void;
|
||||
auto _setMenuFont(const Font& font) -> void;
|
||||
|
@ -55,6 +57,7 @@ struct pWindow : pObject {
|
|||
GtkWidget* gtkStatus = nullptr;
|
||||
GtkAllocation lastMove = {0};
|
||||
GtkAllocation lastSize = {0};
|
||||
bool screenSaver = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ auto pApplication::quit() -> void {
|
|||
qtApplication = nullptr; //note: deleting QApplication will crash libQtGui
|
||||
}
|
||||
|
||||
auto pApplication::setScreenSaver(bool screenSaver) -> void {
|
||||
//TODO: not implemented
|
||||
}
|
||||
|
||||
//this is sadly necessary for things like determining window frame geometry
|
||||
//obviously, it is used as sparingly as possible
|
||||
auto pApplication::syncX() -> void {
|
||||
|
|
|
@ -7,6 +7,7 @@ struct pApplication {
|
|||
static auto pendingEvents() -> bool;
|
||||
static auto processEvents() -> void;
|
||||
static auto quit() -> void;
|
||||
static auto setScreenSaver(bool screenSaver) -> void;
|
||||
|
||||
static auto initialize() -> void;
|
||||
static auto syncX() -> void;
|
||||
|
|
|
@ -54,6 +54,9 @@ auto pApplication::quit() -> void {
|
|||
PostQuitMessage(0);
|
||||
}
|
||||
|
||||
auto pApplication::setScreenSaver(bool screenSaver) -> void {
|
||||
}
|
||||
|
||||
auto pApplication::initialize() -> void {
|
||||
CoInitialize(0);
|
||||
InitCommonControls();
|
||||
|
@ -262,7 +265,7 @@ static auto CALLBACK Application_windowProc(HWND hwnd, UINT msg, WPARAM wparam,
|
|||
case WM_EXITMENULOOP: case WM_EXITSIZEMOVE: pWindow->onModalEnd(); return false;
|
||||
case WM_SYSCOMMAND:
|
||||
if(wparam == SC_SCREENSAVE || wparam == SC_MONITORPOWER) {
|
||||
if(!Application::Windows::doScreenSaver()) return 0;
|
||||
if(!Application::screenSaver()) return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ struct pApplication {
|
|||
static auto pendingEvents() -> bool;
|
||||
static auto processEvents() -> void;
|
||||
static auto quit() -> void;
|
||||
static auto setScreenSaver(bool screenSaver) -> void;
|
||||
|
||||
static auto initialize() -> void;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue