mirror of https://github.com/bsnes-emu/bsnes.git
Update to v082r16 release.
byuu says: Binary output is once again called bsnes. No versioning on the title without a system cartridge loaded. Still saving config files to .config/batch for now. Finally fixed NES APU frame IRQ clearing on $4015 reads. Added mouse button/axis binding through buttons on the input capture window. Added advanced settings window with driver selection and focus policy settings. Will show your default driver properly if none are selected now, unlike old bsnes. That exposed a small bug where phoenix isn't removing widgets on Layout::remove, worked around it for now by hiding the panels. Damn, sick of working on phoenix. Added all missing input controllers, which can all now be mapped, and bound them to the main menu, and added NES support for selecting "no connected controller." Added mouse capture and the requisite tools menu option for it. Added WindowManager class that keeps track of both position and size now (eg full geometry), so now you can resize your windows and save the settings, unlike old bsnes. WindowManager has more stringent geometry checks. The *client area* (not the window border) can't be below 0,0 or above the width/height of three 30" monitors. If you have 4+ 30" monitors, then fuck you :P settings.cfg is now also saved, captures all currently available settings. Right now, there's only one path for the file browser to remember. I will probably make this per-system later. FileBrowser has been made a bit more friendly. The bottom left tells you what type of files the list is filtered by (so you see "*.sfc" for SNES), and the bottom right has an open button that can enter folders or load files. Added video shader support. Fixed nall/dsp variadic-channel support, was only outputting the left channel.
This commit is contained in:
parent
382ae1e61e
commit
5c2d16828c
|
@ -89,7 +89,7 @@ void DSP::read(signed channel[]) {
|
||||||
adjustBalance();
|
adjustBalance();
|
||||||
|
|
||||||
for(unsigned c = 0; c < settings.channels; c++) {
|
for(unsigned c = 0; c < settings.channels; c++) {
|
||||||
channel[c] = clamp(settings.precision, output.read(0) * settings.intensity);
|
channel[c] = clamp(settings.precision, output.read(c) * settings.intensity);
|
||||||
}
|
}
|
||||||
output.rdoffset++;
|
output.rdoffset++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
nes_objects := nes-interface nes-system nes-scheduler
|
nes_objects := nes-interface nes-system nes-scheduler nes-input
|
||||||
nes_objects += nes-mapper nes-cartridge nes-memory
|
nes_objects += nes-mapper nes-cartridge nes-memory
|
||||||
nes_objects += nes-cpu nes-apu nes-ppu
|
nes_objects += nes-cpu nes-apu nes-ppu
|
||||||
nes_objects += nes-cheat
|
nes_objects += nes-cheat
|
||||||
|
@ -7,6 +7,7 @@ objects += $(nes_objects)
|
||||||
obj/nes-interface.o: $(nes)/interface/interface.cpp $(call rwildcard,$(nes)/interface/)
|
obj/nes-interface.o: $(nes)/interface/interface.cpp $(call rwildcard,$(nes)/interface/)
|
||||||
obj/nes-system.o: $(nes)/system/system.cpp $(call rwildcard,$(nes)/system/)
|
obj/nes-system.o: $(nes)/system/system.cpp $(call rwildcard,$(nes)/system/)
|
||||||
obj/nes-scheduler.o: $(nes)/scheduler/scheduler.cpp $(call rwildcard,$(nes)/scheduler/)
|
obj/nes-scheduler.o: $(nes)/scheduler/scheduler.cpp $(call rwildcard,$(nes)/scheduler/)
|
||||||
|
obj/nes-input.o: $(nes)/input/input.cpp $(call rwildcard,$(nes)/input/)
|
||||||
obj/nes-mapper.o: $(nes)/mapper/mapper.cpp $(call rwildcard,$(nes)/mapper/)
|
obj/nes-mapper.o: $(nes)/mapper/mapper.cpp $(call rwildcard,$(nes)/mapper/)
|
||||||
obj/nes-cartridge.o: $(nes)/cartridge/cartridge.cpp $(call rwildcard,$(nes)/cartridge/)
|
obj/nes-cartridge.o: $(nes)/cartridge/cartridge.cpp $(call rwildcard,$(nes)/cartridge/)
|
||||||
obj/nes-memory.o: $(nes)/memory/memory.cpp $(call rwildcard,$(nes)/memory/)
|
obj/nes-memory.o: $(nes)/memory/memory.cpp $(call rwildcard,$(nes)/memory/)
|
||||||
|
|
|
@ -139,7 +139,7 @@ void APU::reset() {
|
||||||
frame.divider = 1;
|
frame.divider = 1;
|
||||||
|
|
||||||
enabled_channels = 0;
|
enabled_channels = 0;
|
||||||
//cpu.set_alu_irq_line(frame.irq_pending || dmc.irq_pending);
|
set_irq_line();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8 APU::read(uint16 addr) {
|
uint8 APU::read(uint16 addr) {
|
||||||
|
@ -152,6 +152,10 @@ uint8 APU::read(uint16 addr) {
|
||||||
result |= dmc.length_counter ? 0x10 : 0;
|
result |= dmc.length_counter ? 0x10 : 0;
|
||||||
result |= frame.irq_pending ? 0x40 : 0;
|
result |= frame.irq_pending ? 0x40 : 0;
|
||||||
result |= dmc.irq_pending ? 0x80 : 0;
|
result |= dmc.irq_pending ? 0x80 : 0;
|
||||||
|
|
||||||
|
frame.irq_pending = false;
|
||||||
|
set_irq_line();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,13 +105,15 @@ void CPU::ram_write(uint16 addr, uint8 data) {
|
||||||
|
|
||||||
uint8 CPU::read(uint16 addr) {
|
uint8 CPU::read(uint16 addr) {
|
||||||
if(addr == 0x4016) {
|
if(addr == 0x4016) {
|
||||||
if(status.controller_port0 >= 8) return (mdr() & 0xc0) | 1;
|
return (mdr() & 0xc0) | input.data(0);
|
||||||
return interface->inputPoll(0, 0u, status.controller_port0++);
|
// if(status.controller_port0 >= 8) return (mdr() & 0xc0) | 1;
|
||||||
|
// return interface->inputPoll(0, 0u, status.controller_port0++);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(addr == 0x4017) {
|
if(addr == 0x4017) {
|
||||||
if(status.controller_port1 >= 8) return (mdr() & 0xc0) | 1;
|
return (mdr() & 0xc0) | input.data(1);
|
||||||
return interface->inputPoll(1, 0u, status.controller_port1++);
|
// if(status.controller_port1 >= 8) return (mdr() & 0xc0) | 1;
|
||||||
|
// return interface->inputPoll(1, 0u, status.controller_port1++);
|
||||||
}
|
}
|
||||||
|
|
||||||
return apu.read(addr);
|
return apu.read(addr);
|
||||||
|
@ -124,11 +126,12 @@ void CPU::write(uint16 addr, uint8 data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(addr == 0x4016) {
|
if(addr == 0x4016) {
|
||||||
status.controller_latch = data & 0x01;
|
input.latch(data & 0x01);
|
||||||
if(status.controller_latch) {
|
// status.controller_latch = data & 0x01;
|
||||||
status.controller_port0 = 0;
|
// if(status.controller_latch) {
|
||||||
status.controller_port1 = 0;
|
// status.controller_port0 = 0;
|
||||||
}
|
// status.controller_port1 = 0;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return apu.write(addr, data);
|
return apu.write(addr, data);
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
#include <nes/nes.hpp>
|
||||||
|
|
||||||
|
namespace NES {
|
||||||
|
|
||||||
|
Input input;
|
||||||
|
|
||||||
|
void Input::latch(bool data) {
|
||||||
|
latchdata = data;
|
||||||
|
|
||||||
|
if(latchdata == 1) {
|
||||||
|
counter1 = 0;
|
||||||
|
counter2 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Input::data(bool port) {
|
||||||
|
bool result = 0;
|
||||||
|
|
||||||
|
if(port == 0) {
|
||||||
|
if(port1 == Device::Joypad) {
|
||||||
|
if(counter1 >= 8) return 1;
|
||||||
|
result = interface->inputPoll(0, 0u, counter1);
|
||||||
|
if(latchdata == 0) counter1++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == 1) {
|
||||||
|
if(port2 == Device::Joypad) {
|
||||||
|
if(counter2 >= 8) return 1;
|
||||||
|
result = interface->inputPoll(1, 0u, counter2);
|
||||||
|
if(latchdata == 0) counter2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::connect(bool port, Device device) {
|
||||||
|
if(port == 0) port1 = device, counter1 = 0;
|
||||||
|
if(port == 1) port2 = device, counter2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::power() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Input::reset() {
|
||||||
|
latchdata = 0;
|
||||||
|
counter1 = 0;
|
||||||
|
counter2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
struct Input {
|
||||||
|
enum class Device : unsigned {
|
||||||
|
None,
|
||||||
|
Joypad,
|
||||||
|
};
|
||||||
|
|
||||||
|
void latch(bool data);
|
||||||
|
bool data(bool port);
|
||||||
|
void connect(bool port, Device device);
|
||||||
|
|
||||||
|
void power();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Device port1;
|
||||||
|
Device port2;
|
||||||
|
|
||||||
|
bool latchdata;
|
||||||
|
unsigned counter1;
|
||||||
|
unsigned counter2;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Input input;
|
|
@ -19,6 +19,10 @@ void Interface::initialize(Interface *derived_interface) {
|
||||||
system.init();
|
system.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Interface::connect(bool port, Input::Device device) {
|
||||||
|
input.connect(port, device);
|
||||||
|
}
|
||||||
|
|
||||||
bool Interface::cartridgeLoaded() {
|
bool Interface::cartridgeLoaded() {
|
||||||
return cartridge.loaded();
|
return cartridge.loaded();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ struct Interface {
|
||||||
virtual void audioSample(int16_t sample);
|
virtual void audioSample(int16_t sample);
|
||||||
virtual int16_t inputPoll(bool port, unsigned device, unsigned id);
|
virtual int16_t inputPoll(bool port, unsigned device, unsigned id);
|
||||||
|
|
||||||
|
virtual void connect(bool port, Input::Device device);
|
||||||
|
|
||||||
virtual void initialize(Interface*);
|
virtual void initialize(Interface*);
|
||||||
|
|
||||||
virtual bool cartridgeLoaded();
|
virtual bool cartridgeLoaded();
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
namespace NES {
|
namespace NES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bnes";
|
static const char Name[] = "bnes";
|
||||||
static const char Version[] = "000.11";
|
static const char Version[] = "000.12";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +98,9 @@ namespace NES {
|
||||||
inline Processor() : thread(0) {}
|
inline Processor() : thread(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#include <nes/interface/interface.hpp>
|
|
||||||
#include <nes/system/system.hpp>
|
#include <nes/system/system.hpp>
|
||||||
#include <nes/scheduler/scheduler.hpp>
|
#include <nes/scheduler/scheduler.hpp>
|
||||||
|
#include <nes/input/input.hpp>
|
||||||
#include <nes/mapper/mapper.hpp>
|
#include <nes/mapper/mapper.hpp>
|
||||||
#include <nes/cartridge/cartridge.hpp>
|
#include <nes/cartridge/cartridge.hpp>
|
||||||
#include <nes/memory/memory.hpp>
|
#include <nes/memory/memory.hpp>
|
||||||
|
@ -108,6 +108,7 @@ namespace NES {
|
||||||
#include <nes/apu/apu.hpp>
|
#include <nes/apu/apu.hpp>
|
||||||
#include <nes/ppu/ppu.hpp>
|
#include <nes/ppu/ppu.hpp>
|
||||||
#include <nes/cheat/cheat.hpp>
|
#include <nes/cheat/cheat.hpp>
|
||||||
|
#include <nes/interface/interface.hpp>
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,6 +13,7 @@ void System::power() {
|
||||||
cpu.power();
|
cpu.power();
|
||||||
apu.power();
|
apu.power();
|
||||||
ppu.power();
|
ppu.power();
|
||||||
|
input.reset();
|
||||||
scheduler.power();
|
scheduler.power();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,11 +22,14 @@ void System::reset() {
|
||||||
cpu.reset();
|
cpu.reset();
|
||||||
apu.reset();
|
apu.reset();
|
||||||
ppu.reset();
|
ppu.reset();
|
||||||
|
input.reset();
|
||||||
scheduler.reset();
|
scheduler.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::init() {
|
void System::init() {
|
||||||
assert(interface != 0);
|
assert(interface != 0);
|
||||||
|
input.connect(0, Input::Device::Joypad);
|
||||||
|
input.connect(1, Input::Device::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::term() {
|
void System::term() {
|
||||||
|
|
|
@ -184,6 +184,10 @@ bool Window::focused() {
|
||||||
return p.focused();
|
return p.focused();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Window::fullScreen() {
|
||||||
|
return state.fullScreen;
|
||||||
|
}
|
||||||
|
|
||||||
Geometry Window::geometry() {
|
Geometry Window::geometry() {
|
||||||
return p.geometry();
|
return p.geometry();
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,6 +133,7 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
|
||||||
Geometry frameGeometry();
|
Geometry frameGeometry();
|
||||||
Geometry frameMargin();
|
Geometry frameMargin();
|
||||||
bool focused();
|
bool focused();
|
||||||
|
bool fullScreen();
|
||||||
Geometry geometry();
|
Geometry geometry();
|
||||||
void ignore();
|
void ignore();
|
||||||
void remove(Layout &layout);
|
void remove(Layout &layout);
|
||||||
|
|
|
@ -19,6 +19,10 @@ void Interface::initialize(Interface *derived_interface) {
|
||||||
system.init();
|
system.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Interface::connect(bool port, Input::Device device) {
|
||||||
|
input.connect(port, device);
|
||||||
|
}
|
||||||
|
|
||||||
bool Interface::cartridgeLoaded() {
|
bool Interface::cartridgeLoaded() {
|
||||||
return cartridge.loaded();
|
return cartridge.loaded();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,8 @@ public:
|
||||||
|
|
||||||
virtual void initialize(Interface*);
|
virtual void initialize(Interface*);
|
||||||
|
|
||||||
|
virtual void connect(bool port, Input::Device device);
|
||||||
|
|
||||||
virtual bool cartridgeLoaded();
|
virtual bool cartridgeLoaded();
|
||||||
virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size);
|
virtual void loadCartridge(const string &xml, const uint8_t *data, unsigned size);
|
||||||
virtual void unloadCartridge();
|
virtual void unloadCartridge();
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
namespace SNES {
|
namespace SNES {
|
||||||
namespace Info {
|
namespace Info {
|
||||||
static const char Name[] = "bsnes";
|
static const char Name[] = "bsnes";
|
||||||
static const char Version[] = "082.15";
|
static const char Version[] = "082.16";
|
||||||
static const unsigned SerializerVersion = 22;
|
static const unsigned SerializerVersion = 22;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
include $(nes)/Makefile
|
include $(nes)/Makefile
|
||||||
include $(snes)/Makefile
|
include $(snes)/Makefile
|
||||||
include $(gameboy)/Makefile
|
include $(gameboy)/Makefile
|
||||||
name := batch
|
name := bsnes
|
||||||
|
|
||||||
ui_objects := ui-main ui-config ui-interface ui-input ui-utility
|
ui_objects := ui-main ui-config ui-interface ui-input ui-utility
|
||||||
ui_objects += ui-general ui-settings ui-tools
|
ui_objects += ui-window ui-general ui-settings ui-tools
|
||||||
ui_objects += phoenix ruby
|
ui_objects += phoenix ruby
|
||||||
ui_objects += $(if $(call streq,$(platform),win),resource)
|
ui_objects += $(if $(call streq,$(platform),win),resource)
|
||||||
|
|
||||||
|
@ -72,6 +72,7 @@ obj/ui-config.o: $(ui)/config/config.cpp $(call rwildcard,$(ui)/)
|
||||||
obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/)
|
obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/)
|
||||||
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/)
|
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/)
|
||||||
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/)
|
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/)
|
||||||
|
obj/ui-window.o: $(ui)/window/window.cpp $(call rwildcard,$(ui)/)
|
||||||
obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/)
|
obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/)
|
||||||
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/)
|
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/)
|
||||||
obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/)
|
obj/ui-tools.o: $(ui)/tools/tools.cpp $(call rwildcard,$(ui)/)
|
||||||
|
|
|
@ -23,12 +23,14 @@ using namespace ruby;
|
||||||
#include "interface/interface.hpp"
|
#include "interface/interface.hpp"
|
||||||
#include "input/input.hpp"
|
#include "input/input.hpp"
|
||||||
#include "utility/utility.hpp"
|
#include "utility/utility.hpp"
|
||||||
|
#include "window/window.hpp"
|
||||||
#include "general/general.hpp"
|
#include "general/general.hpp"
|
||||||
#include "settings/settings.hpp"
|
#include "settings/settings.hpp"
|
||||||
#include "tools/tools.hpp"
|
#include "tools/tools.hpp"
|
||||||
|
|
||||||
struct Application {
|
struct Application {
|
||||||
bool quit;
|
bool quit;
|
||||||
|
bool autopause;
|
||||||
|
|
||||||
string realpath;
|
string realpath;
|
||||||
string userpath;
|
string userpath;
|
||||||
|
|
|
@ -2,7 +2,30 @@
|
||||||
Config *config = 0;
|
Config *config = 0;
|
||||||
|
|
||||||
Config::Config() {
|
Config::Config() {
|
||||||
|
attach(video.driver = "", "Video::Driver");
|
||||||
|
attach(video.shader = "", "Video::Shader");
|
||||||
|
attach(video.synchronize = true, "Video::Synchronize");
|
||||||
|
attach(video.smooth = false, "Video::Smooth");
|
||||||
|
|
||||||
|
attach(audio.driver = "", "Audio::Driver");
|
||||||
|
attach(audio.synchronize = true, "Audio::Synchronize");
|
||||||
|
attach(audio.mute = false, "Audio::Mute");
|
||||||
|
|
||||||
|
attach(input.driver = "", "Input::Driver");
|
||||||
|
attach(input.focusPolicy = 1, "Input::FocusPolicy");
|
||||||
|
|
||||||
|
attach(path.last = application->realpath, "Path::Recent");
|
||||||
|
|
||||||
|
attach(nes.controllerPort1Device = 1, "NES::Controller::Port1");
|
||||||
|
attach(nes.controllerPort2Device = 0, "NES::Controller::Port2");
|
||||||
|
|
||||||
|
attach(snes.controllerPort1Device = 1, "SNES::Controller::Port1");
|
||||||
|
attach(snes.controllerPort2Device = 0, "SNES::Controller::Port2");
|
||||||
|
|
||||||
|
load(string{ application->userpath, "settings.cfg" });
|
||||||
|
save(string{ application->userpath, "settings.cfg" });
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::~Config() {
|
Config::~Config() {
|
||||||
|
save(string{ application->userpath, "settings.cfg" });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,36 @@
|
||||||
struct Config : public configuration {
|
struct Config : public configuration {
|
||||||
|
struct Video {
|
||||||
|
string driver;
|
||||||
|
string shader;
|
||||||
|
bool synchronize;
|
||||||
|
bool smooth;
|
||||||
|
} video;
|
||||||
|
|
||||||
|
struct Audio {
|
||||||
|
string driver;
|
||||||
|
bool synchronize;
|
||||||
|
bool mute;
|
||||||
|
} audio;
|
||||||
|
|
||||||
|
struct Input {
|
||||||
|
string driver;
|
||||||
|
unsigned focusPolicy;
|
||||||
|
} input;
|
||||||
|
|
||||||
|
struct Path {
|
||||||
|
string last;
|
||||||
|
} path;
|
||||||
|
|
||||||
|
struct NES {
|
||||||
|
unsigned controllerPort1Device;
|
||||||
|
unsigned controllerPort2Device;
|
||||||
|
} nes;
|
||||||
|
|
||||||
|
struct SNES {
|
||||||
|
unsigned controllerPort1Device;
|
||||||
|
unsigned controllerPort2Device;
|
||||||
|
} snes;
|
||||||
|
|
||||||
Config();
|
Config();
|
||||||
~Config();
|
~Config();
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,19 +2,22 @@ FileBrowser *fileBrowser = 0;
|
||||||
|
|
||||||
FileBrowser::FileBrowser() {
|
FileBrowser::FileBrowser() {
|
||||||
setGeometry({ 128, 128, 640, 400 });
|
setGeometry({ 128, 128, 640, 400 });
|
||||||
setWidgetFont(application->normalFont);
|
windowManager->append(this, "FileBrowser");
|
||||||
|
|
||||||
pathBrowse.setText("Browse ...");
|
|
||||||
pathUp.setText("..");
|
|
||||||
|
|
||||||
layout.setMargin(5);
|
layout.setMargin(5);
|
||||||
|
pathBrowse.setText("Browse ...");
|
||||||
|
pathUp.setText("..");
|
||||||
|
openButton.setText("Open");
|
||||||
|
|
||||||
append(layout);
|
append(layout);
|
||||||
layout.append(pathLayout, ~0, 0, 5);
|
layout.append(pathLayout, ~0, 0, 5);
|
||||||
pathLayout.append(pathEdit, ~0, 0, 5);
|
pathLayout.append(pathEdit, ~0, 0, 5);
|
||||||
pathLayout.append(pathBrowse, 0, 0, 5);
|
pathLayout.append(pathBrowse, 0, 0, 5);
|
||||||
pathLayout.append(pathUp, 0, 0);
|
pathLayout.append(pathUp, 0, 0);
|
||||||
layout.append(fileList, ~0, ~0);
|
layout.append(fileList, ~0, ~0, 5);
|
||||||
|
layout.append(controlLayout, ~0, 0);
|
||||||
|
controlLayout.append(filterLabel, ~0, 0, 5);
|
||||||
|
controlLayout.append(openButton, 80, 0);
|
||||||
|
|
||||||
pathEdit.onActivate = [&] {
|
pathEdit.onActivate = [&] {
|
||||||
string path = pathEdit.text();
|
string path = pathEdit.text();
|
||||||
|
@ -36,12 +39,9 @@ FileBrowser::FileBrowser() {
|
||||||
setPath(path);
|
setPath(path);
|
||||||
};
|
};
|
||||||
|
|
||||||
fileList.onActivate = { &FileBrowser::fileListActivate, this };
|
fileList.onActivate = openButton.onTick = { &FileBrowser::fileListActivate, this };
|
||||||
|
|
||||||
char path[PATH_MAX];
|
setPath(config->path.last);
|
||||||
auto unused = getcwd(path);
|
|
||||||
strcpy(path, "/media/sdb1/root/nes_images/");
|
|
||||||
setPath(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileBrowser::open(const string &title, const lstring &filterList, function<void (string)> callback) {
|
void FileBrowser::open(const string &title, const lstring &filterList, function<void (string)> callback) {
|
||||||
|
@ -50,10 +50,17 @@ void FileBrowser::open(const string &title, const lstring &filterList, function<
|
||||||
|
|
||||||
setTitle(title);
|
setTitle(title);
|
||||||
setPath(activePath);
|
setPath(activePath);
|
||||||
|
|
||||||
|
string filterText = "Files of type: ";
|
||||||
|
foreach(filter, filterList) filterText.append(filter, ", ");
|
||||||
|
filterText.trim<1>(", ");
|
||||||
|
filterLabel.setText(filterText);
|
||||||
|
|
||||||
setVisible();
|
setVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileBrowser::setPath(const string &path) {
|
void FileBrowser::setPath(const string &path) {
|
||||||
|
config->path.last = path;
|
||||||
activePath = path;
|
activePath = path;
|
||||||
pathEdit.setText(activePath);
|
pathEdit.setText(activePath);
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,9 @@ struct FileBrowser : Window {
|
||||||
Button pathBrowse;
|
Button pathBrowse;
|
||||||
Button pathUp;
|
Button pathUp;
|
||||||
ListView fileList;
|
ListView fileList;
|
||||||
lstring fileNameList;
|
HorizontalLayout controlLayout;
|
||||||
|
Label filterLabel;
|
||||||
|
Button openButton;
|
||||||
|
|
||||||
void open(const string &title, const lstring &filterList, function<void (string)> callback);
|
void open(const string &title, const lstring &filterList, function<void (string)> callback);
|
||||||
|
|
||||||
|
@ -14,6 +16,7 @@ struct FileBrowser : Window {
|
||||||
private:
|
private:
|
||||||
string activePath;
|
string activePath;
|
||||||
lstring filterList;
|
lstring filterList;
|
||||||
|
lstring fileNameList;
|
||||||
function<void (string)> callback;
|
function<void (string)> callback;
|
||||||
|
|
||||||
void setPath(const string &path);
|
void setPath(const string &path);
|
||||||
|
|
|
@ -4,6 +4,7 @@ MainWindow::MainWindow() {
|
||||||
setTitle(application->title);
|
setTitle(application->title);
|
||||||
setGeometry({ 256, 256, 512, 480 });
|
setGeometry({ 256, 256, 512, 480 });
|
||||||
setBackgroundColor({ 0, 0, 0 });
|
setBackgroundColor({ 0, 0, 0 });
|
||||||
|
windowManager->append(this, "MainWindow");
|
||||||
|
|
||||||
cartridgeMenu.setText("Cartridge");
|
cartridgeMenu.setText("Cartridge");
|
||||||
cartridgeLoadSNES.setText("Load SNES Cartridge ...");
|
cartridgeLoadSNES.setText("Load SNES Cartridge ...");
|
||||||
|
@ -13,25 +14,57 @@ MainWindow::MainWindow() {
|
||||||
nesMenu.setText("NES");
|
nesMenu.setText("NES");
|
||||||
nesPower.setText("Power Cycle");
|
nesPower.setText("Power Cycle");
|
||||||
nesReset.setText("Reset");
|
nesReset.setText("Reset");
|
||||||
|
nesPort1.setText("Controller Port 1");
|
||||||
|
nesPort1Device[0].setText("None");
|
||||||
|
nesPort1Device[1].setText("Gamepad");
|
||||||
|
RadioItem::group(nesPort1Device[0], nesPort1Device[1]);
|
||||||
|
nesPort1Device[config->nes.controllerPort1Device].setChecked();
|
||||||
|
nesPort2.setText("Controller Port 2");
|
||||||
|
nesPort2Device[0].setText("None");
|
||||||
|
nesPort2Device[1].setText("Gamepad");
|
||||||
|
RadioItem::group(nesPort2Device[0], nesPort2Device[1]);
|
||||||
|
nesPort2Device[config->nes.controllerPort2Device].setChecked();
|
||||||
nesCartridgeUnload.setText("Unload Cartridge");
|
nesCartridgeUnload.setText("Unload Cartridge");
|
||||||
|
|
||||||
snesMenu.setText("SNES");
|
snesMenu.setText("SNES");
|
||||||
snesPower.setText("Power Cycle");
|
snesPower.setText("Power Cycle");
|
||||||
snesReset.setText("Reset");
|
snesReset.setText("Reset");
|
||||||
snesCartridgeUnload.setText("Unload Cartridge");
|
|
||||||
snesPort1.setText("Controller Port 1");
|
snesPort1.setText("Controller Port 1");
|
||||||
|
snesPort1Device[0].setText("None");
|
||||||
|
snesPort1Device[1].setText("Gamepad");
|
||||||
|
snesPort1Device[2].setText("Multitap");
|
||||||
|
snesPort1Device[3].setText("Mouse");
|
||||||
|
RadioItem::group(snesPort1Device[0], snesPort1Device[1], snesPort1Device[2], snesPort1Device[3]);
|
||||||
|
snesPort1Device[config->snes.controllerPort1Device].setChecked();
|
||||||
snesPort2.setText("Controller Port 2");
|
snesPort2.setText("Controller Port 2");
|
||||||
|
snesPort2Device[0].setText("None");
|
||||||
|
snesPort2Device[1].setText("Gamepad");
|
||||||
|
snesPort2Device[2].setText("Multitap");
|
||||||
|
snesPort2Device[3].setText("Mouse");
|
||||||
|
snesPort2Device[4].setText("Super Scope");
|
||||||
|
snesPort2Device[5].setText("Justifier");
|
||||||
|
snesPort2Device[6].setText("Dual Justifiers");
|
||||||
|
snesPort2Device[7].setText("Serial Cable");
|
||||||
|
RadioItem::group(snesPort2Device[0], snesPort2Device[1], snesPort2Device[2], snesPort2Device[3],
|
||||||
|
snesPort2Device[4], snesPort2Device[5], snesPort2Device[6], snesPort2Device[7]);
|
||||||
|
snesPort2Device[config->snes.controllerPort2Device].setChecked();
|
||||||
|
snesCartridgeUnload.setText("Unload Cartridge");
|
||||||
|
|
||||||
gameBoyMenu.setText("Game Boy");
|
gameBoyMenu.setText("Game Boy");
|
||||||
gameBoyPower.setText("Power Cycle");
|
gameBoyPower.setText("Power Cycle");
|
||||||
gameBoyCartridgeUnload.setText("Unload Cartridge");
|
gameBoyCartridgeUnload.setText("Unload Cartridge");
|
||||||
|
|
||||||
settingsMenu.setText("Settings");
|
settingsMenu.setText("Settings");
|
||||||
|
settingsVideoShaders.setText("Video Shader");
|
||||||
|
setupVideoShaders();
|
||||||
settingsSynchronizeVideo.setText("Synchronize Video");
|
settingsSynchronizeVideo.setText("Synchronize Video");
|
||||||
settingsSynchronizeVideo.setChecked();
|
settingsSynchronizeVideo.setChecked(config->video.synchronize);
|
||||||
settingsSynchronizeAudio.setText("Synchronize Audio");
|
settingsSynchronizeAudio.setText("Synchronize Audio");
|
||||||
settingsSynchronizeAudio.setChecked();
|
settingsSynchronizeAudio.setChecked(config->audio.synchronize);
|
||||||
|
settingsSmoothVideo.setText("Smooth Video Output");
|
||||||
|
settingsSmoothVideo.setChecked(config->video.smooth);
|
||||||
settingsMuteAudio.setText("Mute Audio");
|
settingsMuteAudio.setText("Mute Audio");
|
||||||
|
settingsMuteAudio.setChecked(config->audio.mute);
|
||||||
settingsConfiguration.setText("Configuration ...");
|
settingsConfiguration.setText("Configuration ...");
|
||||||
|
|
||||||
toolsMenu.setText("Tools");
|
toolsMenu.setText("Tools");
|
||||||
|
@ -47,6 +80,7 @@ MainWindow::MainWindow() {
|
||||||
toolsStateLoad3.setText("Slot 3");
|
toolsStateLoad3.setText("Slot 3");
|
||||||
toolsStateLoad4.setText("Slot 4");
|
toolsStateLoad4.setText("Slot 4");
|
||||||
toolsStateLoad5.setText("Slot 5");
|
toolsStateLoad5.setText("Slot 5");
|
||||||
|
toolsCaptureMouse.setText("Capture Mouse");
|
||||||
toolsShrinkWindow.setText("Shrink Window");
|
toolsShrinkWindow.setText("Shrink Window");
|
||||||
toolsCheatEditor.setText("Cheat Editor ...");
|
toolsCheatEditor.setText("Cheat Editor ...");
|
||||||
toolsStateManager.setText("State Manager ...");
|
toolsStateManager.setText("State Manager ...");
|
||||||
|
@ -63,17 +97,36 @@ MainWindow::MainWindow() {
|
||||||
append(nesMenu);
|
append(nesMenu);
|
||||||
nesMenu.append(nesPower);
|
nesMenu.append(nesPower);
|
||||||
nesMenu.append(nesReset);
|
nesMenu.append(nesReset);
|
||||||
nesMenu.append(nesSeparator);
|
nesMenu.append(nesSeparator1);
|
||||||
|
nesMenu.append(nesPort1);
|
||||||
|
nesPort1.append(nesPort1Device[0]);
|
||||||
|
nesPort1.append(nesPort1Device[1]);
|
||||||
|
nesMenu.append(nesPort2);
|
||||||
|
nesPort2.append(nesPort2Device[0]);
|
||||||
|
nesPort2.append(nesPort2Device[1]);
|
||||||
|
nesMenu.append(nesSeparator2);
|
||||||
nesMenu.append(nesCartridgeUnload);
|
nesMenu.append(nesCartridgeUnload);
|
||||||
|
|
||||||
append(snesMenu);
|
append(snesMenu);
|
||||||
snesMenu.append(snesPower);
|
snesMenu.append(snesPower);
|
||||||
snesMenu.append(snesReset);
|
snesMenu.append(snesReset);
|
||||||
snesMenu.append(snesSeparator1);
|
snesMenu.append(snesSeparator1);
|
||||||
snesMenu.append(snesCartridgeUnload);
|
|
||||||
snesMenu.append(snesSeparator2);
|
|
||||||
snesMenu.append(snesPort1);
|
snesMenu.append(snesPort1);
|
||||||
|
snesPort1.append(snesPort1Device[0]);
|
||||||
|
snesPort1.append(snesPort1Device[1]);
|
||||||
|
snesPort1.append(snesPort1Device[2]);
|
||||||
|
snesPort1.append(snesPort1Device[3]);
|
||||||
snesMenu.append(snesPort2);
|
snesMenu.append(snesPort2);
|
||||||
|
snesPort2.append(snesPort2Device[0]);
|
||||||
|
snesPort2.append(snesPort2Device[1]);
|
||||||
|
snesPort2.append(snesPort2Device[2]);
|
||||||
|
snesPort2.append(snesPort2Device[3]);
|
||||||
|
snesPort2.append(snesPort2Device[4]);
|
||||||
|
snesPort2.append(snesPort2Device[5]);
|
||||||
|
snesPort2.append(snesPort2Device[6]);
|
||||||
|
snesPort2.append(snesPort2Device[7]);
|
||||||
|
snesMenu.append(snesSeparator2);
|
||||||
|
snesMenu.append(snesCartridgeUnload);
|
||||||
|
|
||||||
append(gameBoyMenu);
|
append(gameBoyMenu);
|
||||||
gameBoyMenu.append(gameBoyPower);
|
gameBoyMenu.append(gameBoyPower);
|
||||||
|
@ -81,10 +134,15 @@ MainWindow::MainWindow() {
|
||||||
gameBoyMenu.append(gameBoyCartridgeUnload);
|
gameBoyMenu.append(gameBoyCartridgeUnload);
|
||||||
|
|
||||||
append(settingsMenu);
|
append(settingsMenu);
|
||||||
|
settingsMenu.append(settingsVideoShaders);
|
||||||
|
for(unsigned n = 0; n < videoShaderCount; n++)
|
||||||
|
settingsVideoShaders.append(settingsVideoShader[n]);
|
||||||
|
settingsMenu.append(settingsSeparator1);
|
||||||
settingsMenu.append(settingsSynchronizeVideo);
|
settingsMenu.append(settingsSynchronizeVideo);
|
||||||
settingsMenu.append(settingsSynchronizeAudio);
|
settingsMenu.append(settingsSynchronizeAudio);
|
||||||
|
settingsMenu.append(settingsSmoothVideo);
|
||||||
settingsMenu.append(settingsMuteAudio);
|
settingsMenu.append(settingsMuteAudio);
|
||||||
settingsMenu.append(settingsSeparator);
|
settingsMenu.append(settingsSeparator2);
|
||||||
settingsMenu.append(settingsConfiguration);
|
settingsMenu.append(settingsConfiguration);
|
||||||
|
|
||||||
append(toolsMenu);
|
append(toolsMenu);
|
||||||
|
@ -100,20 +158,21 @@ MainWindow::MainWindow() {
|
||||||
toolsStateLoad.append(toolsStateLoad3);
|
toolsStateLoad.append(toolsStateLoad3);
|
||||||
toolsStateLoad.append(toolsStateLoad4);
|
toolsStateLoad.append(toolsStateLoad4);
|
||||||
toolsStateLoad.append(toolsStateLoad5);
|
toolsStateLoad.append(toolsStateLoad5);
|
||||||
toolsMenu.append(toolsSeparator);
|
toolsMenu.append(toolsSeparator1);
|
||||||
|
toolsMenu.append(toolsCaptureMouse);
|
||||||
toolsMenu.append(toolsShrinkWindow);
|
toolsMenu.append(toolsShrinkWindow);
|
||||||
|
toolsMenu.append(toolsSeparator2);
|
||||||
toolsMenu.append(toolsCheatEditor);
|
toolsMenu.append(toolsCheatEditor);
|
||||||
toolsMenu.append(toolsStateManager);
|
toolsMenu.append(toolsStateManager);
|
||||||
|
toolsMenu.append(toolsSeparator3);
|
||||||
toolsMenu.append(toolsTest);
|
toolsMenu.append(toolsTest);
|
||||||
|
|
||||||
append(helpMenu);
|
append(helpMenu);
|
||||||
helpMenu.append(helpAbout);
|
helpMenu.append(helpAbout);
|
||||||
|
|
||||||
setMenuFont(application->normalFont);
|
|
||||||
setMenuVisible();
|
setMenuVisible();
|
||||||
|
|
||||||
setStatusText("No cartridge loaded");
|
setStatusText("No cartridge loaded");
|
||||||
setStatusFont(application->boldFont);
|
|
||||||
setStatusVisible();
|
setStatusVisible();
|
||||||
|
|
||||||
layout.append(viewport, { 0, 0, 512, 480 });
|
layout.append(viewport, { 0, 0, 512, 480 });
|
||||||
|
@ -142,25 +201,55 @@ MainWindow::MainWindow() {
|
||||||
|
|
||||||
nesPower.onTick = { &Interface::power, interface };
|
nesPower.onTick = { &Interface::power, interface };
|
||||||
nesReset.onTick = { &Interface::reset, interface };
|
nesReset.onTick = { &Interface::reset, interface };
|
||||||
|
|
||||||
|
nesPort1Device[0].onTick = [&] { interface->setController(0, 0); };
|
||||||
|
nesPort1Device[1].onTick = [&] { interface->setController(0, 1); };
|
||||||
|
|
||||||
|
nesPort2Device[0].onTick = [&] { interface->setController(1, 0); };
|
||||||
|
nesPort2Device[1].onTick = [&] { interface->setController(1, 1); };
|
||||||
|
|
||||||
nesCartridgeUnload.onTick = { &Interface::unloadCartridge, interface };
|
nesCartridgeUnload.onTick = { &Interface::unloadCartridge, interface };
|
||||||
|
|
||||||
snesPower.onTick = { &Interface::power, interface };
|
snesPower.onTick = { &Interface::power, interface };
|
||||||
snesReset.onTick = { &Interface::reset, interface };
|
snesReset.onTick = { &Interface::reset, interface };
|
||||||
|
|
||||||
|
snesPort1Device[0].onTick = [&] { interface->setController(0, 0); };
|
||||||
|
snesPort1Device[1].onTick = [&] { interface->setController(0, 1); };
|
||||||
|
snesPort1Device[2].onTick = [&] { interface->setController(0, 2); };
|
||||||
|
snesPort1Device[3].onTick = [&] { interface->setController(0, 3); };
|
||||||
|
|
||||||
|
snesPort2Device[0].onTick = [&] { interface->setController(1, 0); };
|
||||||
|
snesPort2Device[1].onTick = [&] { interface->setController(1, 1); };
|
||||||
|
snesPort2Device[2].onTick = [&] { interface->setController(1, 2); };
|
||||||
|
snesPort2Device[3].onTick = [&] { interface->setController(1, 3); };
|
||||||
|
snesPort2Device[4].onTick = [&] { interface->setController(1, 4); };
|
||||||
|
snesPort2Device[5].onTick = [&] { interface->setController(1, 5); };
|
||||||
|
snesPort2Device[6].onTick = [&] { interface->setController(1, 6); };
|
||||||
|
snesPort2Device[7].onTick = [&] { interface->setController(1, 7); };
|
||||||
|
|
||||||
snesCartridgeUnload.onTick = { &Interface::unloadCartridge, interface };
|
snesCartridgeUnload.onTick = { &Interface::unloadCartridge, interface };
|
||||||
|
|
||||||
gameBoyPower.onTick = { &Interface::power, interface };
|
gameBoyPower.onTick = { &Interface::power, interface };
|
||||||
gameBoyCartridgeUnload.onTick = { &Interface::unloadCartridge, interface };
|
gameBoyCartridgeUnload.onTick = { &Interface::unloadCartridge, interface };
|
||||||
|
|
||||||
settingsSynchronizeVideo.onTick = [&] {
|
settingsSynchronizeVideo.onTick = [&] {
|
||||||
video.set(Video::Synchronize, settingsSynchronizeVideo.checked());
|
config->video.synchronize = settingsSynchronizeVideo.checked();
|
||||||
|
video.set(Video::Synchronize, config->video.synchronize);
|
||||||
};
|
};
|
||||||
|
|
||||||
settingsSynchronizeAudio.onTick = [&] {
|
settingsSynchronizeAudio.onTick = [&] {
|
||||||
audio.set(Audio::Synchronize, settingsSynchronizeAudio.checked());
|
config->audio.synchronize = settingsSynchronizeAudio.checked();
|
||||||
|
audio.set(Audio::Synchronize, config->audio.synchronize);
|
||||||
|
};
|
||||||
|
|
||||||
|
settingsSmoothVideo.onTick = [&] {
|
||||||
|
config->video.smooth = settingsSmoothVideo.checked();
|
||||||
|
video.set(Video::Filter, config->video.smooth == false ? 0u : 1u);
|
||||||
};
|
};
|
||||||
|
|
||||||
settingsMuteAudio.onTick = [&] {
|
settingsMuteAudio.onTick = [&] {
|
||||||
dspaudio.setVolume(settingsMuteAudio.checked() ? 0.0 : 1.0);
|
config->audio.mute = settingsMuteAudio.checked();
|
||||||
|
dspaudio.setVolume(config->audio.mute == false ? 1.0 : 0.0);
|
||||||
};
|
};
|
||||||
|
|
||||||
settingsConfiguration.onTick = [&] { settingsWindow->setVisible(); };
|
settingsConfiguration.onTick = [&] { settingsWindow->setVisible(); };
|
||||||
|
@ -177,6 +266,7 @@ MainWindow::MainWindow() {
|
||||||
toolsStateLoad4.onTick = [&] { interface->loadState({ interface->baseName, "-4.bst" }); };
|
toolsStateLoad4.onTick = [&] { interface->loadState({ interface->baseName, "-4.bst" }); };
|
||||||
toolsStateLoad5.onTick = [&] { interface->loadState({ interface->baseName, "-5.bst" }); };
|
toolsStateLoad5.onTick = [&] { interface->loadState({ interface->baseName, "-5.bst" }); };
|
||||||
|
|
||||||
|
toolsCaptureMouse.onTick = [&] { input.acquire(); };
|
||||||
toolsShrinkWindow.onTick = [&] { utility->resizeMainWindow(true); };
|
toolsShrinkWindow.onTick = [&] { utility->resizeMainWindow(true); };
|
||||||
|
|
||||||
toolsCheatEditor.onTick = [&] { cheatEditor->setVisible(); };
|
toolsCheatEditor.onTick = [&] { cheatEditor->setVisible(); };
|
||||||
|
@ -206,3 +296,34 @@ void MainWindow::synchronize() {
|
||||||
toolsStateLoad.setEnabled(false);
|
toolsStateLoad.setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::setupVideoShaders() {
|
||||||
|
lstring files = directory::files({ application->userpath, "shaders/" }, { "*.", config->video.driver, ".shader" });
|
||||||
|
videoShaderCount = 1 + files.size();
|
||||||
|
|
||||||
|
reference_array<RadioItem&> group;
|
||||||
|
unsigned active = 0;
|
||||||
|
|
||||||
|
settingsVideoShader = new RadioItem[videoShaderCount];
|
||||||
|
for(unsigned n = 0; n < videoShaderCount; n++) {
|
||||||
|
string name;
|
||||||
|
if(n == 0) {
|
||||||
|
name = "None";
|
||||||
|
videoShaderName.append("");
|
||||||
|
} else {
|
||||||
|
name = files[n - 1];
|
||||||
|
videoShaderName.append({ application->userpath, "shaders/", name });
|
||||||
|
if(auto position = name.position(string{ ".", config->video.driver, ".shader" })) name[position()] = 0;
|
||||||
|
}
|
||||||
|
if(config->video.shader == videoShaderName[n]) active = n;
|
||||||
|
settingsVideoShader[n].setText(name);
|
||||||
|
settingsVideoShader[n].onTick = [&, n] {
|
||||||
|
config->video.shader = videoShaderName[n];
|
||||||
|
utility->bindVideoShader();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned n = 0; n < videoShaderCount; n++) group.append(settingsVideoShader[n]);
|
||||||
|
RadioItem::group(group);
|
||||||
|
settingsVideoShader[active].setChecked();
|
||||||
|
}
|
||||||
|
|
|
@ -10,17 +10,24 @@ struct MainWindow : Window {
|
||||||
Menu nesMenu;
|
Menu nesMenu;
|
||||||
Item nesPower;
|
Item nesPower;
|
||||||
Item nesReset;
|
Item nesReset;
|
||||||
Separator nesSeparator;
|
Separator nesSeparator1;
|
||||||
|
Menu nesPort1;
|
||||||
|
RadioItem nesPort1Device[2];
|
||||||
|
Menu nesPort2;
|
||||||
|
RadioItem nesPort2Device[2];
|
||||||
|
Separator nesSeparator2;
|
||||||
Item nesCartridgeUnload;
|
Item nesCartridgeUnload;
|
||||||
|
|
||||||
Menu snesMenu;
|
Menu snesMenu;
|
||||||
Item snesPower;
|
Item snesPower;
|
||||||
Item snesReset;
|
Item snesReset;
|
||||||
Separator snesSeparator1;
|
Separator snesSeparator1;
|
||||||
Item snesCartridgeUnload;
|
|
||||||
Separator snesSeparator2;
|
|
||||||
Menu snesPort1;
|
Menu snesPort1;
|
||||||
|
RadioItem snesPort1Device[4];
|
||||||
Menu snesPort2;
|
Menu snesPort2;
|
||||||
|
RadioItem snesPort2Device[8];
|
||||||
|
Separator snesSeparator2;
|
||||||
|
Item snesCartridgeUnload;
|
||||||
|
|
||||||
Menu gameBoyMenu;
|
Menu gameBoyMenu;
|
||||||
Item gameBoyPower;
|
Item gameBoyPower;
|
||||||
|
@ -28,10 +35,14 @@ struct MainWindow : Window {
|
||||||
Item gameBoyCartridgeUnload;
|
Item gameBoyCartridgeUnload;
|
||||||
|
|
||||||
Menu settingsMenu;
|
Menu settingsMenu;
|
||||||
|
Menu settingsVideoShaders;
|
||||||
|
RadioItem *settingsVideoShader;
|
||||||
|
Separator settingsSeparator1;
|
||||||
CheckItem settingsSynchronizeVideo;
|
CheckItem settingsSynchronizeVideo;
|
||||||
CheckItem settingsSynchronizeAudio;
|
CheckItem settingsSynchronizeAudio;
|
||||||
|
CheckItem settingsSmoothVideo;
|
||||||
CheckItem settingsMuteAudio;
|
CheckItem settingsMuteAudio;
|
||||||
Separator settingsSeparator;
|
Separator settingsSeparator2;
|
||||||
Item settingsConfiguration;
|
Item settingsConfiguration;
|
||||||
|
|
||||||
Menu toolsMenu;
|
Menu toolsMenu;
|
||||||
|
@ -47,10 +58,13 @@ struct MainWindow : Window {
|
||||||
Item toolsStateLoad3;
|
Item toolsStateLoad3;
|
||||||
Item toolsStateLoad4;
|
Item toolsStateLoad4;
|
||||||
Item toolsStateLoad5;
|
Item toolsStateLoad5;
|
||||||
Separator toolsSeparator;
|
Separator toolsSeparator1;
|
||||||
|
Item toolsCaptureMouse;
|
||||||
Item toolsShrinkWindow;
|
Item toolsShrinkWindow;
|
||||||
|
Separator toolsSeparator2;
|
||||||
Item toolsCheatEditor;
|
Item toolsCheatEditor;
|
||||||
Item toolsStateManager;
|
Item toolsStateManager;
|
||||||
|
Separator toolsSeparator3;
|
||||||
CheckItem toolsTest;
|
CheckItem toolsTest;
|
||||||
|
|
||||||
Menu helpMenu;
|
Menu helpMenu;
|
||||||
|
@ -58,6 +72,12 @@ struct MainWindow : Window {
|
||||||
|
|
||||||
void synchronize();
|
void synchronize();
|
||||||
MainWindow();
|
MainWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned videoShaderCount;
|
||||||
|
lstring videoShaderName;
|
||||||
|
|
||||||
|
void setupVideoShaders();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MainWindow *mainWindow;
|
extern MainWindow *mainWindow;
|
||||||
|
|
|
@ -12,6 +12,8 @@ void AbstractInput::attach(const string &primaryName, const string &secondaryNam
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractInput::bind() {
|
void AbstractInput::bind() {
|
||||||
|
if(mapping == "") type = Type::Button, mapping = "None";
|
||||||
|
|
||||||
if(mapping.endswith(".Up")) type = Type::HatUp;
|
if(mapping.endswith(".Up")) type = Type::HatUp;
|
||||||
else if(mapping.endswith(".Down")) type = Type::HatDown;
|
else if(mapping.endswith(".Down")) type = Type::HatDown;
|
||||||
else if(mapping.endswith(".Left")) type = Type::HatLeft;
|
else if(mapping.endswith(".Left")) type = Type::HatLeft;
|
||||||
|
@ -19,7 +21,8 @@ void AbstractInput::bind() {
|
||||||
else if(mapping.endswith(".Lo")) type = Type::AxisLo;
|
else if(mapping.endswith(".Lo")) type = Type::AxisLo;
|
||||||
else if(mapping.endswith(".Hi")) type = Type::AxisHi;
|
else if(mapping.endswith(".Hi")) type = Type::AxisHi;
|
||||||
else if(mapping.beginswith("JP") && mapping.position("Axis")) type = Type::Axis;
|
else if(mapping.beginswith("JP") && mapping.position("Axis")) type = Type::Axis;
|
||||||
else if(mapping.beginswith("MS") && mapping.endswith("axis")) type = Type::Axis;
|
else if(mapping.beginswith("MS") && mapping.endswith("axis")) type = Type::MouseAxis;
|
||||||
|
else if(mapping.beginswith("MS")) type = Type::MouseButton;
|
||||||
else type = Type::Button;
|
else type = Type::Button;
|
||||||
|
|
||||||
string decode = mapping;
|
string decode = mapping;
|
||||||
|
@ -28,6 +31,7 @@ void AbstractInput::bind() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t AbstractInput::poll() {
|
int16_t AbstractInput::poll() {
|
||||||
|
if(config->input.focusPolicy == 1 && mainWindow->focused() == false) return 0;
|
||||||
return inputManager->scancode[inputManager->activeScancode][scancode];
|
return inputManager->scancode[inputManager->activeScancode][scancode];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,18 +39,11 @@ int16_t AbstractInput::poll() {
|
||||||
|
|
||||||
bool AnalogInput::bind(int16_t scancode, int16_t value) {
|
bool AnalogInput::bind(int16_t scancode, int16_t value) {
|
||||||
string encode = Scancode::encode(scancode);
|
string encode = Scancode::encode(scancode);
|
||||||
|
Type type = Type::Button;
|
||||||
|
|
||||||
if(Mouse::isAnyAxis(scancode)) {
|
if(scancode == Scancode::None) goto bind;
|
||||||
for(unsigned n = 0; n < Mouse::Count; n++) {
|
if(Mouse::isAnyAxis(scancode)) { type = Type::MouseAxis; goto bind; }
|
||||||
if(scancode == mouse(n)[Mouse::Xaxis]) { encode.append(".Xaxis"); goto bind; }
|
if(Joypad::isAnyAxis(scancode)) { type = Type::Axis; goto bind; }
|
||||||
if(scancode == mouse(n)[Mouse::Yaxis]) { encode.append(".Yaxis"); goto bind; }
|
|
||||||
if(scancode == mouse(n)[Mouse::Zaxis]) { encode.append(".Zaxis"); goto bind; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Joypad::isAnyAxis(scancode)) {
|
|
||||||
goto bind;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -54,13 +51,25 @@ bind:
|
||||||
mapping = encode;
|
mapping = encode;
|
||||||
this->scancode = scancode;
|
this->scancode = scancode;
|
||||||
this->type = Type::Axis;
|
this->type = Type::Axis;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t AnalogInput::poll() {
|
||||||
|
int16_t value = AbstractInput::poll();
|
||||||
|
switch(type) {
|
||||||
|
case Type::MouseAxis: return input.acquired() ? value : 0;
|
||||||
|
case Type::Axis: return value;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
bool DigitalInput::bind(int16_t scancode, int16_t value) {
|
bool DigitalInput::bind(int16_t scancode, int16_t value) {
|
||||||
string encode = Scancode::encode(scancode);
|
string encode = Scancode::encode(scancode);
|
||||||
Type type;
|
Type type = Type::Button;
|
||||||
|
|
||||||
|
if(scancode == Scancode::None) goto bind;
|
||||||
|
|
||||||
if(Keyboard::isAnyKey(scancode) || Keyboard::isAnyModifier(scancode) || Joypad::isAnyButton(scancode)) {
|
if(Keyboard::isAnyKey(scancode) || Keyboard::isAnyModifier(scancode) || Joypad::isAnyButton(scancode)) {
|
||||||
if(value == 0) return false;
|
if(value == 0) return false;
|
||||||
|
@ -68,6 +77,12 @@ bool DigitalInput::bind(int16_t scancode, int16_t value) {
|
||||||
goto bind;
|
goto bind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Mouse::isAnyButton(scancode)) {
|
||||||
|
if(value == 0) return false;
|
||||||
|
type = Type::MouseButton;
|
||||||
|
goto bind;
|
||||||
|
}
|
||||||
|
|
||||||
if(Joypad::isAnyHat(scancode)) {
|
if(Joypad::isAnyHat(scancode)) {
|
||||||
if(value & Joypad::HatUp ) { type = Type::HatUp; encode.append(".Up" ); goto bind; }
|
if(value & Joypad::HatUp ) { type = Type::HatUp; encode.append(".Up" ); goto bind; }
|
||||||
if(value & Joypad::HatDown ) { type = Type::HatDown; encode.append(".Down" ); goto bind; }
|
if(value & Joypad::HatDown ) { type = Type::HatDown; encode.append(".Down" ); goto bind; }
|
||||||
|
@ -93,6 +108,7 @@ int16_t DigitalInput::poll() {
|
||||||
int16_t value = AbstractInput::poll();
|
int16_t value = AbstractInput::poll();
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Button: return (bool)(value);
|
case Type::Button: return (bool)(value);
|
||||||
|
case Type::MouseButton: return (bool)(value & input.acquired());
|
||||||
case Type::HatUp: return (bool)(value & Joypad::HatUp);
|
case Type::HatUp: return (bool)(value & Joypad::HatUp);
|
||||||
case Type::HatDown: return (bool)(value & Joypad::HatDown);
|
case Type::HatDown: return (bool)(value & Joypad::HatDown);
|
||||||
case Type::HatLeft: return (bool)(value & Joypad::HatLeft);
|
case Type::HatLeft: return (bool)(value & Joypad::HatLeft);
|
||||||
|
@ -157,10 +173,14 @@ void InputManager::scan() {
|
||||||
|
|
||||||
for(unsigned n = 0; n < Scancode::Limit; n++) {
|
for(unsigned n = 0; n < Scancode::Limit; n++) {
|
||||||
if(scancode[!activeScancode][n] != scancode[activeScancode][n]) {
|
if(scancode[!activeScancode][n] != scancode[activeScancode][n]) {
|
||||||
inputSettings->inputEvent(n, scancode[activeScancode][n]);
|
if(settingsWindow->focused()) inputSettings->inputEvent(n, scancode[activeScancode][n]);
|
||||||
userInterface.inputEvent(n, scancode[activeScancode][n]);
|
if(mainWindow->focused()) userInterface.inputEvent(n, scancode[activeScancode][n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(scancode[activeScancode][keyboard(0)[Keyboard::Escape]]) {
|
||||||
|
if(mainWindow->fullScreen() == false && input.acquired()) input.unacquire();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputManager::InputManager() {
|
InputManager::InputManager() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
struct AbstractInput {
|
struct AbstractInput {
|
||||||
enum class Type : unsigned { Button, Axis, HatUp, HatDown, HatLeft, HatRight, AxisLo, AxisHi } type;
|
enum class Type : unsigned { Button, MouseButton, MouseAxis, HatUp, HatDown, HatLeft, HatRight, Axis, AxisLo, AxisHi } type;
|
||||||
string name;
|
string name;
|
||||||
string mapping;
|
string mapping;
|
||||||
unsigned scancode;
|
unsigned scancode;
|
||||||
|
@ -12,6 +12,7 @@ struct AbstractInput {
|
||||||
|
|
||||||
struct AnalogInput : AbstractInput {
|
struct AnalogInput : AbstractInput {
|
||||||
bool bind(int16_t scancode, int16_t value);
|
bool bind(int16_t scancode, int16_t value);
|
||||||
|
int16_t poll();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DigitalInput : AbstractInput {
|
struct DigitalInput : AbstractInput {
|
||||||
|
|
|
@ -16,22 +16,14 @@ int16_t SnesGamepad::poll(unsigned n) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SnesGamepad::SnesGamepad() {
|
SnesGamepad::SnesGamepad(const string &name, bool defaultBindings) {
|
||||||
name = "Gamepad";
|
this->name = name;
|
||||||
|
|
||||||
up.name = "Up";
|
up.name = "Up", down.name = "Down", left.name = "Left", right.name = "Right";
|
||||||
down.name = "Down";
|
b.name = "B", a.name = "A", y.name = "Y", x.name = "X";
|
||||||
left.name = "Left";
|
l.name = "L", r.name = "R", select.name = "Select", start.name = "Start";
|
||||||
right.name = "Right";
|
|
||||||
b.name = "B";
|
|
||||||
a.name = "A";
|
|
||||||
y.name = "Y";
|
|
||||||
x.name = "X";
|
|
||||||
l.name = "L";
|
|
||||||
r.name = "R";
|
|
||||||
select.name = "Select";
|
|
||||||
start.name = "Start";
|
|
||||||
|
|
||||||
|
if(defaultBindings) {
|
||||||
up.mapping = "KB0::Up";
|
up.mapping = "KB0::Up";
|
||||||
down.mapping = "KB0::Down";
|
down.mapping = "KB0::Down";
|
||||||
left.mapping = "KB0::Left";
|
left.mapping = "KB0::Left";
|
||||||
|
@ -44,6 +36,7 @@ SnesGamepad::SnesGamepad() {
|
||||||
r.mapping = "KB0::C";
|
r.mapping = "KB0::C";
|
||||||
select.mapping = "KB0::Apostrophe";
|
select.mapping = "KB0::Apostrophe";
|
||||||
start.mapping = "KB0::Return";
|
start.mapping = "KB0::Return";
|
||||||
|
}
|
||||||
|
|
||||||
append(up); append(down); append(left); append(right);
|
append(up); append(down); append(left); append(right);
|
||||||
append(b); append(a); append(y); append(x);
|
append(b); append(a); append(y); append(x);
|
||||||
|
@ -52,16 +45,137 @@ SnesGamepad::SnesGamepad() {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
SnesPort1Input::SnesPort1Input() {
|
int16_t SnesMouse::poll(unsigned n) {
|
||||||
name = "Controller Port 1";
|
switch((SNES::Input::MouseID)n) {
|
||||||
append(gamepad);
|
case SNES::Input::MouseID::X: return xaxis.poll();
|
||||||
|
case SNES::Input::MouseID::Y: return yaxis.poll();
|
||||||
|
case SNES::Input::MouseID::Left: return left.poll();
|
||||||
|
case SNES::Input::MouseID::Right: return right.poll();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SnesMouse::SnesMouse(const string &name, bool defaultBindings) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
xaxis.name = "X-axis", yaxis.name = "Y-axis";
|
||||||
|
left.name = "Left button", right.name = "Right button";
|
||||||
|
|
||||||
|
if(defaultBindings) {
|
||||||
|
xaxis.mapping = "MS0::Xaxis";
|
||||||
|
yaxis.mapping = "MS0::Yaxis";
|
||||||
|
left.mapping = "MS0::Button0";
|
||||||
|
right.mapping = "MS0::Button2";
|
||||||
|
}
|
||||||
|
|
||||||
|
append(xaxis); append(yaxis);
|
||||||
|
append(left); append(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
SnesPort2Input::SnesPort2Input() {
|
int16_t SnesSuperScope::poll(unsigned n) {
|
||||||
|
switch((SNES::Input::SuperScopeID)n) {
|
||||||
|
case SNES::Input::SuperScopeID::X: return xaxis.poll();
|
||||||
|
case SNES::Input::SuperScopeID::Y: return yaxis.poll();
|
||||||
|
case SNES::Input::SuperScopeID::Trigger: return trigger.poll();
|
||||||
|
case SNES::Input::SuperScopeID::Cursor: return cursor.poll();
|
||||||
|
case SNES::Input::SuperScopeID::Turbo: return turbo.poll();
|
||||||
|
case SNES::Input::SuperScopeID::Pause: return pause.poll();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SnesSuperScope::SnesSuperScope(const string &name, bool defaultBindings) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
xaxis.name = "X-axis", yaxis.name = "Y-axis";
|
||||||
|
trigger.name = "Trigger", cursor.name = "Cursor", turbo.name = "Turbo", pause.name = "Pause";
|
||||||
|
|
||||||
|
if(defaultBindings) {
|
||||||
|
xaxis.mapping = "MS0::Xaxis";
|
||||||
|
yaxis.mapping = "MS0::Yaxis";
|
||||||
|
trigger.mapping = "MS0::Button0";
|
||||||
|
cursor.mapping = "MS0::Button2";
|
||||||
|
turbo.mapping = "KB0::T";
|
||||||
|
pause.mapping = "KB0::P";
|
||||||
|
}
|
||||||
|
|
||||||
|
append(xaxis); append(yaxis);
|
||||||
|
append(trigger); append(cursor); append(turbo); append(pause);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
int16_t SnesJustifier::poll(unsigned n) {
|
||||||
|
switch((SNES::Input::JustifierID)n) {
|
||||||
|
case SNES::Input::JustifierID::X: return xaxis.poll();
|
||||||
|
case SNES::Input::JustifierID::Y: return yaxis.poll();
|
||||||
|
case SNES::Input::JustifierID::Trigger: return trigger.poll();
|
||||||
|
case SNES::Input::JustifierID::Start: return start.poll();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SnesJustifier::SnesJustifier(const string &name, bool defaultBindings) {
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
xaxis.name = "X-axis", yaxis.name = "Y-axis";
|
||||||
|
trigger.name = "Trigger", start.name = "Start";
|
||||||
|
|
||||||
|
if(defaultBindings) {
|
||||||
|
xaxis.mapping = "MS0::Xaxis";
|
||||||
|
yaxis.mapping = "MS0::Yaxis";
|
||||||
|
trigger.mapping = "MS0::Button0";
|
||||||
|
start.mapping = "MS0::Button2";
|
||||||
|
}
|
||||||
|
|
||||||
|
append(xaxis), append(yaxis);
|
||||||
|
append(trigger), append(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
SnesPort1Input::SnesPort1Input():
|
||||||
|
gamepad("Gamepad", true),
|
||||||
|
multitap1("Multitap - Port 1", false),
|
||||||
|
multitap2("Multitap - Port 2", false),
|
||||||
|
multitap3("Multitap - Port 3", false),
|
||||||
|
multitap4("Multitap - Port 4", false),
|
||||||
|
mouse("Mouse", true)
|
||||||
|
{
|
||||||
|
name = "Controller Port 1";
|
||||||
|
append(gamepad);
|
||||||
|
append(multitap1);
|
||||||
|
append(multitap2);
|
||||||
|
append(multitap3);
|
||||||
|
append(multitap4);
|
||||||
|
append(mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
SnesPort2Input::SnesPort2Input():
|
||||||
|
gamepad("Gamepad", false),
|
||||||
|
multitap1("Multitap - Port 1", false),
|
||||||
|
multitap2("Multitap - Port 2", false),
|
||||||
|
multitap3("Multitap - Port 3", false),
|
||||||
|
multitap4("Multitap - Port 4", false),
|
||||||
|
mouse("Mouse", true),
|
||||||
|
superScope("Super Scope", true),
|
||||||
|
justifier1("Justifier - Port 1", true),
|
||||||
|
justifier2("Justifier - Port 2", false)
|
||||||
|
{
|
||||||
name = "Controller Port 2";
|
name = "Controller Port 2";
|
||||||
append(gamepad);
|
append(gamepad);
|
||||||
|
append(multitap1);
|
||||||
|
append(multitap2);
|
||||||
|
append(multitap3);
|
||||||
|
append(multitap4);
|
||||||
|
append(mouse);
|
||||||
|
append(superScope);
|
||||||
|
append(justifier1);
|
||||||
|
append(justifier2);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -4,17 +4,54 @@ struct SnesGamepad : TertiaryInput {
|
||||||
DigitalInput l, r, select, start;
|
DigitalInput l, r, select, start;
|
||||||
|
|
||||||
int16_t poll(unsigned n);
|
int16_t poll(unsigned n);
|
||||||
SnesGamepad();
|
SnesGamepad(const string &name, bool defaultBindings);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SnesMouse : TertiaryInput {
|
||||||
|
AnalogInput xaxis, yaxis;
|
||||||
|
DigitalInput left, right;
|
||||||
|
|
||||||
|
int16_t poll(unsigned n);
|
||||||
|
SnesMouse(const string &name, bool defaultBindings);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SnesSuperScope : TertiaryInput {
|
||||||
|
AnalogInput xaxis, yaxis;
|
||||||
|
DigitalInput trigger, cursor, turbo, pause;
|
||||||
|
|
||||||
|
int16_t poll(unsigned n);
|
||||||
|
SnesSuperScope(const string &name, bool defaultBindings);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SnesJustifier : TertiaryInput {
|
||||||
|
AnalogInput xaxis, yaxis;
|
||||||
|
DigitalInput trigger, start;
|
||||||
|
|
||||||
|
int16_t poll(unsigned n);
|
||||||
|
SnesJustifier(const string &name, bool defaultBindings);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SnesPort1Input : SecondaryInput {
|
struct SnesPort1Input : SecondaryInput {
|
||||||
SnesGamepad gamepad;
|
SnesGamepad gamepad;
|
||||||
|
SnesGamepad multitap1;
|
||||||
|
SnesGamepad multitap2;
|
||||||
|
SnesGamepad multitap3;
|
||||||
|
SnesGamepad multitap4;
|
||||||
|
SnesMouse mouse;
|
||||||
|
|
||||||
SnesPort1Input();
|
SnesPort1Input();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SnesPort2Input : SecondaryInput {
|
struct SnesPort2Input : SecondaryInput {
|
||||||
SnesGamepad gamepad;
|
SnesGamepad gamepad;
|
||||||
|
SnesGamepad multitap1;
|
||||||
|
SnesGamepad multitap2;
|
||||||
|
SnesGamepad multitap3;
|
||||||
|
SnesGamepad multitap4;
|
||||||
|
SnesMouse mouse;
|
||||||
|
SnesSuperScope superScope;
|
||||||
|
SnesJustifier justifier1;
|
||||||
|
SnesJustifier justifier2;
|
||||||
|
|
||||||
SnesPort2Input();
|
SnesPort2Input();
|
||||||
};
|
};
|
||||||
|
|
|
@ -33,7 +33,7 @@ bool InterfaceGameBoy::loadState(const string &filename) {
|
||||||
//
|
//
|
||||||
|
|
||||||
void InterfaceGameBoy::videoRefresh(const uint8_t *data) {
|
void InterfaceGameBoy::videoRefresh(const uint8_t *data) {
|
||||||
interface->video_refresh();
|
interface->videoRefresh();
|
||||||
|
|
||||||
uint32_t *output;
|
uint32_t *output;
|
||||||
unsigned outpitch;
|
unsigned outpitch;
|
||||||
|
|
|
@ -4,6 +4,27 @@
|
||||||
#include "gameboy.cpp"
|
#include "gameboy.cpp"
|
||||||
Interface *interface = 0;
|
Interface *interface = 0;
|
||||||
|
|
||||||
|
void Interface::bindControllers() {
|
||||||
|
switch(mode()) {
|
||||||
|
case Mode::NES:
|
||||||
|
nes.setController(0, config->nes.controllerPort1Device);
|
||||||
|
nes.setController(1, config->nes.controllerPort2Device);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Mode::SNES:
|
||||||
|
snes.setController(0, config->snes.controllerPort1Device);
|
||||||
|
snes.setController(1, config->snes.controllerPort2Device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Interface::setController(unsigned port, unsigned device) {
|
||||||
|
switch(mode()) {
|
||||||
|
case Mode::NES: return nes.setController(port, device);
|
||||||
|
case Mode::SNES: return snes.setController(port, device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Interface::loaded() {
|
bool Interface::loaded() {
|
||||||
switch(mode()) {
|
switch(mode()) {
|
||||||
case Mode::NES: return nes.cartridgeLoaded();
|
case Mode::NES: return nes.cartridgeLoaded();
|
||||||
|
@ -22,6 +43,7 @@ bool Interface::loadCartridge(const string &filename) {
|
||||||
if(filename.endswith(".gb" )) result = loadCartridgeGameBoy(filename);
|
if(filename.endswith(".gb" )) result = loadCartridgeGameBoy(filename);
|
||||||
if(filename.endswith(".gbc")) result = loadCartridgeGameBoy(filename);
|
if(filename.endswith(".gbc")) result = loadCartridgeGameBoy(filename);
|
||||||
if(result == true) {
|
if(result == true) {
|
||||||
|
bindControllers();
|
||||||
cheatEditor->load({ baseName, ".cht" });
|
cheatEditor->load({ baseName, ".cht" });
|
||||||
stateManager->load({ baseName, ".bsa" }, 0u);
|
stateManager->load({ baseName, ".bsa" }, 0u);
|
||||||
}
|
}
|
||||||
|
@ -148,10 +170,7 @@ Interface::Interface() {
|
||||||
|
|
||||||
//internal
|
//internal
|
||||||
|
|
||||||
void Interface::input_poll() {
|
void Interface::videoRefresh() {
|
||||||
}
|
|
||||||
|
|
||||||
void Interface::video_refresh() {
|
|
||||||
static unsigned frameCounter = 0;
|
static unsigned frameCounter = 0;
|
||||||
static time_t previous, current;
|
static time_t previous, current;
|
||||||
frameCounter++;
|
frameCounter++;
|
||||||
|
|
|
@ -6,6 +6,9 @@ struct Interface : property<Interface> {
|
||||||
enum class Mode : unsigned { None, SNES, NES, GameBoy };
|
enum class Mode : unsigned { None, SNES, NES, GameBoy };
|
||||||
readonly<Mode> mode;
|
readonly<Mode> mode;
|
||||||
|
|
||||||
|
void bindControllers();
|
||||||
|
void setController(unsigned port, unsigned device);
|
||||||
|
|
||||||
bool loaded();
|
bool loaded();
|
||||||
|
|
||||||
bool loadCartridge(const string &filename);
|
bool loadCartridge(const string &filename);
|
||||||
|
@ -31,8 +34,7 @@ struct Interface : property<Interface> {
|
||||||
|
|
||||||
Interface();
|
Interface();
|
||||||
|
|
||||||
void input_poll();
|
void videoRefresh();
|
||||||
void video_refresh();
|
|
||||||
|
|
||||||
string baseName; // = "/path/to/cartridge" (no extension)
|
string baseName; // = "/path/to/cartridge" (no extension)
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
void InterfaceNES::setController(bool port, unsigned device) {
|
||||||
|
if(port == 0) config->nes.controllerPort1Device = device;
|
||||||
|
if(port == 1) config->nes.controllerPort2Device = device;
|
||||||
|
|
||||||
|
if(port == 0) switch(device) {
|
||||||
|
case 0: return connect(0, NES::Input::Device::None);
|
||||||
|
case 1: return connect(0, NES::Input::Device::Joypad);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == 1) switch(device) {
|
||||||
|
case 0: return connect(1, NES::Input::Device::None);
|
||||||
|
case 1: return connect(1, NES::Input::Device::Joypad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool InterfaceNES::loadCartridge(const string &filename) {
|
bool InterfaceNES::loadCartridge(const string &filename) {
|
||||||
filemap fp;
|
filemap fp;
|
||||||
if(fp.open(filename, filemap::mode::read) == false) return false;
|
if(fp.open(filename, filemap::mode::read) == false) return false;
|
||||||
|
@ -17,7 +32,7 @@ void InterfaceNES::unloadCartridge() {
|
||||||
//
|
//
|
||||||
|
|
||||||
void InterfaceNES::videoRefresh(const uint16_t *data) {
|
void InterfaceNES::videoRefresh(const uint16_t *data) {
|
||||||
interface->video_refresh();
|
interface->videoRefresh();
|
||||||
|
|
||||||
uint32_t *output;
|
uint32_t *output;
|
||||||
unsigned outpitch;
|
unsigned outpitch;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
struct InterfaceNES : NES::Interface {
|
struct InterfaceNES : NES::Interface {
|
||||||
|
void setController(bool port, unsigned device);
|
||||||
|
|
||||||
bool loadCartridge(const string &filename);
|
bool loadCartridge(const string &filename);
|
||||||
void unloadCartridge();
|
void unloadCartridge();
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
void InterfaceSNES::setController(bool port, unsigned device) {
|
||||||
|
if(port == 0) config->snes.controllerPort1Device = device;
|
||||||
|
if(port == 1) config->snes.controllerPort2Device = device;
|
||||||
|
|
||||||
|
if(port == 0) switch(device) {
|
||||||
|
case 0: return connect(0, SNES::Input::Device::None);
|
||||||
|
case 1: return connect(0, SNES::Input::Device::Joypad);
|
||||||
|
case 2: return connect(0, SNES::Input::Device::Multitap);
|
||||||
|
case 3: return connect(0, SNES::Input::Device::Mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == 1) switch(device) {
|
||||||
|
case 0: return connect(1, SNES::Input::Device::None);
|
||||||
|
case 1: return connect(1, SNES::Input::Device::Joypad);
|
||||||
|
case 2: return connect(1, SNES::Input::Device::Multitap);
|
||||||
|
case 3: return connect(1, SNES::Input::Device::Mouse);
|
||||||
|
case 4: return connect(1, SNES::Input::Device::SuperScope);
|
||||||
|
case 5: return connect(1, SNES::Input::Device::Justifier);
|
||||||
|
case 6: return connect(1, SNES::Input::Device::Justifiers);
|
||||||
|
case 7: return connect(1, SNES::Input::Device::Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool InterfaceSNES::loadCartridge(const string &filename) {
|
bool InterfaceSNES::loadCartridge(const string &filename) {
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
|
@ -33,7 +56,7 @@ bool InterfaceSNES::loadState(const string &filename) {
|
||||||
//
|
//
|
||||||
|
|
||||||
void InterfaceSNES::videoRefresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {
|
void InterfaceSNES::videoRefresh(const uint16_t *data, bool hires, bool interlace, bool overscan) {
|
||||||
interface->video_refresh();
|
interface->videoRefresh();
|
||||||
|
|
||||||
unsigned width = hires ? 512 : 256;
|
unsigned width = hires ? 512 : 256;
|
||||||
unsigned height = 0 ? 224 : 239;
|
unsigned height = 0 ? 224 : 239;
|
||||||
|
@ -78,7 +101,34 @@ void InterfaceSNES::audioSample(int16_t lsample, int16_t rsample) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t InterfaceSNES::inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
|
int16_t InterfaceSNES::inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
|
||||||
if(port == 0 && device == SNES::Input::Device::Joypad) return inputManager->snes.port1.gamepad.poll(id);
|
if(port == 0) {
|
||||||
|
if(device == SNES::Input::Device::Joypad) return inputManager->snes.port1.gamepad.poll(id);
|
||||||
|
if(device == SNES::Input::Device::Multitap) {
|
||||||
|
if(index == 0) return inputManager->snes.port1.multitap1.poll(id);
|
||||||
|
if(index == 1) return inputManager->snes.port1.multitap1.poll(id);
|
||||||
|
if(index == 2) return inputManager->snes.port1.multitap1.poll(id);
|
||||||
|
if(index == 3) return inputManager->snes.port1.multitap1.poll(id);
|
||||||
|
}
|
||||||
|
if(device == SNES::Input::Device::Mouse) return inputManager->snes.port1.mouse.poll(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(port == 1) {
|
||||||
|
if(device == SNES::Input::Device::Joypad) return inputManager->snes.port2.gamepad.poll(id);
|
||||||
|
if(device == SNES::Input::Device::Multitap) {
|
||||||
|
if(index == 0) return inputManager->snes.port2.multitap1.poll(id);
|
||||||
|
if(index == 1) return inputManager->snes.port2.multitap1.poll(id);
|
||||||
|
if(index == 2) return inputManager->snes.port2.multitap1.poll(id);
|
||||||
|
if(index == 3) return inputManager->snes.port2.multitap1.poll(id);
|
||||||
|
}
|
||||||
|
if(device == SNES::Input::Device::Mouse) return inputManager->snes.port2.mouse.poll(id);
|
||||||
|
if(device == SNES::Input::Device::SuperScope) return inputManager->snes.port2.superScope.poll(id);
|
||||||
|
if(device == SNES::Input::Device::Justifier) return inputManager->snes.port2.justifier1.poll(id);
|
||||||
|
if(device == SNES::Input::Device::Justifiers) {
|
||||||
|
if(index == 0) return inputManager->snes.port2.justifier1.poll(id);
|
||||||
|
if(index == 1) return inputManager->snes.port2.justifier2.poll(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
struct InterfaceSNES : SNES::Interface {
|
struct InterfaceSNES : SNES::Interface {
|
||||||
|
void setController(bool port, unsigned device);
|
||||||
|
|
||||||
bool loadCartridge(const string &filename);
|
bool loadCartridge(const string &filename);
|
||||||
void unloadCartridge();
|
void unloadCartridge();
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,10 @@ nall::DSP dspaudio;
|
||||||
void Application::run() {
|
void Application::run() {
|
||||||
inputManager->scan();
|
inputManager->scan();
|
||||||
|
|
||||||
if(interface->loaded() == false) {
|
autopause = (mainWindow->focused() == false && config->input.focusPolicy == 2);
|
||||||
|
|
||||||
|
if(interface->loaded() == false || autopause) {
|
||||||
|
audio.clear();
|
||||||
usleep(20 * 1000);
|
usleep(20 * 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -34,48 +37,50 @@ Application::Application(int argc, char **argv) : quit(false) {
|
||||||
inputManager = new InputManager;
|
inputManager = new InputManager;
|
||||||
utility = new Utility;
|
utility = new Utility;
|
||||||
|
|
||||||
title = "batch";
|
title = "bsnes";
|
||||||
|
|
||||||
#if defined(PLATFORM_WIN)
|
#if defined(PLATFORM_WIN)
|
||||||
string videoDriver = "Direct3D", audioDriver = "XAudio2", inputDriver = "RawInput";
|
|
||||||
normalFont = "Tahoma, 8";
|
normalFont = "Tahoma, 8";
|
||||||
boldFont = "Tahoma, 8, Bold";
|
boldFont = "Tahoma, 8, Bold";
|
||||||
titleFont = "Tahoma, 16, Bold";
|
titleFont = "Tahoma, 16, Bold";
|
||||||
#else
|
#else
|
||||||
string videoDriver = "OpenGL", audioDriver = "PulseAudio", inputDriver = "SDL";
|
|
||||||
normalFont = "Sans, 8";
|
normalFont = "Sans, 8";
|
||||||
boldFont = "Sans, 8, Bold";
|
boldFont = "Sans, 8, Bold";
|
||||||
titleFont = "Sans, 16, Bold";
|
titleFont = "Sans, 16, Bold";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
windowManager = new WindowManager;
|
||||||
mainWindow = new MainWindow;
|
mainWindow = new MainWindow;
|
||||||
fileBrowser = new FileBrowser;
|
fileBrowser = new FileBrowser;
|
||||||
settingsWindow = new SettingsWindow;
|
settingsWindow = new SettingsWindow;
|
||||||
cheatEditor = new CheatEditor;
|
cheatEditor = new CheatEditor;
|
||||||
stateManager = new StateManager;
|
stateManager = new StateManager;
|
||||||
|
windowManager->loadGeometry();
|
||||||
|
|
||||||
utility->setMode(Interface::Mode::None);
|
utility->setMode(Interface::Mode::None);
|
||||||
mainWindow->setVisible();
|
mainWindow->setVisible();
|
||||||
|
|
||||||
video.driver(videoDriver);
|
video.driver(config->video.driver);
|
||||||
video.set(Video::Handle, mainWindow->viewport.handle());
|
video.set(Video::Handle, mainWindow->viewport.handle());
|
||||||
video.set(Video::Synchronize, true);
|
video.set(Video::Synchronize, config->video.synchronize);
|
||||||
video.set(Video::Filter, 0u);
|
video.set(Video::Filter, config->video.smooth == false ? 0u : 1u);
|
||||||
video.init();
|
video.init();
|
||||||
|
utility->bindVideoShader();
|
||||||
|
|
||||||
audio.driver(audioDriver);
|
audio.driver(config->audio.driver);
|
||||||
audio.set(Audio::Handle, mainWindow->viewport.handle());
|
audio.set(Audio::Handle, mainWindow->viewport.handle());
|
||||||
audio.set(Audio::Synchronize, true);
|
audio.set(Audio::Synchronize, config->audio.synchronize);
|
||||||
audio.set(Audio::Latency, 60u);
|
audio.set(Audio::Latency, 60u);
|
||||||
audio.set(Audio::Frequency, 48000u);
|
audio.set(Audio::Frequency, 48000u);
|
||||||
audio.init();
|
audio.init();
|
||||||
|
|
||||||
dspaudio.setPrecision(16);
|
dspaudio.setPrecision(16);
|
||||||
dspaudio.setVolume(1.0);
|
dspaudio.setVolume(config->audio.mute == false ? 1.0 : 0.0);
|
||||||
dspaudio.setBalance(0.0);
|
dspaudio.setBalance(0.0);
|
||||||
dspaudio.setResampler(DSP::Resampler::Average);
|
dspaudio.setResampler(DSP::Resampler::Average);
|
||||||
dspaudio.setResamplerFrequency(48000.0);
|
dspaudio.setResamplerFrequency(48000.0);
|
||||||
|
|
||||||
input.driver(inputDriver);
|
input.driver(config->input.driver);
|
||||||
input.set(Input::Handle, mainWindow->viewport.handle());
|
input.set(Input::Handle, mainWindow->viewport.handle());
|
||||||
input.init();
|
input.init();
|
||||||
|
|
||||||
|
@ -87,6 +92,7 @@ Application::Application(int argc, char **argv) : quit(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface->unloadCartridge();
|
interface->unloadCartridge();
|
||||||
|
windowManager->saveGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
Application::~Application() {
|
Application::~Application() {
|
||||||
|
@ -95,6 +101,7 @@ Application::~Application() {
|
||||||
delete settingsWindow;
|
delete settingsWindow;
|
||||||
delete fileBrowser;
|
delete fileBrowser;
|
||||||
delete mainWindow;
|
delete mainWindow;
|
||||||
|
delete windowManager;
|
||||||
delete utility;
|
delete utility;
|
||||||
delete inputManager;
|
delete inputManager;
|
||||||
delete interface;
|
delete interface;
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
AdvancedSettings *advancedSettings = 0;
|
||||||
|
|
||||||
|
AdvancedSettings::AdvancedSettings() {
|
||||||
|
title.setFont(application->titleFont);
|
||||||
|
title.setText("Advanced Settings");
|
||||||
|
driverLabel.setFont(application->boldFont);
|
||||||
|
driverLabel.setText("Driver selection: (changes require restart to take effect)");
|
||||||
|
videoLabel.setText("Video:");
|
||||||
|
audioLabel.setText("Audio:");
|
||||||
|
inputLabel.setText("Input:");
|
||||||
|
focusPolicyLabel.setFont(application->boldFont);
|
||||||
|
focusPolicyLabel.setText("When emulation window does not have focus:");
|
||||||
|
focusPolicy[0].setText("Allow input");
|
||||||
|
focusPolicy[1].setText("Ignore input");
|
||||||
|
focusPolicy[2].setText("Pause emulation");
|
||||||
|
RadioBox::group(focusPolicy[0], focusPolicy[1], focusPolicy[2]);
|
||||||
|
focusPolicy[config->input.focusPolicy].setChecked();
|
||||||
|
|
||||||
|
lstring list;
|
||||||
|
|
||||||
|
list.split(";", video.driver_list());
|
||||||
|
for(unsigned n = 0; n < list.size(); n++) {
|
||||||
|
videoDriver.append(list[n]);
|
||||||
|
if(list[n] == config->video.driver) videoDriver.setSelection(n);
|
||||||
|
if(list[n] == video.default_driver() && config->video.driver == "") videoDriver.setSelection(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.split(";", audio.driver_list());
|
||||||
|
for(unsigned n = 0; n < list.size(); n++) {
|
||||||
|
audioDriver.append(list[n]);
|
||||||
|
if(list[n] == config->audio.driver) audioDriver.setSelection(n);
|
||||||
|
if(list[n] == audio.default_driver() && config->audio.driver == "") audioDriver.setSelection(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
list.split(";", input.driver_list());
|
||||||
|
for(unsigned n = 0; n < list.size(); n++) {
|
||||||
|
inputDriver.append(list[n]);
|
||||||
|
if(list[n] == config->input.driver) inputDriver.setSelection(n);
|
||||||
|
if(list[n] == input.default_driver() && config->input.driver == "") inputDriver.setSelection(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
append(title, ~0, 0, 5);
|
||||||
|
append(driverLabel, ~0, 0, 5);
|
||||||
|
append(driverLayout, ~0, 0, 5);
|
||||||
|
driverLayout.append(videoLabel, 0, 0, 5);
|
||||||
|
driverLayout.append(videoDriver, ~0, 0, 5);
|
||||||
|
driverLayout.append(audioLabel, 0, 0, 5);
|
||||||
|
driverLayout.append(audioDriver, ~0, 0, 5);
|
||||||
|
driverLayout.append(inputLabel, 0, 0, 5);
|
||||||
|
driverLayout.append(inputDriver, ~0, 0);
|
||||||
|
append(focusPolicyLabel, ~0, 0, 5);
|
||||||
|
append(focusPolicyLayout, ~0, 0, 5);
|
||||||
|
focusPolicyLayout.append(focusPolicy[0], ~0, 0, 5);
|
||||||
|
focusPolicyLayout.append(focusPolicy[1], ~0, 0, 5);
|
||||||
|
focusPolicyLayout.append(focusPolicy[2], ~0, 0);
|
||||||
|
|
||||||
|
videoDriver.onChange = [&] {
|
||||||
|
lstring list;
|
||||||
|
list.split(";", video.driver_list());
|
||||||
|
config->video.driver = list[videoDriver.selection()];
|
||||||
|
};
|
||||||
|
|
||||||
|
audioDriver.onChange = [&] {
|
||||||
|
lstring list;
|
||||||
|
list.split(";", audio.driver_list());
|
||||||
|
config->audio.driver = list[audioDriver.selection()];
|
||||||
|
};
|
||||||
|
|
||||||
|
inputDriver.onChange = [&] {
|
||||||
|
lstring list;
|
||||||
|
list.split(";", input.driver_list());
|
||||||
|
config->input.driver = list[inputDriver.selection()];
|
||||||
|
};
|
||||||
|
|
||||||
|
focusPolicy[0].onTick = [&] { config->input.focusPolicy = 0; };
|
||||||
|
focusPolicy[1].onTick = [&] { config->input.focusPolicy = 1; };
|
||||||
|
focusPolicy[2].onTick = [&] { config->input.focusPolicy = 2; };
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
struct AdvancedSettings : VerticalLayout {
|
||||||
|
Label title;
|
||||||
|
Label driverLabel;
|
||||||
|
HorizontalLayout driverLayout;
|
||||||
|
Label videoLabel;
|
||||||
|
ComboBox videoDriver;
|
||||||
|
Label audioLabel;
|
||||||
|
ComboBox audioDriver;
|
||||||
|
Label inputLabel;
|
||||||
|
ComboBox inputDriver;
|
||||||
|
Label focusPolicyLabel;
|
||||||
|
HorizontalLayout focusPolicyLayout;
|
||||||
|
RadioBox focusPolicy[3];
|
||||||
|
|
||||||
|
AdvancedSettings();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern AdvancedSettings *advancedSettings;
|
|
@ -5,6 +5,9 @@ InputSettings::InputSettings() : activeInput(0) {
|
||||||
title.setText("Input Settings");
|
title.setText("Input Settings");
|
||||||
inputList.setHeaderText("Name", "Mapping");
|
inputList.setHeaderText("Name", "Mapping");
|
||||||
inputList.setHeaderVisible();
|
inputList.setHeaderVisible();
|
||||||
|
assignPrimary.setVisible(false);
|
||||||
|
assignSecondary.setVisible(false);
|
||||||
|
assignTertiary.setVisible(false);
|
||||||
clearButton.setText("Clear");
|
clearButton.setText("Clear");
|
||||||
|
|
||||||
for(unsigned n = 0; n < inputManager->inputList.size(); n++) {
|
for(unsigned n = 0; n < inputManager->inputList.size(); n++) {
|
||||||
|
@ -19,6 +22,9 @@ InputSettings::InputSettings() : activeInput(0) {
|
||||||
selectionLayout.append(tertiary, ~0, 0);
|
selectionLayout.append(tertiary, ~0, 0);
|
||||||
append(inputList, ~0, ~0, 5);
|
append(inputList, ~0, ~0, 5);
|
||||||
append(controlLayout, ~0, 0);
|
append(controlLayout, ~0, 0);
|
||||||
|
controlLayout.append(assignPrimary, 100, 0, 5);
|
||||||
|
controlLayout.append(assignSecondary, 100, 0, 5);
|
||||||
|
controlLayout.append(assignTertiary, 100, 0, 5);
|
||||||
controlLayout.append(spacer, ~0, 0);
|
controlLayout.append(spacer, ~0, 0);
|
||||||
controlLayout.append(clearButton, 80, 0);
|
controlLayout.append(clearButton, 80, 0);
|
||||||
|
|
||||||
|
@ -26,7 +32,11 @@ InputSettings::InputSettings() : activeInput(0) {
|
||||||
secondary.onChange = { &InputSettings::secondaryChange, this };
|
secondary.onChange = { &InputSettings::secondaryChange, this };
|
||||||
tertiary.onChange = { &InputSettings::tertiaryChange, this };
|
tertiary.onChange = { &InputSettings::tertiaryChange, this };
|
||||||
inputList.onChange = { &InputSettings::synchronize, this };
|
inputList.onChange = { &InputSettings::synchronize, this };
|
||||||
inputList.onActivate = { &InputSettings::assignInputBegin, this };
|
inputList.onActivate = { &InputSettings::assignInput, this };
|
||||||
|
assignPrimary.onTick = [&] { assignMouseInput(0); };
|
||||||
|
assignSecondary.onTick = [&] { assignMouseInput(1); };
|
||||||
|
assignTertiary.onTick = [&] { assignMouseInput(2); };
|
||||||
|
clearButton.onTick = { &InputSettings::clearInput, this };
|
||||||
|
|
||||||
synchronize();
|
synchronize();
|
||||||
}
|
}
|
||||||
|
@ -67,22 +77,70 @@ void InputSettings::tertiaryChange() {
|
||||||
inputList.autoSizeColumns();
|
inputList.autoSizeColumns();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputSettings::assignInputBegin() {
|
void InputSettings::assignInput() {
|
||||||
PrimaryInput &pinput = inputManager->inputList[primary.selection()];
|
PrimaryInput &pinput = inputManager->inputList[primary.selection()];
|
||||||
SecondaryInput &sinput = pinput[secondary.selection()];
|
SecondaryInput &sinput = pinput[secondary.selection()];
|
||||||
TertiaryInput &tinput = sinput[tertiary.selection()];
|
TertiaryInput &tinput = sinput[tertiary.selection()];
|
||||||
activeInput = &tinput[inputList.selection()];
|
activeInput = &tinput[inputList.selection()];
|
||||||
|
|
||||||
settingsWindow->layout.setEnabled(false);
|
|
||||||
settingsWindow->setStatusText({ "Set asssignment for [", tinput.name, "::", activeInput->name, "] ..." });
|
settingsWindow->setStatusText({ "Set asssignment for [", tinput.name, "::", activeInput->name, "] ..." });
|
||||||
|
settingsWindow->panelList.setEnabled(false);
|
||||||
|
primary.setEnabled(false);
|
||||||
|
secondary.setEnabled(false);
|
||||||
|
tertiary.setEnabled(false);
|
||||||
|
inputList.setEnabled(false);
|
||||||
|
|
||||||
|
if(dynamic_cast<AnalogInput*>(activeInput)) {
|
||||||
|
assignPrimary.setText("Mouse X-axis");
|
||||||
|
assignSecondary.setText("Mouse Y-axis");
|
||||||
|
assignPrimary.setVisible(true);
|
||||||
|
assignSecondary.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dynamic_cast<DigitalInput*>(activeInput)) {
|
||||||
|
assignPrimary.setText("Mouse Left");
|
||||||
|
assignSecondary.setText("Mouse Middle");
|
||||||
|
assignTertiary.setText("Mouse Right");
|
||||||
|
assignPrimary.setVisible(true);
|
||||||
|
assignSecondary.setVisible(true);
|
||||||
|
assignTertiary.setVisible(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputSettings::inputEvent(int16_t scancode, int16_t value) {
|
void InputSettings::assignMouseInput(unsigned n) {
|
||||||
if(activeInput == 0) return;
|
if(activeInput == 0) return;
|
||||||
|
|
||||||
|
if(dynamic_cast<AnalogInput*>(activeInput)) {
|
||||||
|
return inputEvent(mouse(0).axis(n), 1u, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dynamic_cast<DigitalInput*>(activeInput)) {
|
||||||
|
return inputEvent(mouse(0).button(n), 1u, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSettings::clearInput() {
|
||||||
|
PrimaryInput &pinput = inputManager->inputList[primary.selection()];
|
||||||
|
SecondaryInput &sinput = pinput[secondary.selection()];
|
||||||
|
TertiaryInput &tinput = sinput[tertiary.selection()];
|
||||||
|
activeInput = &tinput[inputList.selection()];
|
||||||
|
inputEvent(Scancode::None, 1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSettings::inputEvent(int16_t scancode, int16_t value, bool allowMouseInput) {
|
||||||
|
if(activeInput == 0) return;
|
||||||
|
if(allowMouseInput == false && (Mouse::isAnyButton(scancode) || Mouse::isAnyAxis(scancode))) return;
|
||||||
if(activeInput->bind(scancode, value) == false) return;
|
if(activeInput->bind(scancode, value) == false) return;
|
||||||
|
|
||||||
activeInput = 0;
|
activeInput = 0;
|
||||||
tertiaryChange();
|
tertiaryChange();
|
||||||
settingsWindow->setStatusText("");
|
settingsWindow->setStatusText("");
|
||||||
settingsWindow->layout.setEnabled(true);
|
settingsWindow->panelList.setEnabled(true);
|
||||||
|
primary.setEnabled(true);
|
||||||
|
secondary.setEnabled(true);
|
||||||
|
tertiary.setEnabled(true);
|
||||||
|
inputList.setEnabled(true);
|
||||||
|
assignPrimary.setVisible(false);
|
||||||
|
assignSecondary.setVisible(false);
|
||||||
|
assignTertiary.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ struct InputSettings : VerticalLayout {
|
||||||
ComboBox tertiary;
|
ComboBox tertiary;
|
||||||
ListView inputList;
|
ListView inputList;
|
||||||
HorizontalLayout controlLayout;
|
HorizontalLayout controlLayout;
|
||||||
|
Button assignPrimary;
|
||||||
|
Button assignSecondary;
|
||||||
|
Button assignTertiary;
|
||||||
Widget spacer;
|
Widget spacer;
|
||||||
Button clearButton;
|
Button clearButton;
|
||||||
|
|
||||||
|
@ -15,8 +18,10 @@ struct InputSettings : VerticalLayout {
|
||||||
void primaryChange();
|
void primaryChange();
|
||||||
void secondaryChange();
|
void secondaryChange();
|
||||||
void tertiaryChange();
|
void tertiaryChange();
|
||||||
void assignInputBegin();
|
void assignInput();
|
||||||
void inputEvent(int16_t scancode, int16_t value);
|
void assignMouseInput(unsigned);
|
||||||
|
void clearInput();
|
||||||
|
void inputEvent(int16_t scancode, int16_t value, bool allowMouseInput = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractInput *activeInput;
|
AbstractInput *activeInput;
|
||||||
|
|
|
@ -1,24 +1,51 @@
|
||||||
#include "../base.hpp"
|
#include "../base.hpp"
|
||||||
#include "input.cpp"
|
#include "input.cpp"
|
||||||
|
#include "advanced.cpp"
|
||||||
SettingsWindow *settingsWindow = 0;
|
SettingsWindow *settingsWindow = 0;
|
||||||
|
|
||||||
SettingsWindow::SettingsWindow() {
|
SettingsWindow::SettingsWindow() {
|
||||||
setTitle("Configuration Settings");
|
setTitle("Configuration Settings");
|
||||||
setGeometry({ 128, 128, 640, 360 });
|
setGeometry({ 128, 128, 640, 360 });
|
||||||
setStatusFont(application->boldFont);
|
|
||||||
setStatusVisible();
|
setStatusVisible();
|
||||||
|
windowManager->append(this, "SettingsWindow");
|
||||||
|
|
||||||
panelList.append("Input");
|
panelList.append("Input");
|
||||||
|
panelList.append("Advanced");
|
||||||
|
|
||||||
inputSettings = new InputSettings;
|
inputSettings = new InputSettings;
|
||||||
|
advancedSettings = new AdvancedSettings;
|
||||||
|
|
||||||
append(layout);
|
append(layout);
|
||||||
layout.setMargin(5);
|
layout.setMargin(5);
|
||||||
layout.append(panelList, 120, ~0, 5);
|
layout.append(panelList, 120, ~0, 5);
|
||||||
|
|
||||||
layout.append(*inputSettings, ~0, ~0);
|
panelList.onChange = [&] { setPanel(panelList.selection()); };
|
||||||
|
|
||||||
|
setPanel(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsWindow::~SettingsWindow() {
|
SettingsWindow::~SettingsWindow() {
|
||||||
|
delete advancedSettings;
|
||||||
delete inputSettings;
|
delete inputSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsWindow::setPanel(unsigned n) {
|
||||||
|
//TODO: removing layouts isn't working right, so for now we are hiding them on toggle
|
||||||
|
|
||||||
|
layout.remove(*inputSettings);
|
||||||
|
layout.remove(*advancedSettings);
|
||||||
|
|
||||||
|
inputSettings->setVisible(false);
|
||||||
|
advancedSettings->setVisible(false);
|
||||||
|
|
||||||
|
switch(n) {
|
||||||
|
case 0:
|
||||||
|
layout.append(*inputSettings, ~0, ~0);
|
||||||
|
inputSettings->setVisible();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
layout.append(*advancedSettings, ~0, ~0);
|
||||||
|
advancedSettings->setVisible();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#include "input.hpp"
|
#include "input.hpp"
|
||||||
|
#include "advanced.hpp"
|
||||||
|
|
||||||
struct SettingsWindow : Window {
|
struct SettingsWindow : Window {
|
||||||
HorizontalLayout layout;
|
HorizontalLayout layout;
|
||||||
ListView panelList;
|
ListView panelList;
|
||||||
|
|
||||||
|
void setPanel(unsigned);
|
||||||
|
|
||||||
SettingsWindow();
|
SettingsWindow();
|
||||||
~SettingsWindow();
|
~SettingsWindow();
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ CheatEditor *cheatEditor = 0;
|
||||||
CheatEditor::CheatEditor() {
|
CheatEditor::CheatEditor() {
|
||||||
setTitle("Cheat Editor");
|
setTitle("Cheat Editor");
|
||||||
setGeometry({ 128, 128, 600, 360 });
|
setGeometry({ 128, 128, 600, 360 });
|
||||||
|
windowManager->append(this, "CheatEditor");
|
||||||
|
|
||||||
cheatList.setHeaderText("Slot", "Code", "Description");
|
cheatList.setHeaderText("Slot", "Code", "Description");
|
||||||
cheatList.setHeaderVisible();
|
cheatList.setHeaderVisible();
|
||||||
|
|
|
@ -3,6 +3,7 @@ StateManager *stateManager = 0;
|
||||||
StateManager::StateManager() {
|
StateManager::StateManager() {
|
||||||
setTitle("State Manager");
|
setTitle("State Manager");
|
||||||
setGeometry({ 128, 128, 600, 360 });
|
setGeometry({ 128, 128, 600, 360 });
|
||||||
|
windowManager->append(this, "StateManager");
|
||||||
|
|
||||||
stateList.setHeaderText("Slot", "Description");
|
stateList.setHeaderText("Slot", "Description");
|
||||||
stateList.setHeaderVisible();
|
stateList.setHeaderVisible();
|
||||||
|
|
|
@ -95,3 +95,9 @@ void Utility::toggleFullScreen() {
|
||||||
fullScreen ^= 1;
|
fullScreen ^= 1;
|
||||||
resizeMainWindow();
|
resizeMainWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Utility::bindVideoShader() {
|
||||||
|
string data;
|
||||||
|
data.readfile(config->video.shader);
|
||||||
|
video.set(Video::Shader, (const char*)data);
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ struct Utility {
|
||||||
void resizeMainWindow(bool shrink = false);
|
void resizeMainWindow(bool shrink = false);
|
||||||
void shrinkMainWindow();
|
void shrinkMainWindow();
|
||||||
void toggleFullScreen();
|
void toggleFullScreen();
|
||||||
|
void bindVideoShader();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Utility *utility;
|
extern Utility *utility;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include "../base.hpp"
|
||||||
|
WindowManager *windowManager = 0;
|
||||||
|
|
||||||
|
void WindowManager::append(Window *window, const string &name) {
|
||||||
|
windowList.append({ window, name, geometry(window->geometry()) });
|
||||||
|
|
||||||
|
window->setMenuFont(application->normalFont);
|
||||||
|
window->setWidgetFont(application->normalFont);
|
||||||
|
window->setStatusFont(application->boldFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
string WindowManager::geometry(const Geometry &geometry) {
|
||||||
|
return { geometry.x, ",", geometry.y, ",", geometry.width, ",", geometry.height };
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry WindowManager::geometry(const string &geometry) {
|
||||||
|
lstring part;
|
||||||
|
part.split(",", geometry);
|
||||||
|
Geometry geom = {
|
||||||
|
(signed)integer(part[0]), (signed)integer(part[1]),
|
||||||
|
(unsigned)decimal(part[2]), (unsigned)decimal(part[3])
|
||||||
|
};
|
||||||
|
geom.x = max(0, min(7680, geom.x));
|
||||||
|
geom.y = max(0, min(4800, geom.y));
|
||||||
|
geom.width = min(7680, geom.width );
|
||||||
|
geom.height = min(4800, geom.height);
|
||||||
|
return geom;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::loadGeometry() {
|
||||||
|
foreach(window, windowList) {
|
||||||
|
config.attach(window.geometry, window.name);
|
||||||
|
}
|
||||||
|
config.load(string{ application->userpath, "geometry.cfg" });
|
||||||
|
config.save(string{ application->userpath, "geometry.cfg" });
|
||||||
|
foreach(window, windowList) {
|
||||||
|
window.window->setGeometry(geometry(window.geometry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::saveGeometry() {
|
||||||
|
foreach(window, windowList) {
|
||||||
|
window.geometry = geometry(window.window->geometry());
|
||||||
|
}
|
||||||
|
config.save(string{ application->userpath, "geometry.cfg" });
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
struct WindowManager {
|
||||||
|
struct WindowList {
|
||||||
|
Window *window;
|
||||||
|
string name;
|
||||||
|
string geometry;
|
||||||
|
};
|
||||||
|
linear_vector<WindowList> windowList;
|
||||||
|
|
||||||
|
void append(Window *window, const string &name);
|
||||||
|
|
||||||
|
string geometry(const Geometry &geometry);
|
||||||
|
Geometry geometry(const string &geometry);
|
||||||
|
|
||||||
|
void loadGeometry();
|
||||||
|
void saveGeometry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
configuration config;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern WindowManager *windowManager;
|
Loading…
Reference in New Issue