Compare commits

...

4 Commits
v054 ... v058

Author SHA1 Message Date
byuu
6ec765f2c4 Update to bsnes v058 release.
We've tested the latest release on at least a dozen computers now, all seems to be in order for a release.
Changelog:
    - added 21fx support (more on this later)
    - added movie recording and playback support
    - added rewind support (enable under Settings->Configuration->Advanced, use backspace key to rewind)
    - added speedup (fast forward) and slowdown key bindings
    - audio no longer stutters on Windows when moving or resizing the main window
    - co-processors can now specify their own clock rates instead of sharing the S-CPU clock rate
    - Super Game Boy 2 now runs at the correct hardware speed, and not 2.4% faster like the Super Game Boy 1 does
    - added Vsync support to the Windows OpenGL driver (Intel graphics drivers do not support this option, because their engineers are lazy)
    - OpenGL driver no longer re-initializes when changing video synchronization, helps pixel shaders
    - refactored user interface compilation; now split into several object files, auto-generated MOC files placed under src/obj/
    - worked around a bug in the PulseAudio sound server that was causing the ALSA output driver to lock up [BearOso]
    - rewrote and simplified the save state manager, it is no longer a part of the core
    - S-DD1 and SPC7110 can now access up to 256MB via their MMCs
    - re-added background and OAM layer toggling under the tools dialog
    - added config file options to adjust emulation speed levels (config.system.speed*)
    - added snesreader, snesfilter and supergameboy support to the OS X port
    - added a really neat pixel shader that can perform point scaling to non-even multiples, eg it looks great even with aspect correction [Fes]
    - upgraded to Qt 4.6.0 official
Debugger changelog:
    - added memory export and import to the memory editor
    - added bus usage analyzer: logs opcodes, memory reads, memory writes and M/X states to usage.bin file
    - added disassembler that can trace both forward and backward from the current execution address
    - extended read/write breakpoints to the S-SMP
    - re-added trace masking option
Errata: there is one known bug in Qt 4.6.0 that affects the Windows port: menus attached to buttons show up as invisible on Windows Vista and above. I only use this on the file load dialog options button, and only to toggle the information pane on and off. Given that this is less severe than the bugs in the beta versions, I've upgraded anyway. I'll submit a bug report to the Qt team for this shortly. Also, my sincerest thanks to Bradley Hughes from the Qt development team for quickly fixing this show-stopper bug that greatly affected performance in bsnes v056.
2009-12-09 13:34:03 +00:00
byuu
54c7b4692d Update to bsnes v057 release.
I'm really sorry about this, but a major issue snuck into v056. It was caused by a bug in the newly released Qt 4.6.0 RC1. Whenever one moved the mouse cursor over the main window in the Windows port, the frame rate was immediately cut in half, which effectively ruined Mouse, Super Scope and Justifier support. As for how this could happen, well ... I'm ... really at a loss for words about this.
This release does not change the source code at all except to increment the version number, and it is built against Qt 4.6.0 beta 1 instead of 4.6.0 release candidate 1 as v055 was.
I will file an official bug complaint and post a link to it here during next week. Again, my apologies for any inconvenience. I incorrectly assumed it would be safe to update to RC1, and didn't spot the bug in time.
2009-11-23 13:24:03 +00:00
byuu
66067f0015 Update to bsnes v056 release.
This release adds a lot of new user interface features, and polishes Super Game Boy support.
Note that many pixel shaders need to be coded specifically for bsnes, eg ones designed for Pete's OpenGL2 plugin will not work. I will maintain a pixelshaders archive on the bsnes download page with a collection of working shaders. Right now, there are three: HDR TV, Scale2x and HQ2x; written by guest(r) and Pete, and ported by myself.
Changelog:
    - lowered Game Boy audio volume so that it matches SNES audio volume
    - fixed Super Game Boy multi-player support
    - fixed Super Game Boy swapped player bug
    - compressed Game Boy cartridges can now be loaded
    - added save state support for Super Game Boy games
    - blocked illegal Super Game Boy packets, fixes Zelda DX, Akumajou Dracula, etc palette issues
    - main window once again shrinks on size changes
    - joypads can now control the file loading window (support is very rudimentary)
    - cleaned up video and audio sliders, increased audio input frequency range for 59hz monitors
    - rewrote all of the input capture system from scratch
    - added dozens of additional GUI hotkey bindings to resize the main window, control synchronization, control speed, etc
    - it is now possible to map keyboard modifiers (shift, control, alt, super) to any input or hotkey; eg alt+enter = fullscreen
    - merged all input capture windows into the main settings panel
    - added turbo button support; hold down turbo buttons to send a 30hz input pulse
    - added asciiPad controller emulation; contains off/turbo/auto fire toggles and slow-motion mode
    - asciiPad support allows for quick switching between keyboard and gamepad input
    - merged scanline filter into the user interface (under Video Settings) to allow it to work on all filters; including the NTSC filter
    - killed off an evil QString <> string intermediary class called utf8; string class can convert to and from QString directly now
    - added fast BS-X, Sufami Turbo and Game Boy cartridge loading: use the filter list under "Load Cartridge" to bypass the BIOS selection screen
    - added pixel shader support to the OpenGL driver on Windows and Linux; note that it only really works well on Linux at the moment
    - added proper Vsync support to the OpenGL driver on Windows and Linux using GL extensions; again this really only works well on Linux
    - added unique path memory for shaders, folders, cartridges, BS-X, Sufami Turbo and Game Boy images
    - upgraded to Qt 4.6.0 release candidate 1; fixes an issue with the first checkbox in lists not updating when clicked
2009-11-22 14:48:58 +00:00
byuu
4c66de6f27 Update to bsnes v055 release.
Happy Halloween, this release adds full Super Game Boy support ... but is it a trick, or a treat? ;) ::cough::, lameness aside ...
The Game Boy emulation core is courtesy of gambatte, and excellent, accuracy-focused, open source, and lightning fast Game Boy Color emulator. Now I know what you're thinking, using a Game Boy Color emulator with the Super Game Boy? The truth is, gambatte was just such an amazingly perfect fit that nothing else compared. I fully believe that even as a CGB emulator, gambatte will do a better job than any pure DMG emulator could.
The emulation of the ICD2 chip (aka the Super Game Boy) was fully reverse engineered by myself. Eventually I'll get an updated document put up explaining how it works.
The next question might be, "why emulate the Super Game Boy when existing Game Boy emulators do?"; well, they can only simulate part of the SGB. Features such as custom SNES sound effects, hand-drawn borders, multi-tap support and custom SNES code execution can only be accomplished by a true SNES emulator. Space Invaders is perhaps the most impressive demonstration, as it contains an entire SNES game embedded inside the Game Boy cartridge.
bsnes' SGB emulation supports virtually every command, full sound mixing from both the SNES and Game Boy sides, both BIOS revisions, etc. The only thing that is not fully functional yet is the multi-player support, but it should be in due time. Save state support is also planned for a later date.
Changelog:
    - added Super Game Boy emulation (thanks to gambatte for the Game Boy core)
    - extended hybrid scanline/cycle PPU renderer to support Mode7 register caching; fixes scanline flickering on NHL '94 title screen
    - all windows (other than the main window) can be closed with the escape key now
    - file dialog path selection now accepts typed paths; can be used to access hidden directories and network shares
    - file dialog's game information panel can now be disabled
    - fixed a crashing issue when the file dialog was given an invalid path
    - fixed screenshot capture save location
    - added screenshot capture option to tools menu
    - state manager now auto-closes when loading a state; it can be reopened quickly with F3
    - fixed GZip archive loading
    - fixed NTSC off-by-one filter bug on hires screens
    - extended Scale2x, LQ2x and HQ2x to properly filter hires screens
    - added Pixellate2x filter
2009-11-01 14:30:51 +00:00
170 changed files with 7048 additions and 4737 deletions

View File

@@ -79,8 +79,9 @@ link += $(call ifhas,input.rawinput,$(ruby),-ldinput8 -ldxguid)
objects := libco ruby
objects += system cartridge cheat
objects += memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu
objects += sgb superfx sa1
objects += supergameboy superfx sa1
objects += bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010 st011 st018
objects += 21fx
######################
### implicit rules ###
@@ -166,22 +167,23 @@ obj/system.o: system/system.cpp $(call rwildcard,system/)
### special chips ###
#####################
obj/sgb.o : chip/sgb/sgb.cpp $(call rwildcard,chip/sgb/)
obj/superfx.o: chip/superfx/superfx.cpp $(call rwildcard,chip/superfx/)
obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/)
obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.o : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/spc7110.o: chip/spc7110/spc7110.cpp chip/spc7110/*
obj/cx4.o : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.o : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.o : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.o : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.o : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.o : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.o : chip/st010/st010.cpp chip/st010/*
obj/st011.o : chip/st011/st011.cpp chip/st011/*
obj/st018.o : chip/st018/st018.cpp chip/st018/*
obj/supergameboy.o: chip/supergameboy/supergameboy.cpp $(call rwildcard,chip/supergameboy/)
obj/superfx.o : chip/superfx/superfx.cpp $(call rwildcard,chip/superfx/)
obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/)
obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.o : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/spc7110.o : chip/spc7110/spc7110.cpp chip/spc7110/*
obj/cx4.o : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.o : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.o : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.o : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.o : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.o : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.o : chip/st010/st010.cpp chip/st010/*
obj/st011.o : chip/st011/st011.cpp chip/st011/*
obj/st018.o : chip/st018/st018.cpp chip/st018/*
obj/21fx.o : chip/21fx/21fx.cpp chip/21fx/*
###############
### targets ###

View File

@@ -1,6 +1,6 @@
static const char bsnesVersion[] = "0.054";
static const char bsnesVersion[] = "0.058";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSaveStateVersion = 3;
static const unsigned bsnesSerializerVersion = 4;
//S-DSP can be encapsulated into a state machine using #define magic
//this avoids ~2.048m co_switch() calls per second (~5% speedup)

View File

@@ -6,13 +6,14 @@
namespace SNES {
#include "header.cpp"
#include "gameboyheader.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bsxflash, bsxram, bsxpram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
MappedRAM gbrom, gbram;
MappedRAM gbrom, gbram, gbrtc;
};
Cartridge cartridge;
@@ -43,7 +44,13 @@ void Cartridge::load(Mode cartridge_mode) {
}
if(mode() == ModeSuperGameBoy) {
if(memory::gbrom.data()) memory::gbram.map(allocate<uint8_t>(64 * 1024, 0xff), 64 * 1024);
if(memory::gbrom.data()) {
unsigned ram_size = gameboy_ram_size();
unsigned rtc_size = gameboy_rtc_size();
if(ram_size) memory::gbram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
if(rtc_size) memory::gbrtc.map(allocate<uint8_t>(rtc_size, 0x00), rtc_size);
}
}
memory::cartrom.write_protect(true);
@@ -58,6 +65,7 @@ void Cartridge::load(Mode cartridge_mode) {
memory::stBram.write_protect(false);
memory::gbrom.write_protect(true);
memory::gbram.write_protect(false);
memory::gbrtc.write_protect(false);
unsigned checksum = ~0;
for(unsigned n = 0; n < memory::cartrom.size(); n++) checksum = crc32_adjust(checksum, memory::cartrom[n]);
@@ -104,6 +112,7 @@ void Cartridge::unload() {
memory::stBram.reset();
memory::gbrom.reset();
memory::gbram.reset();
memory::gbrtc.reset();
if(loaded() == false) return;
bus.unload_cart();
@@ -116,6 +125,8 @@ Cartridge::Type Cartridge::detect_image_type(uint8_t *data, unsigned size) const
return info.type;
}
bool Cartridge::has_21fx() const { return s21fx.exists(); }
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
@@ -144,6 +155,10 @@ void Cartridge::serialize(serializer &s) {
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
s.array(memory::gbram.data(), memory::gbram.size());
}
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
s.array(memory::gbrtc.data(), memory::gbrtc.size());
}
}
Cartridge::Cartridge() {
@@ -213,5 +228,4 @@ Cartridge::cartinfo_t::cartinfo_t() {
reset();
}
};
}

View File

@@ -67,6 +67,7 @@ public:
property_t<bool> has_dsp1, has_dsp2, has_dsp3, has_dsp4;
property_t<bool> has_obc1;
property_t<bool> has_st010, has_st011, has_st018;
bool has_21fx() const;
//main interface
void load(Mode);
@@ -118,6 +119,9 @@ private:
unsigned find_header(const uint8_t *data, unsigned size) const;
unsigned score_header(const uint8_t *data, unsigned size, unsigned addr) const;
void set_cartinfo(const cartinfo_t&);
unsigned gameboy_ram_size() const;
unsigned gameboy_rtc_size() const;
};
namespace memory {
@@ -125,7 +129,7 @@ namespace memory {
extern MappedRAM bsxflash, bsxram, bsxpram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;
extern MappedRAM gbrom, gbram;
extern MappedRAM gbrom, gbram, gbrtc;
};
extern Cartridge cartridge;

View File

@@ -0,0 +1,22 @@
#ifdef CARTRIDGE_CPP
unsigned Cartridge::gameboy_ram_size() const {
if(memory::gbrom.size() < 512) return 0;
switch(memory::gbrom[0x0149]) {
case 0x00: return 0 * 1024;
case 0x01: return 8 * 1024;
case 0x02: return 8 * 1024;
case 0x03: return 32 * 1024;
case 0x04: return 128 * 1024;
case 0x05: return 128 * 1024;
default: return 128 * 1024;
}
}
unsigned Cartridge::gameboy_rtc_size() const {
if(memory::gbrom.size() < 512) return 0;
if(memory::gbrom[0x0147] == 0x0f || memory::gbrom[0x0147] == 0x10) return 4;
return 0;
}
#endif

165
src/chip/21fx/21fx.cpp Normal file
View File

@@ -0,0 +1,165 @@
#include <../base.hpp>
//$21f0 command port (r/w)
//-------------------
//$00 set data port address (sr[3-0] = address)
//$01 set audio track number (sr[1-0] = track number)
//$02 set volume (sr[1] = left, sr[0] = right)
//$03 set audio state (sr[0].d1 = pause, sr[0].d0 = repeat)
//
//d7 = data port busy
//d6 = audio port busy
//d5 = audio playing
//d4 = reserved (0)
//d3-d0 = version (1)
//
//
//$21f1 parameter port (w)
//---------------------
//(shift register)
//
//
//$21f2 data port (r)
//----------------
//(auto-increment read port)
#define S21FX_CPP
namespace SNES {
S21fx s21fx;
#include "serialization.cpp"
void S21fx::enter() {
scheduler.clock.cop_freq = 44100;
while(true) {
int16 left = 0, right = 0;
if((mmio.status & AudioPlaying) && !mmio.audio_pause) {
if(audiofile.open()) {
if(audiofile.end()) {
if(!mmio.audio_repeat) mmio.status &= ~AudioPlaying;
audiofile.seek(mmio.audio_offset = 58);
} else {
mmio.audio_offset += 4;
left = audiofile.readl(2);
right = audiofile.readl(2);
}
} else {
mmio.status &= ~AudioPlaying;
}
}
left = sclamp<16>((double)left * (double)mmio.audio_volume_left / 255.0);
right = sclamp<16>((double)right * (double)mmio.audio_volume_right / 255.0);
audio.coprocessor_sample(left, right);
scheduler.addclocks_cop(1);
scheduler.sync_copcpu();
}
}
void S21fx::init() {
}
void S21fx::enable() {
audio.coprocessor_enable(true);
audio.coprocessor_frequency(44100.0);
for(unsigned i = 0x21f0; i <= 0x21f7; i++) {
memory::mmio.map(i, *this);
}
if(datafile.open()) datafile.close();
datafile.open(string() << basepath << "21fx.bin", file::mode_read);
}
void S21fx::power() {
reset();
}
void S21fx::reset() {
mmio.status = DataPortBusy | AudioBusy;
mmio.shift_register = 0;
mmio.data_offset = 0;
mmio.audio_offset = 0;
mmio.audio_track = 0;
mmio.audio_volume_left = 255;
mmio.audio_volume_right = 255;
mmio.audio_repeat = false;
mmio.audio_pause = false;
}
uint8 S21fx::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x21f0) {
return mmio.status | 0x01;
}
if(addr == 0x21f2) {
if(mmio.status & DataPortBusy) return 0x00;
mmio.data_offset++;
if(datafile.open()) return datafile.read();
return 0x00;
}
return 0x00;
}
void S21fx::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr == 0x21f0) {
if(data == 0x00) {
mmio.data_offset = mmio.shift_register & 0xffffffff;
if(datafile.open()) {
datafile.seek(mmio.data_offset);
}
mmio.status &= ~DataPortBusy;
}
if(data == 0x01) {
mmio.audio_track = mmio.shift_register & 0xffff;
if(audiofile.open()) audiofile.close();
char track[16];
sprintf(track, "%.5u", mmio.audio_track);
if(audiofile.open(string() << basepath << "audio" << track << ".wav", file::mode_read)) {
audiofile.seek(mmio.audio_offset = 58); //skip WAV header
}
mmio.status &= ~(AudioBusy | AudioPlaying);
}
if(data == 0x02) {
mmio.audio_volume_left = mmio.shift_register >> 8;
mmio.audio_volume_right = mmio.shift_register >> 0;
}
if(data == 0x03) {
mmio.status |= AudioPlaying;
mmio.audio_repeat = mmio.shift_register & 1;
mmio.audio_pause = mmio.shift_register & 2;
}
mmio.shift_register = 0;
}
if(addr == 0x21f1) {
mmio.shift_register = (mmio.shift_register << 8) | data;
}
}
void S21fx::base(const string& path) {
basepath = path;
}
bool S21fx::exists() {
return file::exists(string() << basepath << "21fx.bin");
}
S21fx::S21fx() {
}
}

44
src/chip/21fx/21fx.hpp Normal file
View File

@@ -0,0 +1,44 @@
class S21fx : public MMIO {
public:
void enter();
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void base(const string &path);
bool exists();
void serialize(serializer&);
S21fx();
private:
string basepath;
file datafile;
file audiofile;
enum Flag {
DataPortBusy = 0x80,
AudioBusy = 0x40,
AudioPlaying = 0x20,
};
struct MMIO {
uint8 status;
uint64 shift_register;
uint32 data_offset;
uint32 audio_offset;
uint16 audio_track;
uint8 audio_volume_left;
uint8 audio_volume_right;
bool audio_repeat;
bool audio_pause;
} mmio;
};
extern S21fx s21fx;

View File

@@ -0,0 +1,31 @@
#ifdef S21FX_CPP
void S21fx::serialize(serializer &s) {
s.integer(mmio.status);
s.integer(mmio.shift_register);
s.integer(mmio.data_offset);
s.integer(mmio.audio_offset);
s.integer(mmio.audio_track);
s.integer(mmio.audio_volume_left);
s.integer(mmio.audio_volume_right);
s.integer(mmio.audio_repeat);
s.integer(mmio.audio_pause);
//flush file handles and indices, as a different track may be playing,
//or the file offsets may be at the wrong location ...
if(datafile.open()) datafile.close();
if(datafile.open(string() << basepath << "21fx.bin", file::mode_read)) {
datafile.seek(mmio.data_offset);
}
if(audiofile.open()) audiofile.close();
char track[16];
sprintf(track, "%.5u", mmio.audio_track);
if(audiofile.open(string() << basepath << "audio" << track << ".wav", file::mode_read)) {
audiofile.seek(mmio.audio_offset);
}
}
#endif

View File

@@ -1,4 +1,4 @@
#include "sgb/sgb.hpp"
#include "supergameboy/supergameboy.hpp"
#include "superfx/superfx.hpp"
#include "sa1/sa1.hpp"
#include "bsx/bsx.hpp"
@@ -14,3 +14,4 @@
#include "st010/st010.hpp"
#include "st011/st011.hpp"
#include "st018/st018.hpp"
#include "21fx/21fx.hpp"

View File

@@ -55,10 +55,10 @@ uint8 SDD1::mmio_read(unsigned addr) {
}
switch(addr) {
case 0x4804: return (mmc[0] >> 20) & 7;
case 0x4805: return (mmc[1] >> 20) & 7;
case 0x4806: return (mmc[2] >> 20) & 7;
case 0x4807: return (mmc[3] >> 20) & 7;
case 0x4804: return mmc[0] >> 20;
case 0x4805: return mmc[1] >> 20;
case 0x4806: return mmc[2] >> 20;
case 0x4807: return mmc[3] >> 20;
}
return cpu.regs.mdr;
@@ -84,10 +84,10 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
case 0x4800: sdd1_enable = data; break;
case 0x4801: xfer_enable = data; break;
case 0x4804: mmc[0] = (data & 7) << 20; break;
case 0x4805: mmc[1] = (data & 7) << 20; break;
case 0x4806: mmc[2] = (data & 7) << 20; break;
case 0x4807: mmc[3] = (data & 7) << 20; break;
case 0x4804: mmc[0] = data << 20; break;
case 0x4805: mmc[1] = data << 20; break;
case 0x4806: mmc[2] = data << 20; break;
case 0x4807: mmc[3] = data << 20; break;
}
}

View File

@@ -1,65 +0,0 @@
#include <../base.hpp>
#define SGB_CPP
namespace SNES {
SuperGameBoy sgb;
void SuperGameBoy::enter() {
while(true) {
if(sgb_run) {
unsigned samples = sgb_run(samplebuffer, 16);
scheduler.addclocks_cop(samples * 10);
scheduler.sync_copcpu();
} else {
scheduler.addclocks_cop(64 * 1024 * 1024);
scheduler.sync_copcpu();
}
}
}
uint8_t SuperGameBoy::read(unsigned addr) {
addr &= 0xffff;
if(sgb_read) return sgb_read(addr);
return 0x00;
}
void SuperGameBoy::write(unsigned addr, uint8_t data) {
addr &= 0xffff;
if(sgb_write) return sgb_write(addr, data);
}
void SuperGameBoy::init() {
if(libsgb.open("SuperGameBoy")) {
sgb_init = libsgb.sym("sgb_init");
sgb_term = libsgb.sym("sgb_term");
sgb_power = libsgb.sym("sgb_power");
sgb_reset = libsgb.sym("sgb_reset");
sgb_read = libsgb.sym("sgb_read");
sgb_write = libsgb.sym("sgb_write");
sgb_run = libsgb.sym("sgb_run");
}
}
void SuperGameBoy::enable() {
}
void SuperGameBoy::power() {
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
if(sgb_init) {
sgb_init(SGB2,
memory::gbrom.data(), memory::gbrom.size(),
memory::gbram.data(), memory::gbram.size()
);
}
if(sgb_power) sgb_power();
}
void SuperGameBoy::reset() {
if(sgb_reset) sgb_reset();
}
};

View File

@@ -1,27 +0,0 @@
class SuperGameBoy : public Memory {
public:
void enter();
uint8_t read(unsigned addr);
void write(unsigned addr, uint8_t data);
void init();
void enable();
void power();
void reset();
private:
library libsgb;
uint32_t samplebuffer[4096];
enum { SGB1 = 0, SGB2 = 1 };
function<bool (bool, uint8_t*, unsigned, uint8_t*, unsigned)> sgb_init;
function<void ()> sgb_term;
function<void ()> sgb_power;
function<void ()> sgb_reset;
function<uint8_t (unsigned)> sgb_read;
function<void (unsigned, uint8_t)> sgb_write;
function<unsigned (uint32_t*, unsigned)> sgb_run;
};
extern SuperGameBoy sgb;

View File

@@ -535,17 +535,17 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
case 0x4831: {
r4831 = data;
dx_offset = datarom_addr((data & 7) * 0x100000);
dx_offset = datarom_addr(data * 0x100000);
} break;
case 0x4832: {
r4832 = data;
ex_offset = datarom_addr((data & 7) * 0x100000);
ex_offset = datarom_addr(data * 0x100000);
} break;
case 0x4833: {
r4833 = data;
fx_offset = datarom_addr((data & 7) * 0x100000);
fx_offset = datarom_addr(data * 0x100000);
} break;
case 0x4834: r4834 = data; break;

View File

@@ -0,0 +1,133 @@
#include <../base.hpp>
#define SUPERGAMEBOY_CPP
namespace SNES {
SuperGameBoy supergameboy;
void SuperGameBoy::enter() {
scheduler.clock.cop_freq = (version == SuperGameBoy1 ? 2147727 : 2097152);
if(!sgb_run) while(true) {
audio.coprocessor_sample(0, 0);
scheduler.addclocks_cop(1);
scheduler.sync_copcpu();
}
while(true) {
unsigned samples = sgb_run(samplebuffer, 16);
for(unsigned i = 0; i < samples; i++) {
int16 left = samplebuffer[i] >> 0;
int16 right = samplebuffer[i] >> 16;
//SNES audio is notoriously quiet; lower Game Boy samples to match SGB sound effects
audio.coprocessor_sample(left / 3, right / 3);
}
scheduler.addclocks_cop(samples);
scheduler.sync_copcpu();
}
}
uint8 SuperGameBoy::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x2181) return mmio[0]->mmio_read(addr);
if(addr == 0x2182) return mmio[1]->mmio_read(addr);
if(addr == 0x420b) return mmio[2]->mmio_read(addr);
return 0x00;
}
void SuperGameBoy::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr == 0x2181) {
row = (row & 0xff00) | (data << 0);
mmio[0]->mmio_write(addr, data);
}
if(addr == 0x2182) {
row = (row & 0x00ff) | (data << 8);
mmio[1]->mmio_write(addr, data);
}
if(addr == 0x420b) {
if(data == 0x10 && sgb_row) {
if(row >= 0x5000 && row <= 0x6540) sgb_row((row - 0x5000) / 320);
if(row >= 0x6800 && row <= 0x7d40) sgb_row((row - 0x6800) / 320);
}
mmio[2]->mmio_write(addr, data);
}
}
uint8 SuperGameBoy::read(unsigned addr) {
if(sgb_read) return sgb_read(addr);
return 0x00;
}
void SuperGameBoy::write(unsigned addr, uint8 data) {
if(sgb_write) sgb_write(addr, data);
}
void SuperGameBoy::init() {
if(open("supergameboy")) {
sgb_rom = sym("sgb_rom");
sgb_ram = sym("sgb_ram");
sgb_rtc = sym("sgb_rtc");
sgb_init = sym("sgb_init");
sgb_term = sym("sgb_term");
sgb_power = sym("sgb_power");
sgb_reset = sym("sgb_reset");
sgb_row = sym("sgb_row");
sgb_read = sym("sgb_read");
sgb_write = sym("sgb_write");
sgb_run = sym("sgb_run");
sgb_save = sym("sgb_save");
sgb_serialize = sym("sgb_serialize");
}
}
void SuperGameBoy::enable() {
mmio[0] = memory::mmio.mmio[0x2181 - 0x2000];
mmio[1] = memory::mmio.mmio[0x2182 - 0x2000];
mmio[2] = memory::mmio.mmio[0x420b - 0x2000];
memory::mmio.map(0x2181, *this);
memory::mmio.map(0x2182, *this);
memory::mmio.map(0x420b, *this);
}
void SuperGameBoy::power() {
//determine whether to use SGB1 or SGB2 mode based on the cartridge title (look for the '2')
version = memory::cartrom[0x7fcd] != 0x32 ? SuperGameBoy1 : SuperGameBoy2;
audio.coprocessor_enable(true);
audio.coprocessor_frequency(version == SuperGameBoy1 ? 2147727.0 : 2097152.0);
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
sgb_rom(memory::gbrom.data(), memory::gbrom.size() == -1U ? 0 : memory::gbrom.size());
sgb_ram(memory::gbram.data(), memory::gbram.size() == -1U ? 0 : memory::gbram.size());
sgb_rtc(memory::gbrtc.data(), memory::gbrtc.size() == -1U ? 0 : memory::gbrtc.size());
//determine whether to use SGB1 or SGB2 mode based on the cartridge title (look for the '2')
if(sgb_init) sgb_init(version);
if(sgb_power) sgb_power();
}
void SuperGameBoy::reset() {
if(sgb_reset) sgb_reset();
}
void SuperGameBoy::unload() {
if(sgb_term) sgb_term();
}
void SuperGameBoy::serialize(serializer &s) {
s.integer(row);
s.integer(version);
if(sgb_serialize) sgb_serialize(s);
}
}

View File

@@ -0,0 +1,41 @@
class SuperGameBoy : public MMIO, public Memory, public library {
public:
void enter();
MMIO *mmio[3];
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void init();
void enable();
void power();
void reset();
void unload();
void serialize(serializer&);
private:
uint32_t samplebuffer[4096];
unsigned row;
bool version;
enum { SuperGameBoy1 = 0, SuperGameBoy2 = 1 };
function<void (uint8_t*, unsigned)> sgb_rom;
function<void (uint8_t*, unsigned)> sgb_ram;
function<void (uint8_t*, unsigned)> sgb_rtc;
function<bool (bool)> sgb_init;
function<void ()> sgb_term;
function<void ()> sgb_power;
function<void ()> sgb_reset;
function<void (unsigned)> sgb_row;
function<uint8 (uint16)> sgb_read;
function<void (uint16, uint8)> sgb_write;
function<unsigned (uint32_t*, unsigned)> sgb_run;
function<void ()> sgb_save;
function<void (serializer&)> sgb_serialize;
};
extern SuperGameBoy supergameboy;

View File

@@ -102,7 +102,7 @@ uint32 CPUcore::decode(uint8 offset_type, uint32 addr) {
return(r & 0xffffff);
}
void CPUcore::disassemble_opcode(char *output) {
void CPUcore::disassemble_opcode(char *output, uint32 addr) {
static reg24_t pc;
char t[256];
char *s = output;
@@ -112,7 +112,7 @@ void CPUcore::disassemble_opcode(char *output) {
return;
}
pc.d = regs.pc.d;
pc.d = addr;
sprintf(s, "%.6x ", (uint32)pc.d);
uint8 op = dreadb(pc.d); pc.w++;

View File

@@ -22,7 +22,7 @@
OPTYPE_RELW, //relw
};
void disassemble_opcode(char *output);
void disassemble_opcode(char *output, uint32 addr);
uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);

View File

@@ -10,25 +10,36 @@ void sCPUDebug::op_step() {
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Exec, regs.pc, 0x00);
}
if(debugger.trace_cpu) {
char t[256];
disassemble_opcode(t);
debugger.tracefile.print(string() << t << "\n");
}
usage[regs.pc] &= ~(UsageFlagM | UsageFlagX);
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
opcode_pc = regs.pc;
if(step_event) step_event();
sCPU::op_step();
scheduler.sync_cpusmp();
}
uint8 sCPUDebug::op_read(uint32 addr) {
uint8 data = sCPU::op_read(addr);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Read, addr, data);
return data;
}
void sCPUDebug::op_write(uint32 addr, uint8 data) {
sCPU::op_write(addr, data);
usage[addr] |= UsageWrite;
usage[addr] &= ~UsageExec;
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Write, addr, data);
}
sCPUDebug::sCPUDebug() {
usage = new uint8[1 << 24]();
opcode_pc = 0x8000;
}
sCPUDebug::~sCPUDebug() {
delete[] usage;
}
#endif

View File

@@ -1,6 +1,21 @@
class sCPUDebug : public sCPU {
public:
function<void ()> step_event;
enum Usage {
UsageRead = 0x80,
UsageWrite = 0x40,
UsageExec = 0x20,
UsageFlagM = 0x02,
UsageFlagX = 0x01,
};
uint8 *usage;
uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
void op_step();
uint8 op_read(uint32 addr);
void op_write(uint32 addr, uint8 data);
sCPUDebug();
~sCPUDebug();
};

View File

@@ -32,7 +32,7 @@ configuration data.
<h3>Supported Filetypes</h3><br>
<b>SFC, SMC:</b> SNES cartridge &mdash; ROM image.<br>
<b>SFC:</b> SNES cartridge &mdash; ROM image.<br>
<b>BS:</b> Satellaview BS-X flash cartridge &mdash; EEPROM image.<br>
<b>ST:</b> Sufami Turbo cartridge &mdash; ROM image.<br>
<b>SRM, PSR:</b> non-volatile memory, often used to save game data &mdash; (P)SRAM image.<br>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 935 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

View File

@@ -8,7 +8,7 @@
#include <nall/stdint.hpp>
#include <nall/utility.hpp>
#if defined(PLATFORM_X)
#if defined(PLATFORM_X) || defined(PLATFORM_OSX)
#include <dlfcn.h>
#elif defined(PLATFORM_WIN)
#include <windows.h>
@@ -52,6 +52,34 @@ namespace nall {
return dlsym((void*)handle, name);
}
inline void library::close() {
if(!handle) return;
dlclose((void*)handle);
handle = 0;
}
#elif defined(PLATFORM_OSX)
inline bool library::open(const char *name) {
if(handle) close();
char *t = new char[strlen(name) + 256];
strcpy(t, "lib");
strcat(t, name);
strcat(t, ".dylib");
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
if(!handle) {
strcpy(t, "/usr/local/lib/lib");
strcat(t, name);
strcat(t, ".dylib");
handle = (uintptr_t)dlopen(t, RTLD_LAZY);
}
delete[] t;
return handle;
}
inline void* library::sym(const char *name) {
if(!handle) return 0;
return dlsym((void*)handle, name);
}
inline void library::close() {
if(!handle) return;
dlclose((void*)handle);

View File

@@ -136,7 +136,7 @@ namespace nall {
function() { data.fn_call = 0; }
function(void *fn) {
data.fn_call = &fn_call_global;
data.fn_call = fn ? &fn_call_global : 0;
data.fn_global = (R (*)(PL))fn;
}

View File

@@ -6,258 +6,381 @@
#include <string.h>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
enum { input_none = 0 };
template<int number = -1> struct keyboard {
enum {
none = keyboard<number - 1>::limit,
escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
print_screen, scroll_lock, pause, tilde,
num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0,
dash, equal, backspace,
insert, delete_, home, end, page_up, page_down,
a, b, c, d, e, f, g, h, i, j, k, l, m,
n, o, p, q, r, s, t, u, v, w, x, y, z,
lbracket, rbracket, backslash, semicolon, apostrophe, comma, period, slash,
pad_1, pad_2, pad_3, pad_4, pad_5, pad_6, pad_7, pad_8, pad_9, pad_0,
point, enter, add, subtract, multiply, divide,
num_lock, caps_lock,
up, down, left, right,
tab, return_, spacebar,
lctrl, rctrl, lalt, ralt, lshift, rshift, lsuper, rsuper, menu,
limit,
};
struct Keyboard;
Keyboard& keyboard(unsigned = 0);
static const char KeyboardScancodeName[][64] = {
"Escape", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
"PrintScreen", "ScrollLock", "Pause", "Tilde",
"Num1", "Num2", "Num3", "Num4", "Num5", "Num6", "Num7", "Num8", "Num9", "Num0",
"Dash", "Equal", "Backspace",
"Insert", "Delete", "Home", "End", "PageUp", "PageDown",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"LeftBracket", "RightBracket", "Backslash", "Semicolon", "Apostrophe", "Comma", "Period", "Slash",
"Keypad1", "Keypad2", "Keypad3", "Keypad4", "Keypad5", "Keypad6", "Keypad7", "Keypad8", "Keypad9", "Keypad0",
"Point", "Enter", "Add", "Subtract", "Multiply", "Divide",
"NumLock", "CapsLock",
"Up", "Down", "Left", "Right",
"Tab", "Return", "Spacebar", "Menu",
"Shift", "Control", "Alt", "Super",
};
struct Keyboard {
const unsigned ID;
enum { Base = 1 };
enum { Count = 8, Size = 128 };
enum Scancode {
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
PrintScreen, ScrollLock, Pause, Tilde,
Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
Dash, Equal, Backspace,
Insert, Delete, Home, End, PageUp, PageDown,
A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
Point, Enter, Add, Subtract, Multiply, Divide,
NumLock, CapsLock,
Up, Down, Left, Right,
Tab, Return, Spacebar, Menu,
Shift, Control, Alt, Super,
Limit,
};
template<> struct keyboard<-1> {
enum { count = 16 };
enum {
none,
escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
print_screen, scroll_lock, pause, tilde,
num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0,
dash, equal, backspace,
insert, delete_, home, end, page_up, page_down,
a, b, c, d, e, f, g, h, i, j, k, l, m,
n, o, p, q, r, s, t, u, v, w, x, y, z,
lbracket, rbracket, backslash, semicolon, apostrophe, comma, period, slash,
pad_1, pad_2, pad_3, pad_4, pad_5, pad_6, pad_7, pad_8, pad_9, pad_0,
point, enter, add, subtract, multiply, divide,
num_lock, caps_lock,
up, down, left, right,
tab, return_, spacebar,
lctrl, rctrl, lalt, ralt, lshift, rshift, lsuper, rsuper, menu,
length, //number of syms per keyboard
limit = 0,
};
static uint16_t index(unsigned keyboard_number, unsigned keyboard_enum) {
if(keyboard_number >= count) return input_none;
return limit + keyboard_number * length + keyboard_enum;
static signed numberDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(keyboard(i).belongsTo(scancode)) return i;
}
};
template<int number = -1> struct mouse {
enum { buttons = 8 };
enum {
none = mouse<number - 1>::limit,
x, y, z,
button,
limit = button + buttons,
};
};
template<> struct mouse<-1> {
enum { count = 16, buttons = 8 };
enum {
none,
x, y, z,
button,
length = button + buttons - none, //number of syms per mouse
limit = keyboard<keyboard<>::count - 1>::limit,
};
static uint16_t index(unsigned mouse_number, unsigned mouse_enum) {
if(mouse_number >= count) return input_none;
return limit + mouse_number * length + mouse_enum;
}
};
template<int number = -1> struct joypad {
enum { hats = 8, axes = 32, buttons = 96 };
enum {
none = joypad<number - 1>::limit,
hat,
axis = hat + hats,
button = axis + axes,
limit = button + buttons,
};
};
template<> struct joypad<-1> {
enum { count = 16, hats = 8, axes = 32, buttons = 96 };
enum { hat_center = 0, hat_up = 1, hat_right = 2, hat_down = 4, hat_left = 8 };
enum {
none,
hat,
axis = hat + hats,
button = axis + axes,
length = button + buttons - none, //number of syms per joypad
limit = mouse<mouse<>::count - 1>::limit,
};
static uint16_t index(unsigned joypad_number, unsigned joypad_enum) {
if(joypad_number >= count) return input_none;
return limit + joypad_number * length + joypad_enum;
}
};
enum { input_limit = joypad<joypad<>::count - 1>::limit };
static const char keysym[][64] = {
"none",
"escape", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12",
"print_screen", "scroll_lock", "pause", "tilde",
"num_1", "num_2", "num_3", "num_4", "num_5", "num_6", "num_7", "num_8", "num_9", "num_0",
"dash", "equal", "backspace",
"insert", "delete", "home", "end", "page_up", "page_down",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"lbracket", "rbracket", "backslash", "semicolon", "apostrophe", "comma", "period", "slash",
"pad_1", "pad_2", "pad_3", "pad_4", "pad_5", "pad_6", "pad_7", "pad_8", "pad_9", "pad_0",
"point", "enter", "add", "subtract", "multiply", "divide",
"num_lock", "caps_lock",
"up", "down", "left", "right",
"tab", "return", "spacebar",
"lctrl", "rctrl", "lalt", "ralt", "lshift", "rshift", "lsuper", "rsuper", "menu",
"limit",
};
static const char* input_find(uint16_t key) {
static char buffer[64];
for(unsigned k = 0; k < keyboard<>::count; k++) {
if(key >= keyboard<>::index(k, keyboard<>::none) && key < keyboard<>::index(k, keyboard<>::length)) {
sprintf(buffer, "keyboard%.2d.%s", k, keysym[key - keyboard<>::index(k, keyboard<>::none)]);
return buffer;
}
}
for(unsigned m = 0; m < mouse<>::count; m++) {
if(key == mouse<>::index(m, mouse<>::x)) { sprintf(buffer, "mouse%.2d.x", m); return buffer; }
if(key == mouse<>::index(m, mouse<>::y)) { sprintf(buffer, "mouse%.2d.y", m); return buffer; }
if(key == mouse<>::index(m, mouse<>::z)) { sprintf(buffer, "mouse%.2d.z", m); return buffer; }
if(key >= mouse<>::index(m, mouse<>::button + 0)
&& key < mouse<>::index(m, mouse<>::button + mouse<>::buttons)) {
sprintf(buffer, "mouse%.2d.button%.2d", m, key - mouse<>::index(m, mouse<>::button));
return buffer;
}
}
for(unsigned j = 0; j < joypad<>::count; j++) {
if(key >= joypad<>::index(j, joypad<>::hat + 0)
&& key < joypad<>::index(j, joypad<>::hat + joypad<>::hats)) {
sprintf(buffer, "joypad%.2d.hat%.2d", j, key - joypad<>::index(j, joypad<>::hat));
return buffer;
}
if(key >= joypad<>::index(j, joypad<>::axis + 0)
&& key < joypad<>::index(j, joypad<>::axis + joypad<>::axes)) {
sprintf(buffer, "joypad%.2d.axis%.2d", j, key - joypad<>::index(j, joypad<>::axis));
return buffer;
}
if(key >= joypad<>::index(j, joypad<>::button + 0)
&& key < joypad<>::index(j, joypad<>::button + joypad<>::buttons)) {
sprintf(buffer, "joypad%.2d.button%.2d", j, key - joypad<>::index(j, joypad<>::button));
return buffer;
}
}
return "none";
return -1;
}
static char* input_find(char *out, uint16_t key) {
strcpy(out, input_find(key));
return out;
static signed keyDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(keyboard(i).isKey(scancode)) return scancode - keyboard(i).key(Escape);
}
return -1;
}
static uint16_t input_find(const char *key) {
if(!memcmp(key, "keyboard", 8)) {
key += 8;
if(!*key || !*(key + 1)) return input_none;
uint8_t k = (*key - '0') * 10 + (*(key + 1) - '0');
if(k >= keyboard<>::count) return input_none;
key += 2;
static signed modifierDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(keyboard(i).isModifier(scancode)) return scancode - keyboard(i).key(Shift);
}
return -1;
}
if(*key++ != '.') return input_none;
static bool isAnyKey(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(keyboard(i).isKey(scancode)) return true;
}
return false;
}
for(unsigned i = 0; i < keyboard<>::length; i++) {
if(!strcmp(key, keysym[i])) return keyboard<>::index(k, i);
static bool isAnyModifier(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(keyboard(i).isModifier(scancode)) return true;
}
return false;
}
static uint16_t decode(const char *name) {
string s(name);
if(!strbegin(name, "KB")) return 0;
ltrim(s, "KB");
unsigned id = strunsigned(s);
int pos = strpos(s, "::");
if(pos < 0) return 0;
s = substr(s, pos + 2);
for(unsigned i = 0; i < Limit; i++) {
if(s == KeyboardScancodeName[i]) return Base + Size * id + i;
}
return 0;
}
string encode(uint16_t code) const {
unsigned index = 0;
for(unsigned i = 0; i < Count; i++) {
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
index = code - (Base + Size * i);
break;
}
}
return string() << "KB" << ID << "::" << KeyboardScancodeName[index];
}
if(!memcmp(key, "mouse", 5)) {
key += 5;
if(!*key || !*(key + 1)) return input_none;
uint8_t m = (*key - '0') * 10 + (*(key + 1) - '0');
if(m >= mouse<>::count) return input_none;
key += 2;
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
uint16_t key(unsigned id) const { return Base + Size * ID + id; }
bool isKey(unsigned id) const { return id >= key(Escape) && id <= key(Menu); }
bool isModifier(unsigned id) const { return id >= key(Shift) && id <= key(Super); }
bool belongsTo(uint16_t scancode) const { return isKey(scancode) || isModifier(scancode); }
if(!strcmp(key, ".x")) return mouse<>::index(m, mouse<>::x);
if(!strcmp(key, ".y")) return mouse<>::index(m, mouse<>::y);
if(!strcmp(key, ".z")) return mouse<>::index(m, mouse<>::z);
Keyboard(unsigned ID_) : ID(ID_) {}
};
if(!memcmp(key, ".button", 7)) {
key += 7;
if(!*key || !*(key + 1)) return input_none;
uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0');
if(button >= mouse<>::buttons) return input_none;
return mouse<>::index(m, mouse<>::button + button);
}
return input_none;
}
if(!memcmp(key, "joypad", 6)) {
key += 6;
if(!*key || !*(key + 1)) return input_none;
uint8_t j = (*key - '0') * 10 + (*(key + 1) - '0');
if(j >= joypad<>::count) return input_none;
key += 2;
if(!memcmp(key, ".hat", 4)) {
key += 4;
if(!*key || !*(key + 1)) return input_none;
uint8_t hat = (*key - '0') * 10 + (*(key + 1) - '0');
if(hat >= joypad<>::hats) return input_none;
return joypad<>::index(j, joypad<>::hat + hat);
}
if(!memcmp(key, ".axis", 5)) {
key += 5;
if(!*key || !*(key + 1)) return input_none;
uint8_t axis = (*key - '0') * 10 + (*(key + 1) - '0');
if(axis >= joypad<>::axes) return input_none;
return joypad<>::index(j, joypad<>::axis + axis);
}
if(!memcmp(key, ".button", 7)) {
key += 7;
if(!*key || !*(key + 1)) return input_none;
uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0');
if(button >= joypad<>::buttons) return input_none;
return joypad<>::index(j, joypad<>::button + button);
}
return input_none;
}
return input_none;
inline Keyboard& keyboard(unsigned id) {
static Keyboard kb0(0), kb1(1), kb2(2), kb3(3), kb4(4), kb5(5), kb6(6), kb7(7);
switch(id) { default:
case 0: return kb0; case 1: return kb1; case 2: return kb2; case 3: return kb3;
case 4: return kb4; case 5: return kb5; case 6: return kb6; case 7: return kb7;
}
}
static const char MouseScancodeName[][64] = {
"Xaxis", "Yaxis", "Zaxis",
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
};
struct Mouse;
Mouse& mouse(unsigned = 0);
struct Mouse {
const unsigned ID;
enum { Base = Keyboard::Base + Keyboard::Size * Keyboard::Count };
enum { Count = 8, Size = 16 };
enum { Axes = 3, Buttons = 8 };
enum Scancode {
Xaxis, Yaxis, Zaxis,
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
Limit,
};
static signed numberDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(mouse(i).belongsTo(scancode)) return i;
}
return -1;
}
static signed axisDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(mouse(i).isAxis(scancode)) return scancode - mouse(i).axis(0);
}
return -1;
}
static signed buttonDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(mouse(i).isButton(scancode)) return scancode - mouse(i).button(0);
}
return -1;
}
static bool isAnyAxis(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(mouse(i).isAxis(scancode)) return true;
}
return false;
}
static bool isAnyButton(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(mouse(i).isButton(scancode)) return true;
}
return false;
}
static uint16_t decode(const char *name) {
string s(name);
if(!strbegin(name, "MS")) return 0;
ltrim(s, "MS");
unsigned id = strunsigned(s);
int pos = strpos(s, "::");
if(pos < 0) return 0;
s = substr(s, pos + 2);
for(unsigned i = 0; i < Limit; i++) {
if(s == MouseScancodeName[i]) return Base + Size * id + i;
}
return 0;
}
string encode(uint16_t code) const {
unsigned index = 0;
for(unsigned i = 0; i < Count; i++) {
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
index = code - (Base + Size * i);
break;
}
}
return string() << "MS" << ID << "::" << MouseScancodeName[index];
}
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
uint16_t axis(unsigned id) const { return Base + Size * ID + Xaxis + id; }
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(2); }
bool isButton(unsigned id) const { return id >= button(0) && id <= button(7); }
bool belongsTo(uint16_t scancode) const { return isAxis(scancode) || isButton(scancode); }
Mouse(unsigned ID_) : ID(ID_) {}
};
inline Mouse& mouse(unsigned id) {
static Mouse ms0(0), ms1(1), ms2(2), ms3(3), ms4(4), ms5(5), ms6(6), ms7(7);
switch(id) { default:
case 0: return ms0; case 1: return ms1; case 2: return ms2; case 3: return ms3;
case 4: return ms4; case 5: return ms5; case 6: return ms6; case 7: return ms7;
}
}
static const char JoypadScancodeName[][64] = {
"Hat0", "Hat1", "Hat2", "Hat3", "Hat4", "Hat5", "Hat6", "Hat7",
"Axis0", "Axis1", "Axis2", "Axis3", "Axis4", "Axis5", "Axis6", "Axis7",
"Axis8", "Axis9", "Axis10", "Axis11", "Axis12", "Axis13", "Axis14", "Axis15",
"Button0", "Button1", "Button2", "Button3", "Button4", "Button5", "Button6", "Button7",
"Button8", "Button9", "Button10", "Button11", "Button12", "Button13", "Button14", "Button15",
"Button16", "Button17", "Button18", "Button19", "Button20", "Button21", "Button22", "Button23",
"Button24", "Button25", "Button26", "Button27", "Button28", "Button29", "Button30", "Button31",
};
struct Joypad;
Joypad& joypad(unsigned = 0);
struct Joypad {
const unsigned ID;
enum { Base = Mouse::Base + Mouse::Size * Mouse::Count };
enum { Count = 8, Size = 64 };
enum { Hats = 8, Axes = 16, Buttons = 32 };
enum Scancode {
Hat0, Hat1, Hat2, Hat3, Hat4, Hat5, Hat6, Hat7,
Axis0, Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7,
Axis8, Axis9, Axis10, Axis11, Axis12, Axis13, Axis14, Axis15,
Button0, Button1, Button2, Button3, Button4, Button5, Button6, Button7,
Button8, Button9, Button10, Button11, Button12, Button13, Button14, Button15,
Button16, Button17, Button18, Button19, Button20, Button21, Button22, Button23,
Button24, Button25, Button26, Button27, Button28, Button29, Button30, Button31,
Limit,
};
enum Hat { HatCenter = 0, HatUp = 1, HatRight = 2, HatDown = 4, HatLeft = 8 };
static signed numberDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(joypad(i).belongsTo(scancode)) return i;
}
return -1;
}
static signed hatDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(joypad(i).isHat(scancode)) return scancode - joypad(i).hat(0);
}
return -1;
}
static signed axisDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(joypad(i).isAxis(scancode)) return scancode - joypad(i).axis(0);
}
return -1;
}
static signed buttonDecode(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(joypad(i).isButton(scancode)) return scancode - joypad(i).button(0);
}
return -1;
}
static bool isAnyHat(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(joypad(i).isHat(scancode)) return true;
}
return false;
}
static bool isAnyAxis(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(joypad(i).isAxis(scancode)) return true;
}
return false;
}
static bool isAnyButton(uint16_t scancode) {
for(unsigned i = 0; i < Count; i++) {
if(joypad(i).isButton(scancode)) return true;
}
return false;
}
static uint16_t decode(const char *name) {
string s(name);
if(!strbegin(name, "JP")) return 0;
ltrim(s, "JP");
unsigned id = strunsigned(s);
int pos = strpos(s, "::");
if(pos < 0) return 0;
s = substr(s, pos + 2);
for(unsigned i = 0; i < Limit; i++) {
if(s == JoypadScancodeName[i]) return Base + Size * id + i;
}
return 0;
}
string encode(uint16_t code) const {
unsigned index = 0;
for(unsigned i = 0; i < Count; i++) {
if(code >= Base + Size * i && code < Base + Size * (i + 1)) {
index = code - (Base + Size * i);
}
}
return string() << "JP" << ID << "::" << JoypadScancodeName[index];
}
uint16_t operator[](Scancode code) const { return Base + ID * Size + code; }
uint16_t hat(unsigned id) const { return Base + Size * ID + Hat0 + id; }
uint16_t axis(unsigned id) const { return Base + Size * ID + Axis0 + id; }
uint16_t button(unsigned id) const { return Base + Size * ID + Button0 + id; }
bool isHat(unsigned id) const { return id >= hat(0) && id <= hat(7); }
bool isAxis(unsigned id) const { return id >= axis(0) && id <= axis(15); }
bool isButton(unsigned id) const { return id >= button(0) && id <= button(31); }
bool belongsTo(uint16_t scancode) const { return isHat(scancode) || isAxis(scancode) || isButton(scancode); }
Joypad(unsigned ID_) : ID(ID_) {}
};
inline Joypad& joypad(unsigned id) {
static Joypad jp0(0), jp1(1), jp2(2), jp3(3), jp4(4), jp5(5), jp6(6), jp7(7);
switch(id) { default:
case 0: return jp0; case 1: return jp1; case 2: return jp2; case 3: return jp3;
case 4: return jp4; case 5: return jp5; case 6: return jp6; case 7: return jp7;
}
}
struct Scancode {
enum { None = 0, Limit = Joypad::Base + Joypad::Size * Joypad::Count };
static uint16_t decode(const char *name) {
uint16_t code;
code = Keyboard::decode(name);
if(code) return code;
code = Mouse::decode(name);
if(code) return code;
code = Joypad::decode(name);
if(code) return code;
return None;
}
static string encode(uint16_t code) {
for(unsigned i = 0; i < Keyboard::Count; i++) {
if(keyboard(i).belongsTo(code)) return keyboard(i).encode(code);
}
for(unsigned i = 0; i < Mouse::Count; i++) {
if(mouse(i).belongsTo(code)) return mouse(i).encode(code);
}
for(unsigned i = 0; i < Joypad::Count; i++) {
if(joypad(i).belongsTo(code)) return joypad(i).encode(code);
}
return "None";
}
};
}
#endif

View File

@@ -20,6 +20,12 @@ namespace nall {
class serializer {
public:
enum mode_t { Load, Save, Size };
mode_t mode() const {
return imode;
}
const uint8_t* data() const {
return idata;
}
@@ -37,9 +43,9 @@ namespace nall {
//this is rather dangerous, and not cross-platform safe;
//but there is no standardized way to export FP-values
uint8_t *p = (uint8_t*)&value;
if(mode == Save) {
if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = p[n];
} else if(mode == Load) {
} else if(imode == Load) {
for(unsigned n = 0; n < size; n++) p[n] = idata[isize++];
} else {
isize += size;
@@ -48,12 +54,12 @@ namespace nall {
template<typename T> void integer(T &value) {
enum { size = is_bool<T>::value ? 1 : sizeof(T) };
if(mode == Save) {
if(imode == Save) {
for(unsigned n = 0; n < size; n++) idata[isize++] = value >> (n << 3);
} else if(mode == Load) {
} else if(imode == Load) {
value = 0;
for(unsigned n = 0; n < size; n++) value |= idata[isize++] << (n << 3);
} else if(mode == Size) {
} else if(imode == Size) {
isize += size;
}
}
@@ -70,7 +76,7 @@ namespace nall {
serializer& operator=(const serializer &s) {
if(idata) delete[] idata;
mode = s.mode;
imode = s.imode;
idata = new uint8_t[s.icapacity];
isize = s.isize;
icapacity = s.icapacity;
@@ -84,20 +90,20 @@ namespace nall {
}
serializer() {
mode = Size;
imode = Size;
idata = 0;
isize = 0;
}
serializer(unsigned capacity) {
mode = Save;
imode = Save;
idata = new uint8_t[capacity]();
isize = 0;
icapacity = capacity;
}
serializer(const uint8_t *data, unsigned capacity) {
mode = Load;
imode = Load;
idata = new uint8_t[capacity];
isize = 0;
icapacity = capacity;
@@ -109,7 +115,7 @@ namespace nall {
}
private:
enum mode_t { Load, Save, Size } mode;
mode_t imode;
uint8_t *idata;
unsigned isize;
unsigned icapacity;

View File

@@ -80,6 +80,11 @@ namespace nall {
protected:
char *data;
size_t size;
#if defined(QT_CORE_LIB)
public:
inline operator QString() const;
#endif
};
class lstring : public vector<string> {

View File

@@ -20,6 +20,11 @@ namespace nall {
operator[](size()).assign(to_string<T>(value));
return *this;
}
#if defined(QT_CORE_LIB)
template<> inline string to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
string::operator QString() const { return QString::fromUtf8(*this); }
#endif
};
#endif

View File

@@ -31,6 +31,11 @@ namespace nall {
inline string basename(char const *name) {
string result = name;
for(signed i = strlen(result); i >= 0; i--) {
if(result[i] == '/' || result[i] == '\\') {
//file has no extension
break;
}
if(result[i] == '.') {
result[i] = 0;
break;

View File

@@ -1,7 +1,5 @@
/*
audio.alsa (2008-08-12)
authors: Nach, RedDwarf
*/
//audio.alsa (2009-11-30)
//authors: BearOso, byuu, Nach, RedDwarf
#include <alsa/asoundlib.h>
@@ -77,6 +75,22 @@ public:
buffer.data[buffer.length++] = left + (right << 16);
if(buffer.length < device.period_size) return;
snd_pcm_sframes_t avail;
do {
avail = snd_pcm_avail_update(device.handle);
if(avail < 0) snd_pcm_recover(device.handle, avail, 1);
if(avail < buffer.length) {
if(settings.synchronize == false) {
buffer.length = 0;
return;
}
int error = snd_pcm_wait(device.handle, -1);
if(error < 0) snd_pcm_recover(device.handle, error, 1);
}
} while(avail < buffer.length);
//below code has issues with PulseAudio sound server
#if 0
if(settings.synchronize == false) {
snd_pcm_sframes_t avail = snd_pcm_avail_update(device.handle);
if(avail < device.period_size) {
@@ -84,6 +98,7 @@ public:
return;
}
}
#endif
uint32_t *buffer_ptr = buffer.data;
int i = 4;
@@ -114,12 +129,13 @@ public:
bool init() {
term();
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) {
term();
return false;
}
/* //below code will not work with 24khz frequency rate (ALSA library bug)
//below code will not work with 24khz frequency rate (ALSA library bug)
#if 0
if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED,
device.channels, settings.frequency, 1, settings.latency * 1000) < 0) {
//failed to set device parameters
@@ -129,7 +145,8 @@ public:
if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) {
device.period_size = settings.latency * 1000 * 1e-6 * settings.frequency / 4;
}*/
}
#endif
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;

View File

@@ -19,129 +19,126 @@ public:
bool acquired() { return false; }
bool poll(int16_t *table) {
memset(table, 0, nall::input_limit * sizeof(int16_t));
memset(table, 0, Scancode::Limit * sizeof(int16_t));
KeyMap keys;
GetKeys(keys);
uint8_t *keymap = (uint8_t*)keys;
#define map(id, name) table[keyboard<0>::name] = (bool)(keymap[id >> 3] & (1 << (id & 7)))
map(0x35, escape);
#define map(id, name) table[keyboard(0)[name]] = (bool)(keymap[id >> 3] & (1 << (id & 7)))
map(0x35, Keyboard::Escape);
map(0x7a, f1);
map(0x78, f2);
map(0x63, f3);
map(0x76, f4);
map(0x60, f5);
map(0x61, f6);
map(0x62, f7);
map(0x64, f8);
map(0x65, f9);
map(0x6d, f10);
map(0x67, f11);
//map(0x??, f12);
map(0x7a, Keyboard::F1);
map(0x78, Keyboard::F2);
map(0x63, Keyboard::F3);
map(0x76, Keyboard::F4);
map(0x60, Keyboard::F5);
map(0x61, Keyboard::F6);
map(0x62, Keyboard::F7);
map(0x64, Keyboard::F8);
map(0x65, Keyboard::F9);
map(0x6d, Keyboard::F10);
map(0x67, Keyboard::F11);
//map(0x??, Keyboard::F12);
map(0x69, print_screen);
//map(0x??, scroll_lock);
map(0x71, pause);
map(0x69, Keyboard::PrintScreen);
//map(0x??, Keyboard::ScrollLock);
map(0x71, Keyboard::Pause);
map(0x32, tilde);
map(0x12, num_1);
map(0x13, num_2);
map(0x14, num_3);
map(0x15, num_4);
map(0x17, num_5);
map(0x16, num_6);
map(0x1a, num_7);
map(0x1c, num_8);
map(0x19, num_9);
map(0x1d, num_0);
map(0x32, Keyboard::Tilde);
map(0x12, Keyboard::Num1);
map(0x13, Keyboard::Num2);
map(0x14, Keyboard::Num3);
map(0x15, Keyboard::Num4);
map(0x17, Keyboard::Num5);
map(0x16, Keyboard::Num6);
map(0x1a, Keyboard::Num7);
map(0x1c, Keyboard::Num8);
map(0x19, Keyboard::Num9);
map(0x1d, Keyboard::Num0);
map(0x1b, dash);
map(0x18, equal);
map(0x33, backspace);
map(0x1b, Keyboard::Dash);
map(0x18, Keyboard::Equal);
map(0x33, Keyboard::Backspace);
map(0x72, insert);
map(0x75, delete_);
map(0x73, home);
map(0x77, end);
map(0x74, page_up);
map(0x79, page_down);
map(0x72, Keyboard::Insert);
map(0x75, Keyboard::Delete);
map(0x73, Keyboard::Home);
map(0x77, Keyboard::End);
map(0x74, Keyboard::PageUp);
map(0x79, Keyboard::PageDown);
map(0x00, a);
map(0x0b, b);
map(0x08, c);
map(0x02, d);
map(0x0e, e);
map(0x03, f);
map(0x05, g);
map(0x04, h);
map(0x22, i);
map(0x26, j);
map(0x28, k);
map(0x25, l);
map(0x2e, m);
map(0x2d, n);
map(0x1f, o);
map(0x23, p);
map(0x0c, q);
map(0x0f, r);
map(0x01, s);
map(0x11, t);
map(0x20, u);
map(0x09, v);
map(0x0d, w);
map(0x07, x);
map(0x10, y);
map(0x06, z);
map(0x00, Keyboard::A);
map(0x0b, Keyboard::B);
map(0x08, Keyboard::C);
map(0x02, Keyboard::D);
map(0x0e, Keyboard::E);
map(0x03, Keyboard::F);
map(0x05, Keyboard::G);
map(0x04, Keyboard::H);
map(0x22, Keyboard::I);
map(0x26, Keyboard::J);
map(0x28, Keyboard::K);
map(0x25, Keyboard::L);
map(0x2e, Keyboard::M);
map(0x2d, Keyboard::N);
map(0x1f, Keyboard::O);
map(0x23, Keyboard::P);
map(0x0c, Keyboard::Q);
map(0x0f, Keyboard::R);
map(0x01, Keyboard::S);
map(0x11, Keyboard::T);
map(0x20, Keyboard::U);
map(0x09, Keyboard::V);
map(0x0d, Keyboard::W);
map(0x07, Keyboard::X);
map(0x10, Keyboard::Y);
map(0x06, Keyboard::Z);
map(0x21, lbracket);
map(0x1e, rbracket);
map(0x2a, backslash);
map(0x29, semicolon);
map(0x27, apostrophe);
map(0x2b, comma);
map(0x2f, period);
map(0x2c, slash);
map(0x21, Keyboard::LeftBracket);
map(0x1e, Keyboard::RightBracket);
map(0x2a, Keyboard::Backslash);
map(0x29, Keyboard::Semicolon);
map(0x27, Keyboard::Apostrophe);
map(0x2b, Keyboard::Comma);
map(0x2f, Keyboard::Period);
map(0x2c, Keyboard::Slash);
map(0x52, pad_0);
map(0x53, pad_1);
map(0x54, pad_2);
map(0x55, pad_3);
map(0x56, pad_4);
map(0x57, pad_5);
map(0x58, pad_6);
map(0x59, pad_7);
map(0x5b, pad_8);
map(0x5c, pad_9);
map(0x53, Keyboard::Keypad1);
map(0x54, Keyboard::Keypad2);
map(0x55, Keyboard::Keypad3);
map(0x56, Keyboard::Keypad4);
map(0x57, Keyboard::Keypad5);
map(0x58, Keyboard::Keypad6);
map(0x59, Keyboard::Keypad7);
map(0x5b, Keyboard::Keypad8);
map(0x5c, Keyboard::Keypad9);
map(0x52, Keyboard::Keypad0);
map(0x45, add);
map(0x4e, subtract);
map(0x43, multiply);
map(0x4b, divide);
map(0x4c, enter);
//map(0x??, Keyboard::Point);
map(0x4c, Keyboard::Enter);
map(0x45, Keyboard::Add);
map(0x4e, Keyboard::Subtract);
map(0x43, Keyboard::Multiply);
map(0x4b, Keyboard::Divide);
map(0x47, num_lock);
//map(0x39, caps_lock);
map(0x47, Keyboard::NumLock);
//map(0x39, Keyboard::CapsLock);
map(0x7e, up);
map(0x7d, down);
map(0x7b, left);
map(0x7c, right);
map(0x7e, Keyboard::Up);
map(0x7d, Keyboard::Down);
map(0x7b, Keyboard::Left);
map(0x7c, Keyboard::Right);
map(0x30, tab);
map(0x24, return_);
map(0x31, spacebar);
map(0x30, Keyboard::Tab);
map(0x24, Keyboard::Return);
map(0x31, Keyboard::Spacebar);
//map(0x??, Keyboard::Menu);
map(0x3b, lctrl);
//map(0x3b, rctrl);
map(0x3a, lalt);
//map(0x3a, ralt);
map(0x38, lshift);
//map(0x38, rshift);
map(0x37, lsuper);
//map(0x37, rsuper);
//map(0x??, menu);
map(0x38, Keyboard::Shift);
map(0x3b, Keyboard::Control);
map(0x3a, Keyboard::Alt);
map(0x37, Keyboard::Super);
#undef map
return true;

View File

@@ -14,7 +14,7 @@ public:
LPDIRECTINPUT8 context;
LPDIRECTINPUTDEVICE8 keyboard;
LPDIRECTINPUTDEVICE8 mouse;
LPDIRECTINPUTDEVICE8 gamepad[joypad<>::count];
LPDIRECTINPUTDEVICE8 gamepad[Joypad::Count];
bool mouseacquired;
} device;
@@ -45,7 +45,7 @@ public:
}
bool poll(int16_t *table) {
memset(table, 0, nall::input_limit * sizeof(int16_t));
memset(table, 0, Scancode::Limit * sizeof(int16_t));
//========
//Keyboard
@@ -60,122 +60,122 @@ public:
}
}
table[keyboard<0>::escape] = (bool)(state[0x01] & 0x80);
table[keyboard<0>::f1 ] = (bool)(state[0x3b] & 0x80);
table[keyboard<0>::f2 ] = (bool)(state[0x3c] & 0x80);
table[keyboard<0>::f3 ] = (bool)(state[0x3d] & 0x80);
table[keyboard<0>::f4 ] = (bool)(state[0x3e] & 0x80);
table[keyboard<0>::f5 ] = (bool)(state[0x3f] & 0x80);
table[keyboard<0>::f6 ] = (bool)(state[0x40] & 0x80);
table[keyboard<0>::f7 ] = (bool)(state[0x41] & 0x80);
table[keyboard<0>::f8 ] = (bool)(state[0x42] & 0x80);
table[keyboard<0>::f9 ] = (bool)(state[0x43] & 0x80);
table[keyboard<0>::f10 ] = (bool)(state[0x44] & 0x80);
table[keyboard<0>::f11 ] = (bool)(state[0x57] & 0x80);
table[keyboard<0>::f12 ] = (bool)(state[0x58] & 0x80);
#define key(id) table[keyboard(0)[id]]
table[keyboard<0>::print_screen] = (bool)(state[0xb7] & 0x80);
table[keyboard<0>::scroll_lock ] = (bool)(state[0x46] & 0x80);
table[keyboard<0>::pause ] = (bool)(state[0xc5] & 0x80);
table[keyboard<0>::tilde ] = (bool)(state[0x29] & 0x80);
key(Keyboard::Escape) = (bool)(state[0x01] & 0x80);
key(Keyboard::F1 ) = (bool)(state[0x3b] & 0x80);
key(Keyboard::F2 ) = (bool)(state[0x3c] & 0x80);
key(Keyboard::F3 ) = (bool)(state[0x3d] & 0x80);
key(Keyboard::F4 ) = (bool)(state[0x3e] & 0x80);
key(Keyboard::F5 ) = (bool)(state[0x3f] & 0x80);
key(Keyboard::F6 ) = (bool)(state[0x40] & 0x80);
key(Keyboard::F7 ) = (bool)(state[0x41] & 0x80);
key(Keyboard::F8 ) = (bool)(state[0x42] & 0x80);
key(Keyboard::F9 ) = (bool)(state[0x43] & 0x80);
key(Keyboard::F10 ) = (bool)(state[0x44] & 0x80);
key(Keyboard::F11 ) = (bool)(state[0x57] & 0x80);
key(Keyboard::F12 ) = (bool)(state[0x58] & 0x80);
table[keyboard<0>::num_1] = (bool)(state[0x02] & 0x80);
table[keyboard<0>::num_2] = (bool)(state[0x03] & 0x80);
table[keyboard<0>::num_3] = (bool)(state[0x04] & 0x80);
table[keyboard<0>::num_4] = (bool)(state[0x05] & 0x80);
table[keyboard<0>::num_5] = (bool)(state[0x06] & 0x80);
table[keyboard<0>::num_6] = (bool)(state[0x07] & 0x80);
table[keyboard<0>::num_7] = (bool)(state[0x08] & 0x80);
table[keyboard<0>::num_8] = (bool)(state[0x09] & 0x80);
table[keyboard<0>::num_9] = (bool)(state[0x0a] & 0x80);
table[keyboard<0>::num_0] = (bool)(state[0x0b] & 0x80);
key(Keyboard::PrintScreen) = (bool)(state[0xb7] & 0x80);
key(Keyboard::ScrollLock ) = (bool)(state[0x46] & 0x80);
key(Keyboard::Pause ) = (bool)(state[0xc5] & 0x80);
key(Keyboard::Tilde ) = (bool)(state[0x29] & 0x80);
table[keyboard<0>::dash ] = (bool)(state[0x0c] & 0x80);
table[keyboard<0>::equal ] = (bool)(state[0x0d] & 0x80);
table[keyboard<0>::backspace] = (bool)(state[0x0e] & 0x80);
key(Keyboard::Num1) = (bool)(state[0x02] & 0x80);
key(Keyboard::Num2) = (bool)(state[0x03] & 0x80);
key(Keyboard::Num3) = (bool)(state[0x04] & 0x80);
key(Keyboard::Num4) = (bool)(state[0x05] & 0x80);
key(Keyboard::Num5) = (bool)(state[0x06] & 0x80);
key(Keyboard::Num6) = (bool)(state[0x07] & 0x80);
key(Keyboard::Num7) = (bool)(state[0x08] & 0x80);
key(Keyboard::Num8) = (bool)(state[0x09] & 0x80);
key(Keyboard::Num9) = (bool)(state[0x0a] & 0x80);
key(Keyboard::Num0) = (bool)(state[0x0b] & 0x80);
table[keyboard<0>::insert ] = (bool)(state[0xd2] & 0x80);
table[keyboard<0>::delete_ ] = (bool)(state[0xd3] & 0x80);
table[keyboard<0>::home ] = (bool)(state[0xc7] & 0x80);
table[keyboard<0>::end ] = (bool)(state[0xcf] & 0x80);
table[keyboard<0>::page_up ] = (bool)(state[0xc9] & 0x80);
table[keyboard<0>::page_down] = (bool)(state[0xd1] & 0x80);
key(Keyboard::Dash ) = (bool)(state[0x0c] & 0x80);
key(Keyboard::Equal ) = (bool)(state[0x0d] & 0x80);
key(Keyboard::Backspace) = (bool)(state[0x0e] & 0x80);
table[keyboard<0>::a] = (bool)(state[0x1e] & 0x80);
table[keyboard<0>::b] = (bool)(state[0x30] & 0x80);
table[keyboard<0>::c] = (bool)(state[0x2e] & 0x80);
table[keyboard<0>::d] = (bool)(state[0x20] & 0x80);
table[keyboard<0>::e] = (bool)(state[0x12] & 0x80);
table[keyboard<0>::f] = (bool)(state[0x21] & 0x80);
table[keyboard<0>::g] = (bool)(state[0x22] & 0x80);
table[keyboard<0>::h] = (bool)(state[0x23] & 0x80);
table[keyboard<0>::i] = (bool)(state[0x17] & 0x80);
table[keyboard<0>::j] = (bool)(state[0x24] & 0x80);
table[keyboard<0>::k] = (bool)(state[0x25] & 0x80);
table[keyboard<0>::l] = (bool)(state[0x26] & 0x80);
table[keyboard<0>::m] = (bool)(state[0x32] & 0x80);
table[keyboard<0>::n] = (bool)(state[0x31] & 0x80);
table[keyboard<0>::o] = (bool)(state[0x18] & 0x80);
table[keyboard<0>::p] = (bool)(state[0x19] & 0x80);
table[keyboard<0>::q] = (bool)(state[0x10] & 0x80);
table[keyboard<0>::r] = (bool)(state[0x13] & 0x80);
table[keyboard<0>::s] = (bool)(state[0x1f] & 0x80);
table[keyboard<0>::t] = (bool)(state[0x14] & 0x80);
table[keyboard<0>::u] = (bool)(state[0x16] & 0x80);
table[keyboard<0>::v] = (bool)(state[0x2f] & 0x80);
table[keyboard<0>::w] = (bool)(state[0x11] & 0x80);
table[keyboard<0>::x] = (bool)(state[0x2d] & 0x80);
table[keyboard<0>::y] = (bool)(state[0x15] & 0x80);
table[keyboard<0>::z] = (bool)(state[0x2c] & 0x80);
key(Keyboard::Insert ) = (bool)(state[0xd2] & 0x80);
key(Keyboard::Delete ) = (bool)(state[0xd3] & 0x80);
key(Keyboard::Home ) = (bool)(state[0xc7] & 0x80);
key(Keyboard::End ) = (bool)(state[0xcf] & 0x80);
key(Keyboard::PageUp ) = (bool)(state[0xc9] & 0x80);
key(Keyboard::PageDown) = (bool)(state[0xd1] & 0x80);
table[keyboard<0>::lbracket ] = (bool)(state[0x1a] & 0x80);
table[keyboard<0>::rbracket ] = (bool)(state[0x1b] & 0x80);
table[keyboard<0>::backslash ] = (bool)(state[0x2b] & 0x80);
table[keyboard<0>::semicolon ] = (bool)(state[0x27] & 0x80);
table[keyboard<0>::apostrophe] = (bool)(state[0x28] & 0x80);
table[keyboard<0>::comma ] = (bool)(state[0x33] & 0x80);
table[keyboard<0>::period ] = (bool)(state[0x34] & 0x80);
table[keyboard<0>::slash ] = (bool)(state[0x35] & 0x80);
key(Keyboard::A) = (bool)(state[0x1e] & 0x80);
key(Keyboard::B) = (bool)(state[0x30] & 0x80);
key(Keyboard::C) = (bool)(state[0x2e] & 0x80);
key(Keyboard::D) = (bool)(state[0x20] & 0x80);
key(Keyboard::E) = (bool)(state[0x12] & 0x80);
key(Keyboard::F) = (bool)(state[0x21] & 0x80);
key(Keyboard::G) = (bool)(state[0x22] & 0x80);
key(Keyboard::H) = (bool)(state[0x23] & 0x80);
key(Keyboard::I) = (bool)(state[0x17] & 0x80);
key(Keyboard::J) = (bool)(state[0x24] & 0x80);
key(Keyboard::K) = (bool)(state[0x25] & 0x80);
key(Keyboard::L) = (bool)(state[0x26] & 0x80);
key(Keyboard::M) = (bool)(state[0x32] & 0x80);
key(Keyboard::N) = (bool)(state[0x31] & 0x80);
key(Keyboard::O) = (bool)(state[0x18] & 0x80);
key(Keyboard::P) = (bool)(state[0x19] & 0x80);
key(Keyboard::Q) = (bool)(state[0x10] & 0x80);
key(Keyboard::R) = (bool)(state[0x13] & 0x80);
key(Keyboard::S) = (bool)(state[0x1f] & 0x80);
key(Keyboard::T) = (bool)(state[0x14] & 0x80);
key(Keyboard::U) = (bool)(state[0x16] & 0x80);
key(Keyboard::V) = (bool)(state[0x2f] & 0x80);
key(Keyboard::W) = (bool)(state[0x11] & 0x80);
key(Keyboard::X) = (bool)(state[0x2d] & 0x80);
key(Keyboard::Y) = (bool)(state[0x15] & 0x80);
key(Keyboard::Z) = (bool)(state[0x2c] & 0x80);
table[keyboard<0>::pad_0] = (bool)(state[0x4f] & 0x80);
table[keyboard<0>::pad_1] = (bool)(state[0x50] & 0x80);
table[keyboard<0>::pad_2] = (bool)(state[0x51] & 0x80);
table[keyboard<0>::pad_3] = (bool)(state[0x4b] & 0x80);
table[keyboard<0>::pad_4] = (bool)(state[0x4c] & 0x80);
table[keyboard<0>::pad_5] = (bool)(state[0x4d] & 0x80);
table[keyboard<0>::pad_6] = (bool)(state[0x47] & 0x80);
table[keyboard<0>::pad_7] = (bool)(state[0x48] & 0x80);
table[keyboard<0>::pad_8] = (bool)(state[0x49] & 0x80);
table[keyboard<0>::pad_9] = (bool)(state[0x52] & 0x80);
table[keyboard<0>::point] = (bool)(state[0x53] & 0x80);
key(Keyboard::LeftBracket ) = (bool)(state[0x1a] & 0x80);
key(Keyboard::RightBracket) = (bool)(state[0x1b] & 0x80);
key(Keyboard::Backslash ) = (bool)(state[0x2b] & 0x80);
key(Keyboard::Semicolon ) = (bool)(state[0x27] & 0x80);
key(Keyboard::Apostrophe ) = (bool)(state[0x28] & 0x80);
key(Keyboard::Comma ) = (bool)(state[0x33] & 0x80);
key(Keyboard::Period ) = (bool)(state[0x34] & 0x80);
key(Keyboard::Slash ) = (bool)(state[0x35] & 0x80);
table[keyboard<0>::add] = (bool)(state[0x4e] & 0x80);
table[keyboard<0>::subtract] = (bool)(state[0x4a] & 0x80);
table[keyboard<0>::multiply] = (bool)(state[0x37] & 0x80);
table[keyboard<0>::divide] = (bool)(state[0xb5] & 0x80);
table[keyboard<0>::enter] = (bool)(state[0x9c] & 0x80);
key(Keyboard::Keypad0) = (bool)(state[0x4f] & 0x80);
key(Keyboard::Keypad1) = (bool)(state[0x50] & 0x80);
key(Keyboard::Keypad2) = (bool)(state[0x51] & 0x80);
key(Keyboard::Keypad3) = (bool)(state[0x4b] & 0x80);
key(Keyboard::Keypad4) = (bool)(state[0x4c] & 0x80);
key(Keyboard::Keypad5) = (bool)(state[0x4d] & 0x80);
key(Keyboard::Keypad6) = (bool)(state[0x47] & 0x80);
key(Keyboard::Keypad7) = (bool)(state[0x48] & 0x80);
key(Keyboard::Keypad8) = (bool)(state[0x49] & 0x80);
key(Keyboard::Keypad9) = (bool)(state[0x52] & 0x80);
key(Keyboard::Point ) = (bool)(state[0x53] & 0x80);
table[keyboard<0>::num_lock ] = (bool)(state[0x45] & 0x80);
table[keyboard<0>::caps_lock] = (bool)(state[0x3a] & 0x80);
key(Keyboard::Add ) = (bool)(state[0x4e] & 0x80);
key(Keyboard::Subtract) = (bool)(state[0x4a] & 0x80);
key(Keyboard::Multiply) = (bool)(state[0x37] & 0x80);
key(Keyboard::Divide ) = (bool)(state[0xb5] & 0x80);
key(Keyboard::Enter ) = (bool)(state[0x9c] & 0x80);
table[keyboard<0>::up ] = (bool)(state[0xc8] & 0x80);
table[keyboard<0>::down ] = (bool)(state[0xd0] & 0x80);
table[keyboard<0>::left ] = (bool)(state[0xcb] & 0x80);
table[keyboard<0>::right] = (bool)(state[0xcd] & 0x80);
key(Keyboard::NumLock ) = (bool)(state[0x45] & 0x80);
key(Keyboard::CapsLock) = (bool)(state[0x3a] & 0x80);
table[keyboard<0>::tab ] = (bool)(state[0x0f] & 0x80);
table[keyboard<0>::return_ ] = (bool)(state[0x1c] & 0x80);
table[keyboard<0>::spacebar] = (bool)(state[0x39] & 0x80);
key(Keyboard::Up ) = (bool)(state[0xc8] & 0x80);
key(Keyboard::Down ) = (bool)(state[0xd0] & 0x80);
key(Keyboard::Left ) = (bool)(state[0xcb] & 0x80);
key(Keyboard::Right) = (bool)(state[0xcd] & 0x80);
table[keyboard<0>::lctrl ] = (bool)(state[0x1d] & 0x80);
table[keyboard<0>::rctrl ] = (bool)(state[0x9d] & 0x80);
table[keyboard<0>::lalt ] = (bool)(state[0x38] & 0x80);
table[keyboard<0>::ralt ] = (bool)(state[0xb8] & 0x80);
table[keyboard<0>::lshift] = (bool)(state[0x2a] & 0x80);
table[keyboard<0>::rshift] = (bool)(state[0x36] & 0x80);
table[keyboard<0>::lsuper] = (bool)(state[0xdb] & 0x80);
table[keyboard<0>::rsuper] = (bool)(state[0xdc] & 0x80);
table[keyboard<0>::menu ] = (bool)(state[0xdd] & 0x80);
key(Keyboard::Tab ) = (bool)(state[0x0f] & 0x80);
key(Keyboard::Return ) = (bool)(state[0x1c] & 0x80);
key(Keyboard::Spacebar) = (bool)(state[0x39] & 0x80);
key(Keyboard::Menu ) = (bool)(state[0xdd] & 0x80);
key(Keyboard::Shift ) = (bool)(state[0x2a] & 0x80) || (bool)(state[0x36] & 0x80);
key(Keyboard::Control) = (bool)(state[0x1d] & 0x80) || (bool)(state[0x9d] & 0x80);
key(Keyboard::Alt ) = (bool)(state[0x38] & 0x80) || (bool)(state[0xb8] & 0x80);
key(Keyboard::Super ) = (bool)(state[0xdb] & 0x80) || (bool)(state[0xdc] & 0x80);
#undef key
}
//=====
@@ -191,27 +191,26 @@ public:
}
}
table[mouse<0>::x] = state.lX;
table[mouse<0>::y] = state.lY;
table[mouse<0>::z] = state.lZ / WHEEL_DELTA;
for(unsigned n = 0; n < mouse<>::buttons; n++) {
table[mouse<0>::button + n] = (bool)state.rgbButtons[n];
table[mouse(0).axis(0)] = state.lX;
table[mouse(0).axis(1)] = state.lY;
table[mouse(0).axis(2)] = state.lZ / WHEEL_DELTA;
for(unsigned n = 0; n < Mouse::Buttons; n++) {
table[mouse(0).button(n)] = (bool)state.rgbButtons[n];
}
//on Windows, 0 = left, 1 = right, 2 = middle
//swap middle and right buttons for consistency with Linux
int16_t temp = table[mouse<0>::button + 1];
table[mouse<0>::button + 1] = table[mouse<0>::button + 2];
table[mouse<0>::button + 2] = temp;
int16_t temp = table[mouse(0).button(1)];
table[mouse(0).button(1)] = table[mouse(0).button(2)];
table[mouse(0).button(2)] = temp;
}
//=========
//Joypad(s)
//=========
for(unsigned i = 0; i < joypad<>::count; i++) {
for(unsigned i = 0; i < Joypad::Count; i++) {
if(!device.gamepad[i]) continue;
unsigned index = joypad<>::index(i, joypad<>::none);
if(FAILED(device.gamepad[i]->Poll())) {
device.gamepad[i]->Acquire();
@@ -222,30 +221,30 @@ public:
device.gamepad[i]->GetDeviceState(sizeof(DIJOYSTATE2), &state);
//POV hats
for(unsigned n = 0; n < min((unsigned)joypad<>::hats, 4); n++) {
for(unsigned n = 0; n < min((unsigned)Joypad::Hats, 4); n++) {
//POV value is in clockwise-hundredth degree units.
unsigned pov = state.rgdwPOV[n];
//some drivers report a centered POV hat as -1U, others as 65535U.
//>= 36000 will match both, as well as invalid ranges.
if(pov < 36000) {
if(pov >= 31500 || pov <= 4500) table[index + joypad<>::hat + n] |= joypad<>::hat_up;
if(pov >= 4500 && pov <= 13500) table[index + joypad<>::hat + n] |= joypad<>::hat_right;
if(pov >= 13500 && pov <= 22500) table[index + joypad<>::hat + n] |= joypad<>::hat_down;
if(pov >= 22500 && pov <= 31500) table[index + joypad<>::hat + n] |= joypad<>::hat_left;
if(pov >= 31500 || pov <= 4500) table[joypad(i).hat(n)] |= Joypad::HatUp;
if(pov >= 4500 && pov <= 13500) table[joypad(i).hat(n)] |= Joypad::HatRight;
if(pov >= 13500 && pov <= 22500) table[joypad(i).hat(n)] |= Joypad::HatDown;
if(pov >= 22500 && pov <= 31500) table[joypad(i).hat(n)] |= Joypad::HatLeft;
}
}
//axes
table[index + joypad<>::axis + 0] = state.lX;
table[index + joypad<>::axis + 1] = state.lY;
table[index + joypad<>::axis + 2] = state.lZ;
table[index + joypad<>::axis + 3] = state.lRx;
table[index + joypad<>::axis + 4] = state.lRy;
table[index + joypad<>::axis + 5] = state.lRz;
table[joypad(i).axis(0)] = state.lX;
table[joypad(i).axis(1)] = state.lY;
table[joypad(i).axis(2)] = state.lZ;
table[joypad(i).axis(3)] = state.lRx;
table[joypad(i).axis(4)] = state.lRy;
table[joypad(i).axis(5)] = state.lRz;
//buttons
for(unsigned n = 0; n < min((unsigned)joypad<>::buttons, 128); n++) {
table[index + joypad<>::button + n] = (bool)state.rgbButtons[n];
for(unsigned n = 0; n < min((unsigned)Joypad::Buttons, 128); n++) {
table[joypad(i).button(n)] = (bool)state.rgbButtons[n];
}
}
@@ -254,8 +253,8 @@ public:
bool init_joypad(const DIDEVICEINSTANCE *instance) {
unsigned n;
for(n = 0; n < joypad<>::count; n++) { if(!device.gamepad[n]) break; }
if(n >= joypad<>::count) return DIENUM_STOP;
for(n = 0; n < Joypad::Count; n++) { if(!device.gamepad[n]) break; }
if(n >= Joypad::Count) return DIENUM_STOP;
if(FAILED(device.context->CreateDevice(instance->guidInstance, &device.gamepad[n], 0))) {
return DIENUM_CONTINUE; //continue and try next gamepad
@@ -270,7 +269,7 @@ public:
bool init_axis(const DIDEVICEOBJECTINSTANCE *instance) {
signed n;
for(n = joypad<>::count - 1; n >= 0; n--) { if(device.gamepad[n]) break; }
for(n = Joypad::Count - 1; n >= 0; n--) { if(device.gamepad[n]) break; }
if(n < 0) return DIENUM_STOP;
DIPROPRANGE range;
@@ -289,7 +288,7 @@ public:
device.context = 0;
device.keyboard = 0;
device.mouse = 0;
for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0;
device.mouseacquired = false;
DirectInput8Create(GetModuleHandle(0), 0x0800, IID_IDirectInput8, (void**)&device.context, 0);
@@ -322,7 +321,7 @@ public:
device.mouse = 0;
}
for(unsigned i = 0; i < joypad<>::count; i++) {
for(unsigned i = 0; i < Joypad::Count; i++) {
if(device.gamepad[i]) {
device.gamepad[i]->Unacquire();
device.gamepad[i]->Release();
@@ -366,7 +365,7 @@ public:
device.context = 0;
device.keyboard = 0;
device.mouse = 0;
for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0;
device.mouseacquired = false;
settings.handle = 0;

View File

@@ -39,139 +39,151 @@ public:
};
struct Keyboard : Device {
bool state[keyboard<>::length];
bool state[nall::Keyboard::Size];
void update(RAWINPUT *input) {
unsigned code = input->data.keyboard.MakeCode;
unsigned flags = input->data.keyboard.Flags;
#define map(id, flag, name) if(code == id) state[name] = (bool)(flags == flag);
map(0x0001, 0, keyboard<>::escape)
map(0x003b, 0, keyboard<>::f1)
map(0x003c, 0, keyboard<>::f2)
map(0x003d, 0, keyboard<>::f3)
map(0x003e, 0, keyboard<>::f4)
map(0x003f, 0, keyboard<>::f5)
map(0x0040, 0, keyboard<>::f6)
map(0x0041, 0, keyboard<>::f7)
map(0x0042, 0, keyboard<>::f8)
map(0x0043, 0, keyboard<>::f9)
map(0x0044, 0, keyboard<>::f10)
map(0x0057, 0, keyboard<>::f11)
map(0x0058, 0, keyboard<>::f12)
map(0x0001, 0, nall::Keyboard::Escape)
map(0x003b, 0, nall::Keyboard::F1)
map(0x003c, 0, nall::Keyboard::F2)
map(0x003d, 0, nall::Keyboard::F3)
map(0x003e, 0, nall::Keyboard::F4)
map(0x003f, 0, nall::Keyboard::F5)
map(0x0040, 0, nall::Keyboard::F6)
map(0x0041, 0, nall::Keyboard::F7)
map(0x0042, 0, nall::Keyboard::F8)
map(0x0043, 0, nall::Keyboard::F9)
map(0x0044, 0, nall::Keyboard::F10)
map(0x0057, 0, nall::Keyboard::F11)
map(0x0058, 0, nall::Keyboard::F12)
map(0x0037, 2, keyboard<>::print_screen)
map(0x0046, 0, keyboard<>::scroll_lock)
map(0x001d, 4, keyboard<>::pause)
map(0x0029, 0, keyboard<>::tilde)
map(0x0037, 2, nall::Keyboard::PrintScreen)
map(0x0046, 0, nall::Keyboard::ScrollLock)
map(0x001d, 4, nall::Keyboard::Pause)
map(0x0029, 0, nall::Keyboard::Tilde)
map(0x0002, 0, keyboard<>::num_1)
map(0x0003, 0, keyboard<>::num_2)
map(0x0004, 0, keyboard<>::num_3)
map(0x0005, 0, keyboard<>::num_4)
map(0x0006, 0, keyboard<>::num_5)
map(0x0007, 0, keyboard<>::num_6)
map(0x0008, 0, keyboard<>::num_7)
map(0x0009, 0, keyboard<>::num_8)
map(0x000a, 0, keyboard<>::num_9)
map(0x000b, 0, keyboard<>::num_0)
map(0x0002, 0, nall::Keyboard::Num1)
map(0x0003, 0, nall::Keyboard::Num2)
map(0x0004, 0, nall::Keyboard::Num3)
map(0x0005, 0, nall::Keyboard::Num4)
map(0x0006, 0, nall::Keyboard::Num5)
map(0x0007, 0, nall::Keyboard::Num6)
map(0x0008, 0, nall::Keyboard::Num7)
map(0x0009, 0, nall::Keyboard::Num8)
map(0x000a, 0, nall::Keyboard::Num9)
map(0x000b, 0, nall::Keyboard::Num0)
map(0x000c, 0, keyboard<>::dash)
map(0x000d, 0, keyboard<>::equal)
map(0x000e, 0, keyboard<>::backspace)
map(0x000c, 0, nall::Keyboard::Dash)
map(0x000d, 0, nall::Keyboard::Equal)
map(0x000e, 0, nall::Keyboard::Backspace)
map(0x0052, 2, keyboard<>::insert)
map(0x0053, 2, keyboard<>::delete_)
map(0x0047, 2, keyboard<>::home)
map(0x004f, 2, keyboard<>::end)
map(0x0049, 2, keyboard<>::page_up)
map(0x0051, 2, keyboard<>::page_down)
map(0x0052, 2, nall::Keyboard::Insert)
map(0x0053, 2, nall::Keyboard::Delete)
map(0x0047, 2, nall::Keyboard::Home)
map(0x004f, 2, nall::Keyboard::End)
map(0x0049, 2, nall::Keyboard::PageUp)
map(0x0051, 2, nall::Keyboard::PageDown)
map(0x001e, 0, keyboard<>::a)
map(0x0030, 0, keyboard<>::b)
map(0x002e, 0, keyboard<>::c)
map(0x0020, 0, keyboard<>::d)
map(0x0012, 0, keyboard<>::e)
map(0x0021, 0, keyboard<>::f)
map(0x0022, 0, keyboard<>::g)
map(0x0023, 0, keyboard<>::h)
map(0x0017, 0, keyboard<>::i)
map(0x0024, 0, keyboard<>::j)
map(0x0025, 0, keyboard<>::k)
map(0x0026, 0, keyboard<>::l)
map(0x0032, 0, keyboard<>::m)
map(0x0031, 0, keyboard<>::n)
map(0x0018, 0, keyboard<>::o)
map(0x0019, 0, keyboard<>::p)
map(0x0010, 0, keyboard<>::q)
map(0x0013, 0, keyboard<>::r)
map(0x001f, 0, keyboard<>::s)
map(0x0014, 0, keyboard<>::t)
map(0x0016, 0, keyboard<>::u)
map(0x002f, 0, keyboard<>::v)
map(0x0011, 0, keyboard<>::w)
map(0x002d, 0, keyboard<>::x)
map(0x0015, 0, keyboard<>::y)
map(0x002c, 0, keyboard<>::z)
map(0x001e, 0, nall::Keyboard::A)
map(0x0030, 0, nall::Keyboard::B)
map(0x002e, 0, nall::Keyboard::C)
map(0x0020, 0, nall::Keyboard::D)
map(0x0012, 0, nall::Keyboard::E)
map(0x0021, 0, nall::Keyboard::F)
map(0x0022, 0, nall::Keyboard::G)
map(0x0023, 0, nall::Keyboard::H)
map(0x0017, 0, nall::Keyboard::I)
map(0x0024, 0, nall::Keyboard::J)
map(0x0025, 0, nall::Keyboard::K)
map(0x0026, 0, nall::Keyboard::L)
map(0x0032, 0, nall::Keyboard::M)
map(0x0031, 0, nall::Keyboard::N)
map(0x0018, 0, nall::Keyboard::O)
map(0x0019, 0, nall::Keyboard::P)
map(0x0010, 0, nall::Keyboard::Q)
map(0x0013, 0, nall::Keyboard::R)
map(0x001f, 0, nall::Keyboard::S)
map(0x0014, 0, nall::Keyboard::T)
map(0x0016, 0, nall::Keyboard::U)
map(0x002f, 0, nall::Keyboard::V)
map(0x0011, 0, nall::Keyboard::W)
map(0x002d, 0, nall::Keyboard::X)
map(0x0015, 0, nall::Keyboard::Y)
map(0x002c, 0, nall::Keyboard::Z)
map(0x001a, 0, keyboard<>::lbracket)
map(0x001b, 0, keyboard<>::rbracket)
map(0x002b, 0, keyboard<>::backslash)
map(0x0027, 0, keyboard<>::semicolon)
map(0x0028, 0, keyboard<>::apostrophe)
map(0x0033, 0, keyboard<>::comma)
map(0x0034, 0, keyboard<>::period)
map(0x0035, 0, keyboard<>::slash)
map(0x001a, 0, nall::Keyboard::LeftBracket)
map(0x001b, 0, nall::Keyboard::RightBracket)
map(0x002b, 0, nall::Keyboard::Backslash)
map(0x0027, 0, nall::Keyboard::Semicolon)
map(0x0028, 0, nall::Keyboard::Apostrophe)
map(0x0033, 0, nall::Keyboard::Comma)
map(0x0034, 0, nall::Keyboard::Period)
map(0x0035, 0, nall::Keyboard::Slash)
map(0x004f, 0, keyboard<>::pad_1)
map(0x0050, 0, keyboard<>::pad_2)
map(0x0051, 0, keyboard<>::pad_3)
map(0x004b, 0, keyboard<>::pad_4)
map(0x004c, 0, keyboard<>::pad_5)
map(0x004d, 0, keyboard<>::pad_6)
map(0x0047, 0, keyboard<>::pad_7)
map(0x0048, 0, keyboard<>::pad_8)
map(0x0049, 0, keyboard<>::pad_9)
map(0x0052, 0, keyboard<>::pad_0)
map(0x004f, 0, nall::Keyboard::Keypad1)
map(0x0050, 0, nall::Keyboard::Keypad2)
map(0x0051, 0, nall::Keyboard::Keypad3)
map(0x004b, 0, nall::Keyboard::Keypad4)
map(0x004c, 0, nall::Keyboard::Keypad5)
map(0x004d, 0, nall::Keyboard::Keypad6)
map(0x0047, 0, nall::Keyboard::Keypad7)
map(0x0048, 0, nall::Keyboard::Keypad8)
map(0x0049, 0, nall::Keyboard::Keypad9)
map(0x0052, 0, nall::Keyboard::Keypad0)
map(0x0053, 0, keyboard<>::point)
map(0x001c, 2, keyboard<>::enter)
map(0x004e, 0, keyboard<>::add)
map(0x004a, 0, keyboard<>::subtract)
map(0x0037, 0, keyboard<>::multiply)
map(0x0035, 2, keyboard<>::divide)
map(0x0053, 0, nall::Keyboard::Point)
map(0x001c, 2, nall::Keyboard::Enter)
map(0x004e, 0, nall::Keyboard::Add)
map(0x004a, 0, nall::Keyboard::Subtract)
map(0x0037, 0, nall::Keyboard::Multiply)
map(0x0035, 2, nall::Keyboard::Divide)
map(0x0045, 0, keyboard<>::num_lock)
map(0x003a, 0, keyboard<>::caps_lock)
map(0x0045, 0, nall::Keyboard::NumLock)
map(0x003a, 0, nall::Keyboard::CapsLock)
//pause signals 0x1d:4 + 0x45:0, whereas num_lock signals only 0x45:0.
//this makes it impractical to detect both pause+num_lock independently.
//workaround: always detect pause; detect num_lock only when pause is released.
if(state[keyboard<>::pause]) state[keyboard<>::num_lock] = false;
//Pause signals 0x1d:4 + 0x45:0, whereas NumLock signals only 0x45:0.
//this makes it impractical to detect both Pause+NumLock independently.
//workaround: always detect Pause; detect NumLock only when Pause is released.
if(state[nall::Keyboard::Pause]) state[nall::Keyboard::NumLock] = false;
map(0x0048, 2, keyboard<>::up)
map(0x0050, 2, keyboard<>::down)
map(0x004b, 2, keyboard<>::left)
map(0x004d, 2, keyboard<>::right)
map(0x0048, 2, nall::Keyboard::Up)
map(0x0050, 2, nall::Keyboard::Down)
map(0x004b, 2, nall::Keyboard::Left)
map(0x004d, 2, nall::Keyboard::Right)
map(0x000f, 0, keyboard<>::tab)
map(0x001c, 0, keyboard<>::return_)
map(0x0039, 0, keyboard<>::spacebar)
map(0x000f, 0, nall::Keyboard::Tab)
map(0x001c, 0, nall::Keyboard::Return)
map(0x0039, 0, nall::Keyboard::Spacebar)
map(0x005d, 2, nall::Keyboard::Menu)
map(0x001d, 0, keyboard<>::lctrl)
map(0x001d, 2, keyboard<>::rctrl)
map(0x0038, 0, keyboard<>::lalt)
map(0x0038, 2, keyboard<>::ralt)
map(0x002a, 0, keyboard<>::lshift)
map(0x0036, 0, keyboard<>::rshift)
map(0x005b, 2, keyboard<>::lsuper)
map(0x005c, 2, keyboard<>::rsuper)
map(0x005d, 2, keyboard<>::menu)
//merge left and right modifiers to one ID
if(code == 0x002a && flags == 0) state[nall::Keyboard::Shift] = 1; //left shift
if(code == 0x002a && flags == 1) state[nall::Keyboard::Shift] = 0;
if(code == 0x0036 && flags == 0) state[nall::Keyboard::Shift] = 1; //right shift
if(code == 0x0036 && flags == 1) state[nall::Keyboard::Shift] = 0;
if(code == 0x001d && flags == 0) state[nall::Keyboard::Control] = 1; //left control
if(code == 0x001d && flags == 1) state[nall::Keyboard::Control] = 0;
if(code == 0x001d && flags == 2) state[nall::Keyboard::Control] = 1; //right control
if(code == 0x001d && flags == 3) state[nall::Keyboard::Control] = 0;
if(code == 0x0038 && flags == 0) state[nall::Keyboard::Alt] = 1; //left alt
if(code == 0x0038 && flags == 1) state[nall::Keyboard::Alt] = 0;
if(code == 0x0038 && flags == 2) state[nall::Keyboard::Alt] = 1; //right alt
if(code == 0x0038 && flags == 3) state[nall::Keyboard::Alt] = 0;
if(code == 0x005b && flags == 2) state[nall::Keyboard::Super] = 1; //left super
if(code == 0x005b && flags == 3) state[nall::Keyboard::Super] = 0;
if(code == 0x005c && flags == 2) state[nall::Keyboard::Super] = 1; //right super
if(code == 0x005c && flags == 3) state[nall::Keyboard::Super] = 0;
#undef map
}
Keyboard() {
for(unsigned i = 0; i < keyboard<>::length; i++) state[i] = false;
for(unsigned i = 0; i < nall::Keyboard::Size; i++) state[i] = false;
}
};
@@ -390,11 +402,11 @@ public:
bool button[10];
void poll(XINPUT_STATE &state) {
hat = joypad<>::hat_center;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hat |= joypad<>::hat_up;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= joypad<>::hat_right;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hat |= joypad<>::hat_down;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hat |= joypad<>::hat_left;
hat = Joypad::HatCenter;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ) hat |= Joypad::HatUp;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) hat |= Joypad::HatRight;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ) hat |= Joypad::HatDown;
if(state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ) hat |= Joypad::HatLeft;
axis[0] = (int16_t)state.Gamepad.sThumbLX;
axis[1] = (int16_t)state.Gamepad.sThumbLY;
@@ -426,7 +438,7 @@ public:
}
Gamepad() {
hat = joypad<>::hat_center;
hat = Joypad::HatCenter;
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
for(unsigned n = 0; n < 10; n++) button[n] = false;
}
@@ -490,7 +502,7 @@ public:
void poll(DIJOYSTATE2 &state) {
//POV hats
for(unsigned n = 0; n < 4; n++) {
hat[n] = joypad<>::hat_center;
hat[n] = Joypad::HatCenter;
//POV value is in clockwise-hundredth degree units
unsigned pov = state.rgdwPOV[n];
@@ -499,10 +511,10 @@ public:
//>= 36000 will match both, as well as invalid ranges.
if(pov >= 36000) continue;
if(pov >= 31500 || pov <= 4500) hat[n] |= joypad<>::hat_up;
if(pov >= 4500 && pov <= 13500) hat[n] |= joypad<>::hat_right;
if(pov >= 13500 && pov <= 22500) hat[n] |= joypad<>::hat_down;
if(pov >= 22500 && pov <= 31500) hat[n] |= joypad<>::hat_left;
if(pov >= 31500 || pov <= 4500) hat[n] |= Joypad::HatUp;
if(pov >= 4500 && pov <= 13500) hat[n] |= Joypad::HatRight;
if(pov >= 13500 && pov <= 22500) hat[n] |= Joypad::HatDown;
if(pov >= 22500 && pov <= 31500) hat[n] |= Joypad::HatLeft;
}
//axes
@@ -521,7 +533,7 @@ public:
Gamepad() {
handle = 0;
for(unsigned n = 0; n < 4; n++) hat[n] = joypad<>::hat_center;
for(unsigned n = 0; n < 4; n++) hat[n] = Joypad::HatCenter;
for(unsigned n = 0; n < 6; n++) axis[n] = 0;
for(unsigned n = 0; n < 128; n++) button[n] = false;
}
@@ -672,33 +684,29 @@ public:
}
bool poll(int16_t *table) {
memset(table, 0, nall::input_limit * sizeof(int16_t));
memset(table, 0, Scancode::Limit * sizeof(int16_t));
WaitForSingleObject(rawinput.mutex, INFINITE);
//=========
//Keyboards
//=========
for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)keyboard<>::count); i++) {
unsigned index = keyboard<>::index(i, keyboard<>::none);
for(unsigned n = 0; n < keyboard<>::length; n++) {
table[index + n] = rawinput.lkeyboard[i].state[n];
for(unsigned i = 0; i < min(rawinput.lkeyboard.size(), (unsigned)Keyboard::Count); i++) {
for(unsigned n = 0; n < nall::Keyboard::Size; n++) {
table[keyboard(i).key(n)] = rawinput.lkeyboard[i].state[n];
}
}
//====
//Mice
//====
for(unsigned i = 0; i < min(rawinput.lmouse.size(), (unsigned)mouse<>::count); i++) {
unsigned index = mouse<>::index(i, mouse<>::none);
for(unsigned i = 0; i < min(rawinput.lmouse.size(), (unsigned)Mouse::Count); i++) {
table[mouse(i).axis(0)] = rawinput.lmouse[i].xDistance;
table[mouse(i).axis(1)] = rawinput.lmouse[i].yDistance;
table[mouse(i).axis(2)] = rawinput.lmouse[i].zDistance;
table[index + mouse<>::x] = rawinput.lmouse[i].xDistance;
table[index + mouse<>::y] = rawinput.lmouse[i].yDistance;
table[index + mouse<>::z] = rawinput.lmouse[i].zDistance;
for(unsigned n = 0; n < min(5U, (unsigned)mouse<>::buttons); n++) {
table[index + mouse<>::button + n] = (bool)(rawinput.lmouse[i].buttonState & (1 << n));
for(unsigned n = 0; n < min(5U, (unsigned)Mouse::Buttons); n++) {
table[mouse(i).button(n)] = (bool)(rawinput.lmouse[i].buttonState & (1 << n));
}
rawinput.lmouse[i].sync();
@@ -713,17 +721,16 @@ public:
//==================
xinput.poll();
for(unsigned i = 0; i < xinput.lgamepad.size(); i++) {
if(joy >= joypad<>::count) break;
unsigned index = joypad<>::index(joy++, joypad<>::none);
if(joy >= Joypad::Count) break;
table[index + joypad<>::hat + 0] = xinput.lgamepad[i].hat;
table[joypad(i).hat(0)] = xinput.lgamepad[i].hat;
for(unsigned axis = 0; axis < min(6U, (unsigned)joypad<>::axes); axis++) {
table[index + joypad<>::axis + axis] = xinput.lgamepad[i].axis[axis];
for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
table[joypad(i).axis(axis)] = xinput.lgamepad[i].axis[axis];
}
for(unsigned button = 0; button < min(10U, (unsigned)joypad<>::buttons); button++) {
table[index + joypad<>::button + button] = xinput.lgamepad[i].button[button];
for(unsigned button = 0; button < min(10U, (unsigned)Joypad::Buttons); button++) {
table[joypad(i).button(button)] = xinput.lgamepad[i].button[button];
}
}
@@ -732,19 +739,18 @@ public:
//=======================
dinput.poll();
for(unsigned i = 0; i < dinput.lgamepad.size(); i++) {
if(joy >= joypad<>::count) break;
unsigned index = joypad<>::index(joy++, joypad<>::none);
if(joy >= Joypad::Count) break;
for(unsigned hat = 0; hat < min(4U, (unsigned)joypad<>::hats); hat++) {
table[index + joypad<>::hat + hat] = dinput.lgamepad[i].hat[hat];
for(unsigned hat = 0; hat < min(4U, (unsigned)Joypad::Hats); hat++) {
table[joypad(i).hat(hat)] = dinput.lgamepad[i].hat[hat];
}
for(unsigned axis = 0; axis < min(6U, (unsigned)joypad<>::axes); axis++) {
table[index + joypad<>::axis + axis] = dinput.lgamepad[i].axis[axis];
for(unsigned axis = 0; axis < min(6U, (unsigned)Joypad::Axes); axis++) {
table[joypad(i).axis(axis)] = dinput.lgamepad[i].axis[axis];
}
for(unsigned button = 0; button < min(128U, (unsigned)joypad<>::buttons); button++) {
table[index + joypad<>::button + button] = dinput.lgamepad[i].button[button];
for(unsigned button = 0; button < min(128U, (unsigned)Joypad::Buttons); button++) {
table[joypad(i).button(button)] = dinput.lgamepad[i].button[button];
}
}

View File

@@ -18,7 +18,7 @@ struct pInputSDL {
Display *display;
Window rootwindow;
Cursor InvisibleCursor;
SDL_Joystick *gamepad[joypad<>::count];
SDL_Joystick *gamepad[Joypad::Count];
unsigned screenwidth, screenheight;
unsigned relativex, relativey;
@@ -91,20 +91,13 @@ struct pInputSDL {
}
bool poll(int16_t *table) {
memset(table, 0, nall::input_limit * sizeof(int16_t));
memset(table, 0, Scancode::Limit * sizeof(int16_t));
//========
//Keyboard
//========
char state[32];
XQueryKeymap(device.display, state);
for(unsigned i = 0; i < keyboard<>::length; i++) {
uint8_t code = keycode[i];
if(code == 0) continue; //unmapped
table[i] = (bool)(state[code >> 3] & (1 << (code & 7)));
}
x_poll(table);
//=====
//Mouse
@@ -123,56 +116,55 @@ struct pInputSDL {
XGetWindowAttributes(device.display, settings.handle, &attributes);
//absolute -> relative conversion
table[mouse<0>::x] = (int16_t)(root_x_return - device.screenwidth / 2);
table[mouse<0>::y] = (int16_t)(root_y_return - device.screenheight / 2);
table[mouse(0).axis(0)] = (int16_t)(root_x_return - device.screenwidth / 2);
table[mouse(0).axis(1)] = (int16_t)(root_y_return - device.screenheight / 2);
if(table[mouse<0>::x] != 0 || table[mouse<0>::y] != 0) {
if(table[mouse(0).axis(0)] != 0 || table[mouse(0).axis(1)] != 0) {
//if mouse movement occurred, re-center mouse for next poll
XWarpPointer(device.display, None, device.rootwindow, 0, 0, 0, 0, device.screenwidth / 2, device.screenheight / 2);
}
} else {
table[mouse<0>::x] = (int16_t)(root_x_return - device.relativex);
table[mouse<0>::y] = (int16_t)(root_y_return - device.relativey);
table[mouse(0).axis(0)] = (int16_t)(root_x_return - device.relativex);
table[mouse(0).axis(1)] = (int16_t)(root_y_return - device.relativey);
device.relativex = root_x_return;
device.relativey = root_y_return;
}
//manual device polling is limited to only five buttons ...
table[mouse<0>::button + 0] = (bool)(mask_return & Button1Mask);
table[mouse<0>::button + 1] = (bool)(mask_return & Button2Mask);
table[mouse<0>::button + 2] = (bool)(mask_return & Button3Mask);
table[mouse<0>::button + 3] = (bool)(mask_return & Button4Mask);
table[mouse<0>::button + 4] = (bool)(mask_return & Button5Mask);
table[mouse(0).button(0)] = (bool)(mask_return & Button1Mask);
table[mouse(0).button(1)] = (bool)(mask_return & Button2Mask);
table[mouse(0).button(2)] = (bool)(mask_return & Button3Mask);
table[mouse(0).button(3)] = (bool)(mask_return & Button4Mask);
table[mouse(0).button(4)] = (bool)(mask_return & Button5Mask);
//=========
//Joypad(s)
//=========
SDL_JoystickUpdate();
for(unsigned i = 0; i < joypad<>::count; i++) {
for(unsigned i = 0; i < Joypad::Count; i++) {
if(!device.gamepad[i]) continue;
unsigned index = joypad<>::index(i, joypad<>::none);
//POV hats
unsigned hats = min((unsigned)joypad<>::hats, SDL_JoystickNumHats(device.gamepad[i]));
unsigned hats = min((unsigned)Joypad::Hats, SDL_JoystickNumHats(device.gamepad[i]));
for(unsigned hat = 0; hat < hats; hat++) {
uint8_t state = SDL_JoystickGetHat(device.gamepad[i], hat);
if(state & SDL_HAT_UP ) table[index + joypad<>::hat + hat] |= joypad<>::hat_up;
if(state & SDL_HAT_RIGHT) table[index + joypad<>::hat + hat] |= joypad<>::hat_right;
if(state & SDL_HAT_DOWN ) table[index + joypad<>::hat + hat] |= joypad<>::hat_down;
if(state & SDL_HAT_LEFT ) table[index + joypad<>::hat + hat] |= joypad<>::hat_left;
if(state & SDL_HAT_UP ) table[joypad(i).hat(hat)] |= Joypad::HatUp;
if(state & SDL_HAT_RIGHT) table[joypad(i).hat(hat)] |= Joypad::HatRight;
if(state & SDL_HAT_DOWN ) table[joypad(i).hat(hat)] |= Joypad::HatDown;
if(state & SDL_HAT_LEFT ) table[joypad(i).hat(hat)] |= Joypad::HatLeft;
}
//axes
unsigned axes = min((unsigned)joypad<>::axes, SDL_JoystickNumAxes(device.gamepad[i]));
unsigned axes = min((unsigned)Joypad::Axes, SDL_JoystickNumAxes(device.gamepad[i]));
for(unsigned axis = 0; axis < axes; axis++) {
table[index + joypad<>::axis + axis] = (int16_t)SDL_JoystickGetAxis(device.gamepad[i], axis);
table[joypad(i).axis(axis)] = (int16_t)SDL_JoystickGetAxis(device.gamepad[i], axis);
}
//buttons
for(unsigned button = 0; button < joypad<>::buttons; button++) {
table[index + joypad<>::button + button] = (bool)SDL_JoystickGetButton(device.gamepad[i], button);
for(unsigned button = 0; button < Joypad::Buttons; button++) {
table[joypad(i).button(button)] = (bool)SDL_JoystickGetButton(device.gamepad[i], button);
}
}
@@ -180,7 +172,7 @@ struct pInputSDL {
}
bool init() {
init_keycodes();
x_init();
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
SDL_JoystickEventState(SDL_IGNORE);
@@ -208,7 +200,7 @@ struct pInputSDL {
device.relativex = 0;
device.relativey = 0;
unsigned joypads = min((unsigned)joypad<>::count, SDL_NumJoysticks());
unsigned joypads = min((unsigned)Joypad::Count, SDL_NumJoysticks());
for(unsigned i = 0; i < joypads; i++) device.gamepad[i] = SDL_JoystickOpen(i);
return true;
@@ -218,7 +210,7 @@ struct pInputSDL {
unacquire();
XFreeCursor(device.display, device.InvisibleCursor);
for(unsigned i = 0; i < joypad<>::count; i++) {
for(unsigned i = 0; i < Joypad::Count; i++) {
if(device.gamepad[i]) SDL_JoystickClose(device.gamepad[i]);
device.gamepad[i] = 0;
}
@@ -228,7 +220,7 @@ struct pInputSDL {
}
pInputSDL() {
for(unsigned i = 0; i < joypad<>::count; i++) device.gamepad[i] = 0;
for(unsigned i = 0; i < Joypad::Count; i++) device.gamepad[i] = 0;
settings.handle = 0;
}
};

View File

@@ -29,22 +29,13 @@ public:
bool acquired() { return false; }
bool poll(int16_t *table) {
memset(table, 0, input_limit * sizeof(int16_t));
char state[32];
XQueryKeymap(display, state);
for(unsigned i = 0; i < keyboard<>::length; i++) {
uint8_t code = keycode[i];
if(code == 0) continue; //unmapped
table[i] = (bool)(state[code >> 3] & (1 << (code & 7)));
}
memset(table, 0, Scancode::Limit * sizeof(int16_t));
x_poll(table);
return true;
}
bool init() {
init_keycodes();
x_init();
display = XOpenDisplay(0);
return true;
}

View File

@@ -1,137 +1,263 @@
//shared keycode lookup table + initialization routine:
//#include inside a class interface to use
uint8_t scancode[256];
//Xlib keycodes for each key can vary between platforms, so this header file
//will lookup keycodes from static keysyms, and map them to nall/input.hpp's
//keyboard identifiers.
//
//this allows input capture routine to iterate quickly over all keycodes and
//map their states to ruby's input state table.
enum XScancode {
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
ScrollLock, Pause, Tilde,
Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
Dash, Equal, Backspace,
Insert, Delete, Home, End, PageUp, PageDown,
A, B, C, D, E, F, G, H, I, J, K, L, M,
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
LeftBracket, RightBracket, Backslash, Semicolon, Apostrophe, Comma, Period, Slash,
Keypad1, Keypad2, Keypad3, Keypad4, Keypad5, Keypad6, Keypad7, Keypad8, Keypad9, Keypad0,
Point, Enter, Add, Subtract, Multiply, Divide,
Up, Down, Left, Right,
Tab, Return, Spacebar, Menu,
LeftShift, RightShift, LeftControl, RightControl, LeftAlt, RightAlt, LeftSuper, RightSuper,
};
uint8_t keycode[256];
void init_keycodes() {
void x_poll(int16_t *table) {
char state[32];
Display *display = XOpenDisplay(0);
memset(&keycode, 0, sizeof keycode);
XQueryKeymap(display, state);
XCloseDisplay(display);
#define assign(x, y) keycode[x] = XKeysymToKeycode(display, y)
assign(keyboard<0>::escape, XK_Escape);
#define key(id) table[keyboard(0)[id]]
#define pressed(id) (bool)(state[scancode[id] >> 3] & (1 << (scancode[id] & 7)))
assign(keyboard<0>::f1, XK_F1);
assign(keyboard<0>::f2, XK_F2);
assign(keyboard<0>::f3, XK_F3);
assign(keyboard<0>::f4, XK_F4);
assign(keyboard<0>::f5, XK_F5);
assign(keyboard<0>::f6, XK_F6);
assign(keyboard<0>::f7, XK_F7);
assign(keyboard<0>::f8, XK_F8);
assign(keyboard<0>::f9, XK_F9);
assign(keyboard<0>::f10, XK_F10);
assign(keyboard<0>::f11, XK_F11);
assign(keyboard<0>::f12, XK_F12);
key(Keyboard::Escape) = pressed(Escape);
//assign(keyboard<0>::print_screen, XK_???);
assign(keyboard<0>::scroll_lock, XK_Scroll_Lock);
assign(keyboard<0>::pause, XK_Pause);
key(Keyboard::F1) = pressed(F1);
key(Keyboard::F2) = pressed(F2);
key(Keyboard::F3) = pressed(F3);
key(Keyboard::F4) = pressed(F4);
key(Keyboard::F5) = pressed(F5);
key(Keyboard::F6) = pressed(F6);
key(Keyboard::F7) = pressed(F7);
key(Keyboard::F8) = pressed(F8);
key(Keyboard::F9) = pressed(F9);
key(Keyboard::F10) = pressed(F10);
key(Keyboard::F11) = pressed(F11);
key(Keyboard::F12) = pressed(F12);
assign(keyboard<0>::tilde, XK_asciitilde);
key(Keyboard::ScrollLock) = pressed(ScrollLock);
key(Keyboard::Pause) = pressed(Pause);
key(Keyboard::Tilde) = pressed(Tilde);
assign(keyboard<0>::num_0, XK_0);
assign(keyboard<0>::num_1, XK_1);
assign(keyboard<0>::num_2, XK_2);
assign(keyboard<0>::num_3, XK_3);
assign(keyboard<0>::num_4, XK_4);
assign(keyboard<0>::num_5, XK_5);
assign(keyboard<0>::num_6, XK_6);
assign(keyboard<0>::num_7, XK_7);
assign(keyboard<0>::num_8, XK_8);
assign(keyboard<0>::num_9, XK_9);
key(Keyboard::Num1) = pressed(Num1);
key(Keyboard::Num2) = pressed(Num2);
key(Keyboard::Num3) = pressed(Num3);
key(Keyboard::Num4) = pressed(Num4);
key(Keyboard::Num5) = pressed(Num5);
key(Keyboard::Num6) = pressed(Num6);
key(Keyboard::Num7) = pressed(Num7);
key(Keyboard::Num8) = pressed(Num8);
key(Keyboard::Num9) = pressed(Num9);
key(Keyboard::Num0) = pressed(Num0);
assign(keyboard<0>::dash, XK_minus);
assign(keyboard<0>::equal, XK_equal);
assign(keyboard<0>::backspace, XK_BackSpace);
key(Keyboard::Dash) = pressed(Dash);
key(Keyboard::Equal) = pressed(Equal);
key(Keyboard::Backspace) = pressed(Backspace);
assign(keyboard<0>::insert, XK_Insert);
assign(keyboard<0>::delete_, XK_Delete);
assign(keyboard<0>::home, XK_Home);
assign(keyboard<0>::end, XK_End);
assign(keyboard<0>::page_up, XK_Prior);
assign(keyboard<0>::page_down, XK_Next);
key(Keyboard::Insert) = pressed(Insert);
key(Keyboard::Delete) = pressed(Delete);
key(Keyboard::Home) = pressed(Home);
key(Keyboard::End) = pressed(End);
key(Keyboard::PageUp) = pressed(PageUp);
key(Keyboard::PageDown) = pressed(PageDown);
assign(keyboard<0>::a, XK_A);
assign(keyboard<0>::b, XK_B);
assign(keyboard<0>::c, XK_C);
assign(keyboard<0>::d, XK_D);
assign(keyboard<0>::e, XK_E);
assign(keyboard<0>::f, XK_F);
assign(keyboard<0>::g, XK_G);
assign(keyboard<0>::h, XK_H);
assign(keyboard<0>::i, XK_I);
assign(keyboard<0>::j, XK_J);
assign(keyboard<0>::k, XK_K);
assign(keyboard<0>::l, XK_L);
assign(keyboard<0>::m, XK_M);
assign(keyboard<0>::n, XK_N);
assign(keyboard<0>::o, XK_O);
assign(keyboard<0>::p, XK_P);
assign(keyboard<0>::q, XK_Q);
assign(keyboard<0>::r, XK_R);
assign(keyboard<0>::s, XK_S);
assign(keyboard<0>::t, XK_T);
assign(keyboard<0>::u, XK_U);
assign(keyboard<0>::v, XK_V);
assign(keyboard<0>::w, XK_W);
assign(keyboard<0>::x, XK_X);
assign(keyboard<0>::y, XK_Y);
assign(keyboard<0>::z, XK_Z);
key(Keyboard::A) = pressed(A);
key(Keyboard::B) = pressed(B);
key(Keyboard::C) = pressed(C);
key(Keyboard::D) = pressed(D);
key(Keyboard::E) = pressed(E);
key(Keyboard::F) = pressed(F);
key(Keyboard::G) = pressed(G);
key(Keyboard::H) = pressed(H);
key(Keyboard::I) = pressed(I);
key(Keyboard::J) = pressed(J);
key(Keyboard::K) = pressed(K);
key(Keyboard::L) = pressed(L);
key(Keyboard::M) = pressed(M);
key(Keyboard::N) = pressed(N);
key(Keyboard::O) = pressed(O);
key(Keyboard::P) = pressed(P);
key(Keyboard::Q) = pressed(Q);
key(Keyboard::R) = pressed(R);
key(Keyboard::S) = pressed(S);
key(Keyboard::T) = pressed(T);
key(Keyboard::U) = pressed(U);
key(Keyboard::V) = pressed(V);
key(Keyboard::W) = pressed(W);
key(Keyboard::X) = pressed(X);
key(Keyboard::Y) = pressed(Y);
key(Keyboard::Z) = pressed(Z);
assign(keyboard<0>::lbracket, XK_bracketleft);
assign(keyboard<0>::rbracket, XK_bracketright);
assign(keyboard<0>::backslash, XK_backslash);
assign(keyboard<0>::semicolon, XK_semicolon);
assign(keyboard<0>::apostrophe, XK_apostrophe);
assign(keyboard<0>::comma, XK_comma);
assign(keyboard<0>::period, XK_period);
assign(keyboard<0>::slash, XK_slash);
key(Keyboard::LeftBracket) = pressed(LeftBracket);
key(Keyboard::RightBracket) = pressed(RightBracket);
key(Keyboard::Backslash) = pressed(Backslash);
key(Keyboard::Semicolon) = pressed(Semicolon);
key(Keyboard::Apostrophe) = pressed(Apostrophe);
key(Keyboard::Comma) = pressed(Comma);
key(Keyboard::Period) = pressed(Period);
key(Keyboard::Slash) = pressed(Slash);
assign(keyboard<0>::pad_0, XK_KP_0);
assign(keyboard<0>::pad_1, XK_KP_1);
assign(keyboard<0>::pad_2, XK_KP_2);
assign(keyboard<0>::pad_3, XK_KP_3);
assign(keyboard<0>::pad_4, XK_KP_4);
assign(keyboard<0>::pad_5, XK_KP_5);
assign(keyboard<0>::pad_6, XK_KP_6);
assign(keyboard<0>::pad_7, XK_KP_7);
assign(keyboard<0>::pad_8, XK_KP_8);
assign(keyboard<0>::pad_9, XK_KP_9);
key(Keyboard::Keypad1) = pressed(Keypad1);
key(Keyboard::Keypad2) = pressed(Keypad2);
key(Keyboard::Keypad3) = pressed(Keypad3);
key(Keyboard::Keypad4) = pressed(Keypad4);
key(Keyboard::Keypad5) = pressed(Keypad5);
key(Keyboard::Keypad6) = pressed(Keypad6);
key(Keyboard::Keypad7) = pressed(Keypad7);
key(Keyboard::Keypad8) = pressed(Keypad8);
key(Keyboard::Keypad9) = pressed(Keypad9);
key(Keyboard::Keypad0) = pressed(Keypad0);
assign(keyboard<0>::add, XK_KP_Add);
assign(keyboard<0>::subtract, XK_KP_Subtract);
assign(keyboard<0>::multiply, XK_KP_Multiply);
assign(keyboard<0>::divide, XK_KP_Divide);
assign(keyboard<0>::enter, XK_KP_Enter);
key(Keyboard::Point) = pressed(Point);
key(Keyboard::Enter) = pressed(Enter);
key(Keyboard::Add) = pressed(Add);
key(Keyboard::Subtract) = pressed(Subtract);
key(Keyboard::Multiply) = pressed(Multiply);
key(Keyboard::Divide) = pressed(Divide);
//assign(keyboard<0>::num_lock, XK_???);
//assign(keyboard<0>::caps_lock, XK_???);
key(Keyboard::Up) = pressed(Up);
key(Keyboard::Down) = pressed(Down);
key(Keyboard::Left) = pressed(Left);
key(Keyboard::Right) = pressed(Right);
assign(keyboard<0>::up, XK_Up);
assign(keyboard<0>::down, XK_Down);
assign(keyboard<0>::left, XK_Left);
assign(keyboard<0>::right, XK_Right);
key(Keyboard::Tab) = pressed(Tab);
key(Keyboard::Return) = pressed(Return);
key(Keyboard::Spacebar) = pressed(Spacebar);
key(Keyboard::Menu) = pressed(Menu);
assign(keyboard<0>::tab, XK_Tab);
assign(keyboard<0>::return_, XK_Return);
assign(keyboard<0>::spacebar, XK_space);
key(Keyboard::Shift) = pressed(LeftShift) || pressed(RightShift);
key(Keyboard::Control) = pressed(LeftControl) || pressed(RightControl);
key(Keyboard::Alt) = pressed(LeftAlt) || pressed(RightAlt);
key(Keyboard::Super) = pressed(LeftSuper) || pressed(RightSuper);
#undef key
#undef pressed
}
void x_init() {
Display *display = XOpenDisplay(0);
memset(&scancode, 0, sizeof scancode);
#define assign(x, y) scancode[x] = XKeysymToKeycode(display, y)
assign(Escape, XK_Escape);
assign(F1, XK_F1);
assign(F2, XK_F2);
assign(F3, XK_F3);
assign(F4, XK_F4);
assign(F5, XK_F5);
assign(F6, XK_F6);
assign(F7, XK_F7);
assign(F8, XK_F8);
assign(F9, XK_F9);
assign(F10, XK_F10);
assign(F11, XK_F11);
assign(F12, XK_F12);
assign(ScrollLock, XK_Scroll_Lock);
assign(Pause, XK_Pause);
assign(Tilde, XK_asciitilde);
assign(Num0, XK_0);
assign(Num1, XK_1);
assign(Num2, XK_2);
assign(Num3, XK_3);
assign(Num4, XK_4);
assign(Num5, XK_5);
assign(Num6, XK_6);
assign(Num7, XK_7);
assign(Num8, XK_8);
assign(Num9, XK_9);
assign(Dash, XK_minus);
assign(Equal, XK_equal);
assign(Backspace, XK_BackSpace);
assign(Insert, XK_Insert);
assign(Delete, XK_Delete);
assign(Home, XK_Home);
assign(End, XK_End);
assign(PageUp, XK_Prior);
assign(PageDown, XK_Next);
assign(A, XK_A);
assign(B, XK_B);
assign(C, XK_C);
assign(D, XK_D);
assign(E, XK_E);
assign(F, XK_F);
assign(G, XK_G);
assign(H, XK_H);
assign(I, XK_I);
assign(J, XK_J);
assign(K, XK_K);
assign(L, XK_L);
assign(M, XK_M);
assign(N, XK_N);
assign(O, XK_O);
assign(P, XK_P);
assign(Q, XK_Q);
assign(R, XK_R);
assign(S, XK_S);
assign(T, XK_T);
assign(U, XK_U);
assign(V, XK_V);
assign(W, XK_W);
assign(X, XK_X);
assign(Y, XK_Y);
assign(Z, XK_Z);
assign(LeftBracket, XK_bracketleft);
assign(RightBracket, XK_bracketright);
assign(Backslash, XK_backslash);
assign(Semicolon, XK_semicolon);
assign(Apostrophe, XK_apostrophe);
assign(Comma, XK_comma);
assign(Period, XK_period);
assign(Slash, XK_slash);
assign(Keypad0, XK_KP_0);
assign(Keypad1, XK_KP_1);
assign(Keypad2, XK_KP_2);
assign(Keypad3, XK_KP_3);
assign(Keypad4, XK_KP_4);
assign(Keypad5, XK_KP_5);
assign(Keypad6, XK_KP_6);
assign(Keypad7, XK_KP_7);
assign(Keypad8, XK_KP_8);
assign(Keypad9, XK_KP_9);
assign(Add, XK_KP_Add);
assign(Subtract, XK_KP_Subtract);
assign(Multiply, XK_KP_Multiply);
assign(Divide, XK_KP_Divide);
assign(Enter, XK_KP_Enter);
assign(Up, XK_Up);
assign(Down, XK_Down);
assign(Left, XK_Left);
assign(Right, XK_Right);
assign(Tab, XK_Tab);
assign(Return, XK_Return);
assign(Spacebar, XK_space);
assign(LeftControl, XK_Control_L);
assign(RightControl, XK_Control_R);
assign(LeftAlt, XK_Alt_L);
assign(RightAlt, XK_Alt_R);
assign(LeftShift, XK_Shift_L);
assign(RightShift, XK_Shift_R);
assign(LeftSuper, XK_Super_L);
assign(RightSuper, XK_Super_R);
assign(Menu, XK_Menu);
assign(keyboard<0>::lctrl, XK_Control_L);
assign(keyboard<0>::rctrl, XK_Control_R);
assign(keyboard<0>::lalt, XK_Alt_L);
assign(keyboard<0>::ralt, XK_Alt_R);
assign(keyboard<0>::lshift, XK_Shift_L);
assign(keyboard<0>::rshift, XK_Shift_R);
assign(keyboard<0>::lsuper, XK_Super_L);
assign(keyboard<0>::rsuper, XK_Super_R);
assign(keyboard<0>::menu, XK_Menu);
#undef assign
XCloseDisplay(display);

View File

@@ -14,6 +14,8 @@ InputInterface input;
const char *Video::Handle = "Handle";
const char *Video::Synchronize = "Synchronize";
const char *Video::Filter = "Filter";
const char *Video::FragmentShader = "FragmentShader";
const char *Video::VertexShader = "VertexShader";
void VideoInterface::driver(const char *driver) {
if(p) term();

View File

@@ -3,6 +3,8 @@ public:
static const char *Handle;
static const char *Synchronize;
static const char *Filter;
static const char *FragmentShader;
static const char *VertexShader;
enum Filter {
FilterPoint,

View File

@@ -2,7 +2,7 @@
video.glx
author: byuu
license: public domain
last updated: 2008-08-20
last updated: 2009-12-08
Design notes:
SGI's GLX is the X11/Xlib interface to OpenGL.
@@ -34,6 +34,8 @@ static Bool glx_wait_for_map_notify(Display *d, XEvent *e, char *arg) {
class pVideoGLX : public OpenGL {
public:
int (*glSwapInterval)(int);
Display *display;
int screen;
Window xwindow;
@@ -60,6 +62,8 @@ public:
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == Video::FragmentShader) return true;
if(name == Video::VertexShader) return true;
return false;
}
@@ -79,7 +83,7 @@ public:
if(name == Video::Synchronize) {
if(settings.synchronize != any_cast<bool>(value)) {
settings.synchronize = any_cast<bool>(value);
if(glxcontext) init();
if(glSwapInterval) glSwapInterval(settings.synchronize);
return true;
}
}
@@ -89,6 +93,16 @@ public:
return true;
}
if(name == Video::FragmentShader) {
OpenGL::set_fragment_shader(any_cast<const char*>(value));
return true;
}
if(name == Video::VertexShader) {
OpenGL::set_vertex_shader(any_cast<const char*>(value));
return true;
}
return false;
}
@@ -138,11 +152,8 @@ public:
//let GLX determine the best Visual to use for GL output; provide a few hints
//note: some video drivers will override double buffering attribute
int elements = 0;
int attributelist[] = { GLX_RGBA, None };
int attributelist_sync[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
XVisualInfo *vi = glXChooseVisual(display, screen,
settings.synchronize ? attributelist_sync : attributelist);
int attributelist[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
XVisualInfo *vi = glXChooseVisual(display, screen, attributelist);
//Window settings.handle has already been realized, most likely with DefaultVisual.
//GLX requires that the GL output window has the same Visual as the GLX context.
@@ -175,6 +186,13 @@ public:
OpenGL::init();
settings.width = 256;
settings.height = 256;
//vertical synchronization
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalEXT");
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
if( glSwapInterval) glSwapInterval(settings.synchronize);
return true;
}
@@ -197,7 +215,7 @@ public:
}
}
pVideoGLX() {
pVideoGLX() : glSwapInterval(0) {
settings.handle = 0;
settings.synchronize = false;
xwindow = 0;

View File

@@ -2,15 +2,36 @@
#if defined(PLATFORM_X)
#include <GL/glx.h>
#define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
#elif defined(PLATFORM_WIN)
#include <GL/glext.h>
#define glGetProcAddress(name) wglGetProcAddress(name)
#else
#error "ruby::OpenGL: unsupported platform"
#endif
PFNGLCREATEPROGRAMPROC glCreateProgram = 0;
PFNGLUSEPROGRAMPROC glUseProgram = 0;
PFNGLCREATESHADERPROC glCreateShader = 0;
PFNGLDELETESHADERPROC glDeleteShader = 0;
PFNGLSHADERSOURCEPROC glShaderSource = 0;
PFNGLCOMPILESHADERPROC glCompileShader = 0;
PFNGLATTACHSHADERPROC glAttachShader = 0;
PFNGLDETACHSHADERPROC glDetachShader = 0;
PFNGLLINKPROGRAMPROC glLinkProgram = 0;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = 0;
PFNGLUNIFORM1IPROC glUniform1i = 0;
PFNGLUNIFORM2FVPROC glUniform2fv = 0;
PFNGLUNIFORM4FVPROC glUniform4fv = 0;
class OpenGL {
public:
GLuint gltexture;
GLuint glprogram;
GLuint fragmentshader;
GLuint vertexshader;
bool shader_support;
uint32_t *buffer;
unsigned iwidth, iheight;
@@ -45,6 +66,23 @@ public:
}
void refresh(bool smooth, unsigned inwidth, unsigned inheight, unsigned outwidth, unsigned outheight) {
if(shader_support) {
glUseProgram(glprogram);
GLint location;
float inputSize[2] = { inwidth, inheight };
location = glGetUniformLocation(glprogram, "rubyInputSize");
glUniform2fv(location, 1, inputSize);
float outputSize[2] = { outwidth, outheight };
location = glGetUniformLocation(glprogram, "rubyOutputSize");
glUniform2fv(location, 1, outputSize);
float textureSize[2] = { iwidth, iheight };
location = glGetUniformLocation(glprogram, "rubyTextureSize");
glUniform2fv(location, 1, textureSize);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, smooth ? GL_LINEAR : GL_NEAREST);
@@ -78,6 +116,48 @@ public:
glEnd();
glFlush();
if(shader_support) {
glUseProgram(0);
}
}
void set_fragment_shader(const char *source) {
if(!shader_support) return;
if(fragmentshader) {
glDetachShader(glprogram, fragmentshader);
glDeleteShader(fragmentshader);
fragmentshader = 0;
}
if(source) {
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentshader, 1, &source, 0);
glCompileShader(fragmentshader);
glAttachShader(glprogram, fragmentshader);
}
glLinkProgram(glprogram);
}
void set_vertex_shader(const char *source) {
if(!shader_support) return;
if(vertexshader) {
glDetachShader(glprogram, vertexshader);
glDeleteShader(vertexshader);
vertexshader = 0;
}
if(source) {
vertexshader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexshader, 1, &source, 0);
glCompileShader(vertexshader);
glAttachShader(glprogram, vertexshader);
}
glLinkProgram(glprogram);
}
void init() {
@@ -92,6 +172,28 @@ public:
glEnable(GL_DITHER);
glEnable(GL_TEXTURE_2D);
//bind shader functions
glCreateProgram = (PFNGLCREATEPROGRAMPROC)glGetProcAddress("glCreateProgram");
glUseProgram = (PFNGLUSEPROGRAMPROC)glGetProcAddress("glUseProgram");
glCreateShader = (PFNGLCREATESHADERPROC)glGetProcAddress("glCreateShader");
glDeleteShader = (PFNGLDELETESHADERPROC)glGetProcAddress("glDeleteShader");
glShaderSource = (PFNGLSHADERSOURCEPROC)glGetProcAddress("glShaderSource");
glCompileShader = (PFNGLCOMPILESHADERPROC)glGetProcAddress("glCompileShader");
glAttachShader = (PFNGLATTACHSHADERPROC)glGetProcAddress("glAttachShader");
glDetachShader = (PFNGLDETACHSHADERPROC)glGetProcAddress("glDetachShader");
glLinkProgram = (PFNGLLINKPROGRAMPROC)glGetProcAddress("glLinkProgram");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)glGetProcAddress("glGetUniformLocation");
glUniform1i = (PFNGLUNIFORM1IPROC)glGetProcAddress("glUniform1i");
glUniform2fv = (PFNGLUNIFORM2FVPROC)glGetProcAddress("glUniform2fv");
glUniform4fv = (PFNGLUNIFORM4FVPROC)glGetProcAddress("glUniform4fv");
shader_support = glCreateProgram && glUseProgram && glCreateShader
&& glDeleteShader && glShaderSource && glCompileShader && glAttachShader
&& glDetachShader && glLinkProgram && glGetUniformLocation
&& glUniform1i && glUniform2fv && glUniform4fv;
if(shader_support) glprogram = glCreateProgram();
//create surface texture
resize(256, 256);
}
@@ -112,6 +214,10 @@ public:
OpenGL() {
gltexture = 0;
glprogram = 0;
fragmentshader = 0;
vertexshader = 0;
buffer = 0;
iwidth = 0;
iheight = 0;

View File

@@ -9,6 +9,8 @@ namespace ruby {
class pVideoWGL : public OpenGL {
public:
BOOL (APIENTRY *glSwapInterval)(int);
HDC display;
HGLRC wglcontext;
HWND window;
@@ -27,6 +29,8 @@ public:
if(name == Video::Handle) return true;
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == Video::FragmentShader) return true;
if(name == Video::VertexShader) return true;
return false;
}
@@ -55,6 +59,16 @@ public:
return true;
}
if(name == Video::FragmentShader) {
OpenGL::set_fragment_shader(any_cast<const char*>(value));
return true;
}
if(name == Video::VertexShader) {
OpenGL::set_vertex_shader(any_cast<const char*>(value));
return true;
}
return false;
}
@@ -92,7 +106,7 @@ public:
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | (settings.synchronize ? PFD_DOUBLEBUFFER : 0);
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
display = GetDC(settings.handle);
@@ -105,6 +119,11 @@ public:
OpenGL::init();
settings.width = 256;
settings.height = 256;
//vertical synchronization
if(!glSwapInterval) glSwapInterval = (BOOL (APIENTRY*)(int))glGetProcAddress("wglSwapIntervalEXT");
if( glSwapInterval) glSwapInterval(settings.synchronize);
return true;
}
@@ -117,7 +136,7 @@ public:
}
}
pVideoWGL() {
pVideoWGL() : glSwapInterval(0) {
settings.handle = 0;
settings.synchronize = false;
settings.filter = 0;

View File

@@ -5,5 +5,3 @@ mkdir nall
mkdir ruby
xcopy /E ..\..\..\nall nall
xcopy /E ..\..\..\ruby ruby
del ruby\test*
del ruby\cc.*

View File

@@ -8,5 +8,3 @@ cp -r ../../../ruby ./ruby
rm -r libco/doc
rm -r libco/test
rm ruby/test*
rm ruby/cc.*

View File

@@ -23,7 +23,15 @@ void bPPU::enter() {
scanline();
add_clocks(10);
//H = 10 (OAM address reset)
//H = 10 (cache mode7 registers + OAM address reset)
cache.m7_hofs = regs.m7_hofs;
cache.m7_vofs = regs.m7_vofs;
cache.m7a = regs.m7a;
cache.m7b = regs.m7b;
cache.m7c = regs.m7c;
cache.m7d = regs.m7d;
cache.m7x = regs.m7x;
cache.m7y = regs.m7y;
if(vcounter() == (!overscan() ? 225 : 240)) {
if(regs.display_disabled == false) {
regs.oam_addr = regs.oam_baseaddr << 1;

View File

@@ -24,6 +24,12 @@ public:
uint8 oam_basesize;
uint8 oam_nameselect;
uint16 oam_tdaddr;
//$210d-$210e
uint16 m7_hofs, m7_vofs;
//$211b-$2120
uint16 m7a, m7b, m7c, m7d, m7x, m7y;
} cache;
alwaysinline bool interlace() const { return display.interlace; }

View File

@@ -55,6 +55,10 @@ template<unsigned mode, unsigned bg, unsigned color_depth>
void bPPU::render_line_bg(uint8 pri0_pos, uint8 pri1_pos) {
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
if(render_enabled(bg, 0) == false) pri0_pos = 0;
if(render_enabled(bg, 1) == false) pri1_pos = 0;
if(pri0_pos == 0 && pri1_pos == 0) return;
const bool bg_enabled = regs.bg_enabled[bg];
const bool bgsub_enabled = regs.bgsub_enabled[bg];

View File

@@ -16,18 +16,22 @@ template<unsigned bg>
void bPPU::render_line_mode7(uint8 pri0_pos, uint8 pri1_pos) {
if(regs.bg_enabled[bg] == false && regs.bgsub_enabled[bg] == false) return;
if(render_enabled(bg, 0) == false) pri0_pos = 0;
if(render_enabled(bg, 1) == false) pri1_pos = 1;
if(pri0_pos == 0 && pri1_pos == 0) return;
int32 px, py;
int32 tx, ty, tile, palette;
int32 a = sclip<16>(regs.m7a);
int32 b = sclip<16>(regs.m7b);
int32 c = sclip<16>(regs.m7c);
int32 d = sclip<16>(regs.m7d);
int32 a = sclip<16>(cache.m7a);
int32 b = sclip<16>(cache.m7b);
int32 c = sclip<16>(cache.m7c);
int32 d = sclip<16>(cache.m7d);
int32 cx = sclip<13>(regs.m7x);
int32 cy = sclip<13>(regs.m7y);
int32 hofs = sclip<13>(regs.m7_hofs);
int32 vofs = sclip<13>(regs.m7_vofs);
int32 cx = sclip<13>(cache.m7x);
int32 cy = sclip<13>(cache.m7y);
int32 hofs = sclip<13>(cache.m7_hofs);
int32 vofs = sclip<13>(cache.m7_vofs);
int _pri, _x;
bool _bg_enabled = regs.bg_enabled[bg];

View File

@@ -189,6 +189,12 @@ void bPPU::render_line_oam_rto() {
void bPPU::render_line_oam(uint8 pri0_pos, uint8 pri1_pos, uint8 pri2_pos, uint8 pri3_pos) {
if(regs.bg_enabled[OAM] == false && regs.bgsub_enabled[OAM] == false) return;
if(render_enabled(OAM, 0) == false) pri0_pos = 0;
if(render_enabled(OAM, 1) == false) pri1_pos = 0;
if(render_enabled(OAM, 2) == false) pri2_pos = 0;
if(render_enabled(OAM, 3) == false) pri3_pos = 0;
if(pri0_pos == 0 && pri1_pos == 0 && pri2_pos == 0 && pri3_pos == 0) return;
for(unsigned s = 0; s < 34; s++) {
if(oam_tilelist[s].tile == 0xffff) continue;
render_oam_tile(s);

View File

@@ -8,6 +8,17 @@
#include "addsub.cpp"
#include "line.cpp"
bool bPPU::render_enabled(unsigned bg, unsigned pri) const {
switch(bg) {
case BG1: return config.ppu.bg1_enabled[pri];
case BG2: return config.ppu.bg2_enabled[pri];
case BG3: return config.ppu.bg3_enabled[pri];
case BG4: return config.ppu.bg4_enabled[pri];
case OAM: return config.ppu.oam_enabled[pri];
}
return true;
}
//Mode 0: ->
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
// BG4B, BG3B, OAM0, BG4A, BG3A, OAM1, BG2B, BG1B, OAM2, BG2A, BG1A, OAM3

View File

@@ -1,4 +1,6 @@
//render.cpp
bool render_enabled(unsigned bg, unsigned pri) const;
inline void render_line_mode0();
inline void render_line_mode1();
inline void render_line_mode2();

View File

@@ -5,18 +5,18 @@ uint16 SMPcore::__relb(int8 offset, int op_len) {
return pc + offset;
}
void SMPcore::disassemble_opcode(char *output) {
void SMPcore::disassemble_opcode(char *output, uint16 addr) {
char *s, t[512];
uint8 op, op0, op1;
uint16 opw, opdp0, opdp1;
s = output;
sprintf(s, "..%.4x ", regs.pc);
sprintf(s, "..%.4x ", addr);
//TODO: read from IPLROM when applicable
op = memory::apuram[(uint16)(regs.pc + 0)];
op0 = memory::apuram[(uint16)(regs.pc + 1)];
op1 = memory::apuram[(uint16)(regs.pc + 2)];
op = memory::apuram[(uint16)(addr + 0)];
op0 = memory::apuram[(uint16)(addr + 1)];
op1 = memory::apuram[(uint16)(addr + 2)];
opw = (op0) | (op1 << 8);
opdp0 = ((unsigned)regs.p.p << 8) + op0;
opdp1 = ((unsigned)regs.p.p << 8) + op1;

View File

@@ -1,2 +1,2 @@
void disassemble_opcode(char *output);
void disassemble_opcode(char *output, uint16 addr);
inline uint16 __relb(int8 offset, int op_len);

View File

@@ -10,14 +10,35 @@ void sSMPDebug::op_step() {
debugger.breakpoint_test(Debugger::Breakpoint::APURAM, Debugger::Breakpoint::Exec, regs.pc, 0x00);
}
if(debugger.trace_smp) {
char t[256];
disassemble_opcode(t);
debugger.tracefile.print(string() << t << "\n");
}
usage[regs.pc] |= UsageExec;
opcode_pc = regs.pc;
if(step_event) step_event();
sSMP::op_step();
scheduler.sync_smpcpu();
}
uint8 sSMPDebug::op_read(uint16 addr) {
uint8 data = sSMP::op_read(addr);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::APURAM, Debugger::Breakpoint::Read, addr, data);
return data;
}
void sSMPDebug::op_write(uint16 addr, uint8 data) {
sSMP::op_write(addr, data);
usage[addr] |= UsageWrite;
usage[addr] &= ~UsageExec;
debugger.breakpoint_test(Debugger::Breakpoint::APURAM, Debugger::Breakpoint::Write, addr, data);
}
sSMPDebug::sSMPDebug() {
usage = new uint8[1 << 16]();
opcode_pc = 0xffc0;
}
sSMPDebug::~sSMPDebug() {
delete[] usage;
}
#endif

View File

@@ -1,4 +1,19 @@
class sSMPDebug : public sSMP {
public:
function<void ()> step_event;
enum Usage {
UsageRead = 0x80,
UsageWrite = 0x40,
UsageExec = 0x20,
};
uint8 *usage;
uint16 opcode_pc;
void op_step();
uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
sSMPDebug();
~sSMPDebug();
};

View File

@@ -1,12 +1,12 @@
uint8 ram_read(uint16 addr);
void ram_write(uint16 addr, uint8 data);
uint8 ram_read(uint16 addr);
void ram_write(uint16 addr, uint8 data);
uint8 port_read(uint8 port);
void port_write(uint8 port, uint8 data);
uint8 port_read(uint8 port);
void port_write(uint8 port, uint8 data);
uint8 op_busread(uint16 addr);
void op_buswrite(uint16 addr, uint8 data);
uint8 op_busread(uint16 addr);
void op_buswrite(uint16 addr, uint8 data);
void op_io();
uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
void op_io();
debugvirtual uint8 op_read(uint16 addr);
debugvirtual void op_write(uint16 addr, uint8 data);

View File

@@ -2,11 +2,89 @@
Audio audio;
void Audio::sample(uint16 l_sample, uint16 r_sample) {
system.interface->audio_sample(l_sample, r_sample);
void Audio::coprocessor_enable(bool state) {
coprocessor = state;
dsp_rdoffset = cop_rdoffset = 0;
dsp_wroffset = cop_wroffset = 0;
dsp_length = cop_length = 0;
r_sum_l = r_sum_r = 0;
}
void Audio::coprocessor_frequency(double input_frequency) {
double output_frequency;
if(system.region() == System::NTSC) {
output_frequency = config.smp.ntsc_clock_rate / 768.0;
} else /* (system.region() == System::PAL) */ {
output_frequency = config.smp.pal_clock_rate / 768.0;
}
r_step = input_frequency / output_frequency;
r_frac = 0;
}
void Audio::sample(int16 left, int16 right) {
if(coprocessor == false) {
system.interface->audio_sample(left, right);
} else {
dsp_buffer[dsp_wroffset] = ((uint16)left << 0) + ((uint16)right << 16);
dsp_wroffset = (dsp_wroffset + 1) & 32767;
dsp_length = (dsp_length + 1) & 32767;
flush();
}
}
void Audio::coprocessor_sample(int16 left, int16 right) {
if(r_frac >= 1.0) {
r_frac -= 1.0;
r_sum_l += left;
r_sum_r += right;
return;
}
r_sum_l += left * r_frac;
r_sum_r += right * r_frac;
uint16 output_left = sclamp<16>(int(r_sum_l / r_step));
uint16 output_right = sclamp<16>(int(r_sum_r / r_step));
double first = 1.0 - r_frac;
r_sum_l = left * first;
r_sum_r = right * first;
r_frac = r_step - first;
cop_buffer[cop_wroffset] = (output_left << 0) + (output_right << 16);
cop_wroffset = (cop_wroffset + 1) & 32767;
cop_length = (cop_length + 1) & 32767;
flush();
}
void Audio::init() {
}
void Audio::flush() {
while(dsp_length > 0 && cop_length > 0) {
uint32 dsp_sample = dsp_buffer[dsp_rdoffset];
uint32 cop_sample = cop_buffer[cop_rdoffset];
dsp_rdoffset = (dsp_rdoffset + 1) & 32767;
cop_rdoffset = (cop_rdoffset + 1) & 32767;
dsp_length--;
cop_length--;
int dsp_left = (int16)(dsp_sample >> 0);
int dsp_right = (int16)(dsp_sample >> 16);
int cop_left = (int16)(cop_sample >> 0);
int cop_right = (int16)(cop_sample >> 16);
system.interface->audio_sample(
sclamp<16>((dsp_left + cop_left ) / 2),
sclamp<16>((dsp_right + cop_right) / 2)
);
}
}
#endif

View File

@@ -1,7 +1,22 @@
class Audio {
public:
void sample(uint16 l_sample, uint16 r_sample);
void coprocessor_enable(bool state);
void coprocessor_frequency(double frequency);
void sample(int16 left, int16 right);
void coprocessor_sample(int16 left, int16 right);
void init();
private:
bool coprocessor;
uint32 dsp_buffer[32768], cop_buffer[32768];
unsigned dsp_rdoffset, cop_rdoffset;
unsigned dsp_wroffset, cop_wroffset;
unsigned dsp_length, cop_length;
double r_step, r_frac;
int r_sum_l, r_sum_r;
void flush();
};
extern Audio audio;

View File

@@ -18,6 +18,12 @@ Configuration::Configuration() {
smp.ntsc_clock_rate = 24607104; //32040.5 * 768
smp.pal_clock_rate = 24607104;
ppu.bg1_enabled[0] = ppu.bg1_enabled[1] = true;
ppu.bg2_enabled[0] = ppu.bg2_enabled[1] = true;
ppu.bg3_enabled[0] = ppu.bg3_enabled[1] = true;
ppu.bg4_enabled[0] = ppu.bg4_enabled[1] = true;
ppu.oam_enabled[0] = ppu.oam_enabled[1] = ppu.oam_enabled[2] = ppu.oam_enabled[3] = true;
ppu1.version = 1;
ppu2.version = 3;

View File

@@ -18,6 +18,14 @@ struct Configuration {
unsigned pal_clock_rate;
} smp;
struct PPU {
bool bg1_enabled[2];
bool bg2_enabled[2];
bool bg3_enabled[2];
bool bg4_enabled[2];
bool oam_enabled[4];
} ppu;
struct PPU1 {
unsigned version;
} ppu1;

View File

@@ -22,10 +22,6 @@ public:
bool step_cpu;
bool step_smp;
file tracefile;
bool trace_cpu;
bool trace_smp;
enum MemorySource { CPUBus, APURAM, VRAM, OAM, CGRAM };
uint8 read(MemorySource, unsigned addr);
void write(MemorySource, unsigned addr, uint8 data);

View File

@@ -8,58 +8,40 @@ uint8 Input::port_read(bool portnumber) {
switch(p.device) {
case DeviceJoypad: {
if(p.counter0 >= 16) return 1;
unsigned deviceid = (portnumber == 0 ? DeviceIDJoypad1 : DeviceIDJoypad2);
return system.interface->input_poll(deviceid, p.counter0++);
return system.interface->input_poll(portnumber, p.device, 0, p.counter0++);
} //case DeviceJoypad
case DeviceMultitap: {
if(cpu.joylatch()) return 2; //when latch is high -- data2 = 1, data1 = 0
unsigned deviceidx, deviceid0, deviceid1;
if(portnumber == 0) {
if(cpu.pio() & 0x40) {
deviceidx = p.counter0;
if(deviceidx >= 16) return 3;
p.counter0++;
unsigned deviceidx, deviceindex0, deviceindex1;
uint8 mask = (portnumber == 0 ? 0x40 : 0x80);
deviceid0 = DeviceIDMultitap1A;
deviceid1 = DeviceIDMultitap1B;
} else {
deviceidx = p.counter1;
if(deviceidx >= 16) return 3;
p.counter1++;
if(cpu.pio() & mask) {
deviceidx = p.counter0;
if(deviceidx >= 16) return 3;
p.counter0++;
deviceid0 = DeviceIDMultitap1C;
deviceid1 = DeviceIDMultitap1D;
}
deviceindex0 = 0; //controller 1
deviceindex1 = 1; //controller 2
} else {
if(cpu.pio() & 0x80) {
deviceidx = p.counter0;
if(deviceidx >= 16) return 3;
p.counter0++;
deviceidx = p.counter1;
if(deviceidx >= 16) return 3;
p.counter1++;
deviceid0 = DeviceIDMultitap2A;
deviceid1 = DeviceIDMultitap2B;
} else {
deviceidx = p.counter1;
if(deviceidx >= 16) return 3;
p.counter1++;
deviceid0 = DeviceIDMultitap2C;
deviceid1 = DeviceIDMultitap2D;
}
deviceindex0 = 2; //controller 3
deviceindex1 = 3; //controller 4
}
return (system.interface->input_poll(deviceid0, deviceidx) << 0)
| (system.interface->input_poll(deviceid1, deviceidx) << 1);
return (system.interface->input_poll(portnumber, p.device, deviceindex0, deviceidx) << 0)
| (system.interface->input_poll(portnumber, p.device, deviceindex1, deviceidx) << 1);
} //case DeviceMultitap
case DeviceMouse: {
if(p.counter0 >= 32) return 1;
unsigned deviceid = (portnumber == 0 ? DeviceIDMouse1 : DeviceIDMouse2);
int position_x = system.interface->input_poll(deviceid, MouseX); //-n = left, 0 = center, +n = right
int position_y = system.interface->input_poll(deviceid, MouseY); //-n = up, 0 = center, +n = right
int position_x = system.interface->input_poll(portnumber, p.device, 0, MouseX); //-n = left, 0 = center, +n = right
int position_y = system.interface->input_poll(portnumber, p.device, 0, MouseY); //-n = up, 0 = center, +n = right
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
@@ -80,8 +62,8 @@ uint8 Input::port_read(bool portnumber) {
case 6: return 0;
case 7: return 0;
case 8: return system.interface->input_poll(deviceid, MouseRight);
case 9: return system.interface->input_poll(deviceid, MouseLeft);
case 8: return system.interface->input_poll(portnumber, p.device, 0, MouseRight);
case 9: return system.interface->input_poll(portnumber, p.device, 0, MouseLeft);
case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
case 11: return 0; // ||
@@ -116,7 +98,7 @@ uint8 Input::port_read(bool portnumber) {
if(p.counter0 == 0) {
//turbo is a switch; toggle is edge sensitive
bool turbo = system.interface->input_poll(DeviceIDSuperScope, SuperScopeTurbo);
bool turbo = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTurbo);
if(turbo && !p.superscope.turbolock) {
p.superscope.turbo = !p.superscope.turbo; //toggle state
p.superscope.turbolock = true;
@@ -127,7 +109,7 @@ uint8 Input::port_read(bool portnumber) {
//trigger is a button
//if turbo is active, trigger is level sensitive; otherwise it is edge sensitive
p.superscope.trigger = false;
bool trigger = system.interface->input_poll(DeviceIDSuperScope, SuperScopeTrigger);
bool trigger = system.interface->input_poll(portnumber, p.device, 0, SuperScopeTrigger);
if(trigger && (p.superscope.turbo || !p.superscope.triggerlock)) {
p.superscope.trigger = true;
p.superscope.triggerlock = true;
@@ -136,11 +118,11 @@ uint8 Input::port_read(bool portnumber) {
}
//cursor is a button; it is always level sensitive
p.superscope.cursor = system.interface->input_poll(DeviceIDSuperScope, SuperScopeCursor);
p.superscope.cursor = system.interface->input_poll(portnumber, p.device, 0, SuperScopeCursor);
//pause is a button; it is always edge sensitive
p.superscope.pause = false;
bool pause = system.interface->input_poll(DeviceIDSuperScope, SuperScopePause);
bool pause = system.interface->input_poll(portnumber, p.device, 0, SuperScopePause);
if(pause && !p.superscope.pauselock) {
p.superscope.pause = true;
p.superscope.pauselock = true;
@@ -171,12 +153,12 @@ uint8 Input::port_read(bool portnumber) {
if(p.counter0 >= 32) return 1;
if(p.counter0 == 0) {
p.justifier.trigger1 = system.interface->input_poll(DeviceIDJustifier1, JustifierTrigger);
p.justifier.start1 = system.interface->input_poll(DeviceIDJustifier1, JustifierStart);
p.justifier.trigger1 = system.interface->input_poll(portnumber, p.device, 0, JustifierTrigger);
p.justifier.start1 = system.interface->input_poll(portnumber, p.device, 0, JustifierStart);
if(p.device == DeviceJustifiers) {
p.justifier.trigger2 = system.interface->input_poll(DeviceIDJustifier2, JustifierTrigger);
p.justifier.start2 = system.interface->input_poll(DeviceIDJustifier2, JustifierStart);
p.justifier.trigger2 = system.interface->input_poll(portnumber, p.device, 1, JustifierTrigger);
p.justifier.start2 = system.interface->input_poll(portnumber, p.device, 1, JustifierStart);
} else {
p.justifier.x2 = -1;
p.justifier.y2 = -1;
@@ -238,8 +220,8 @@ void Input::update() {
switch(p.device) {
case DeviceSuperScope: {
int x = system.interface->input_poll(DeviceIDSuperScope, SuperScopeX);
int y = system.interface->input_poll(DeviceIDSuperScope, SuperScopeY);
int x = system.interface->input_poll(1, p.device, 0, SuperScopeX);
int y = system.interface->input_poll(1, p.device, 0, SuperScopeY);
x += p.superscope.x;
y += p.superscope.y;
p.superscope.x = max(-16, min(256 + 16, x));
@@ -251,15 +233,15 @@ void Input::update() {
case DeviceJustifier:
case DeviceJustifiers: {
int x1 = system.interface->input_poll(DeviceIDJustifier1, JustifierX);
int y1 = system.interface->input_poll(DeviceIDJustifier1, JustifierY);
int x1 = system.interface->input_poll(1, p.device, 0, JustifierX);
int y1 = system.interface->input_poll(1, p.device, 0, JustifierY);
x1 += p.justifier.x1;
y1 += p.justifier.y1;
p.justifier.x1 = max(-16, min(256 + 16, x1));
p.justifier.y1 = max(-16, min(240 + 16, y1));
int x2 = system.interface->input_poll(DeviceIDJustifier2, JustifierX);
int y2 = system.interface->input_poll(DeviceIDJustifier2, JustifierY);
int x2 = system.interface->input_poll(1, p.device, 1, JustifierX);
int y2 = system.interface->input_poll(1, p.device, 1, JustifierY);
x2 += p.justifier.x2;
y2 += p.justifier.y2;
p.justifier.x2 = max(-16, min(256 + 16, x2));

View File

@@ -10,32 +10,13 @@ public:
DeviceJustifiers,
};
enum DeviceID {
DeviceIDNone,
DeviceIDJoypad1,
DeviceIDJoypad2,
DeviceIDMultitap1A,
DeviceIDMultitap1B,
DeviceIDMultitap1C,
DeviceIDMultitap1D,
DeviceIDMultitap2A,
DeviceIDMultitap2B,
DeviceIDMultitap2C,
DeviceIDMultitap2D,
DeviceIDMouse1,
DeviceIDMouse2,
DeviceIDSuperScope,
DeviceIDJustifier1,
DeviceIDJustifier2,
};
enum JoypadID {
JoypadB = 0, JoypadY = 1,
JoypadSelect = 2, JoypadStart = 3,
JoypadUp = 4, JoypadDown = 5,
JoypadLeft = 6, JoypadRight = 7,
JoypadA = 8, JoypadX = 9,
JoypadL = 10, JoypadR = 11,
JoypadB = 0, JoypadY = 1,
JoypadSelect = 2, JoypadStart = 3,
JoypadUp = 4, JoypadDown = 5,
JoypadLeft = 6, JoypadRight = 7,
JoypadA = 8, JoypadX = 9,
JoypadL = 10, JoypadR = 11,
};
enum MouseID {

View File

@@ -3,5 +3,5 @@ public:
virtual void video_refresh(uint16_t *data, unsigned pitch, unsigned *line, unsigned width, unsigned height) {}
virtual void audio_sample(uint16_t l_sample, uint16_t r_sample) {}
virtual void input_poll() {}
virtual int16_t input_poll(unsigned deviceid, unsigned id) { return 0; }
virtual int16_t input_poll(bool port, unsigned device, unsigned index, unsigned id) { return 0; }
};

View File

@@ -23,6 +23,7 @@ void Scheduler::init() {
clock.smp_freq = system.region() == System::NTSC
? config.smp.ntsc_clock_rate
: config.smp.pal_clock_rate;
clock.cop_freq = clock.cpu_freq;
clock.cpucop = 0;
clock.cpuppu = 0;

View File

@@ -15,6 +15,7 @@ public:
struct {
uint32 cpu_freq;
uint32 cop_freq;
uint32 smp_freq;
int64 cpucop;
@@ -102,13 +103,13 @@ public:
//==========
alwaysinline void addclocks_cpu(unsigned clocks) {
clock.cpucop -= clocks;
clock.cpucop -= clocks * (uint64)clock.cop_freq;
clock.cpuppu -= clocks;
clock.cpusmp -= clocks * (uint64)clock.smp_freq;
}
alwaysinline void addclocks_cop(unsigned clocks) {
clock.cpucop += clocks;
clock.cpucop += clocks * (uint64)clock.cpu_freq;
}
alwaysinline void addclocks_ppu(unsigned clocks) {

View File

@@ -1,12 +1,20 @@
#ifdef SYSTEM_CPP
serializer System::serialize() {
serializer s(serialize_size);
unsigned System::serialize_size() const {
return serializer_size;
}
serializer System::serialize() {
serializer s(serializer_size);
unsigned signature = 0x31545342, version = bsnesSerializerVersion, crc32 = cartridge.crc32();
char description[512];
memset(&description, 0, sizeof description);
unsigned signature = 0x31545342, version = bsnesSaveStateVersion, crc32 = cartridge.crc32();
s.integer(signature);
s.integer(version);
s.integer(crc32);
s.array(description);
serialize_all(s);
return s;
@@ -14,12 +22,15 @@ serializer System::serialize() {
bool System::unserialize(serializer &s) {
unsigned signature, version, crc32;
char description[512];
s.integer(signature);
s.integer(version);
s.integer(crc32);
s.array(description);
if(signature != 0x31545342) return false;
if(version != bsnesSaveStateVersion) return false;
if(version != bsnesSerializerVersion) return false;
//if(crc32 != cartridge.crc32()) return false;
scheduler.init();
@@ -27,7 +38,9 @@ bool System::unserialize(serializer &s) {
return true;
}
//========
//internal
//========
void System::serialize(serializer &s) {
s.integer(snes_region);
@@ -51,6 +64,8 @@ void System::serialize_all(serializer &s) {
ppu.serialize(s);
dsp.serialize(s);
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) supergameboy.serialize(s);
if(cartridge.has_srtc()) srtc.serialize(s);
if(cartridge.has_sdd1()) sdd1.serialize(s);
if(cartridge.has_spc7110()) spc7110.serialize(s);
@@ -59,6 +74,7 @@ void System::serialize_all(serializer &s) {
if(cartridge.has_dsp2()) dsp2.serialize(s);
if(cartridge.has_obc1()) obc1.serialize(s);
if(cartridge.has_st010()) st010.serialize(s);
if(cartridge.has_21fx()) s21fx.serialize(s);
}
//called once upon cartridge load event: perform dry-run state save.
@@ -68,12 +84,15 @@ void System::serialize_init() {
serializer s;
unsigned signature = 0, version = 0, crc32 = 0;
char description[512];
s.integer(signature);
s.integer(version);
s.integer(crc32);
s.array(description);
serialize_all(s);
serialize_size = s.size();
serializer_size = s.size();
}
#endif

View File

@@ -1,191 +0,0 @@
StateManager statemanager;
void StateManager::list(lstring &l) const {
l.reset();
for(unsigned x = 0; x < info.slotcount; x++) {
for(unsigned y = 0; y < info.slotcount; y++) {
if(info.slot[y] == x) {
unsigned n = l.size();
char slot[8];
sprintf(slot, "%3u", x + 1);
l[n] << slot << "\t";
char datetime[DateTimeSize + 1];
memcpy(datetime, &info.datetime[y * DateTimeSize], DateTimeSize);
datetime[DateTimeSize] = 0;
l[n] << datetime << "\t";
char desc[DescriptionSize + 1];
memcpy(desc, &info.description[y * DescriptionSize], DescriptionSize);
desc[DescriptionSize] = 0;
l[n] << desc;
}
}
}
}
bool StateManager::set_description(const char *filename, uint8 slot, const char *description) {
if(load(filename) == false) return false;
if(info.slotcount <= slot) return false;
file fp;
if(fp.open(filename, file::mode_readwrite) == false) return false;
uint8 index = findslot(slot);
if(index == SlotInvalid) { fp.close(); return false; }
char desc[DescriptionSize];
memset(&desc, 0, DescriptionSize);
strlcpy(desc, description, DescriptionSize);
fp.seek(DescIndex + index * DescriptionSize);
fp.write((uint8*)&desc[0], DescriptionSize);
fp.close();
return true;
}
serializer StateManager::load(const char *filename, uint8 slot) {
if(load(filename) == false) throw;
if(info.slotcount <= slot) throw;
uint8 index = findslot(slot);
if(index == SlotInvalid) throw;
file fp;
if(fp.open(filename, file::mode_read) == false) throw;
fp.seek(HeaderSize + system.serialize_size * index);
uint8 *data = new uint8[system.serialize_size];
fp.read(data, system.serialize_size);
serializer s(data, system.serialize_size);
delete[] data;
fp.close();
return s;
}
bool StateManager::save(const char *filename, uint8 slot, serializer &s, const char *description) {
//if no state archive exists ...
if(file::exists(filename) == false) {
//try and create one
if(create(filename) == false) return false;
}
//if we cannot load the existing state archive ...
if(load(filename) == false) {
//it's probably an older version, try and create a new one
if(create(filename) == false) return false;
//it still needs to be loaded before we can write to it
if(load(filename) == false) return false;
}
uint8 index = findslot(slot);
if(index == SlotInvalid) {
//create new slot instead of over-writing existing slot
if(info.slotcount >= 255) return false;
index = info.slotcount;
slot = info.slotcount;
}
file fp;
if(fp.open(filename, file::mode_readwrite) == false) return false;
fp.seek(SlotIndex + index);
fp.write(slot);
time_t current = time(0);
tm *ts = localtime(&current);
char timestamp[32];
sprintf(timestamp, "%.4u-%.2u-%.2u %.2u:%.2u:%.2u",
1900 + ts->tm_year, ts->tm_mon + 1, ts->tm_mday,
ts->tm_hour, ts->tm_min, ts->tm_sec,
(ts->tm_hour < 12 ? "AM" : "PM")
);
fp.seek(DateTimeIndex + index * DateTimeSize);
fp.write((uint8*)&timestamp[0], DateTimeSize);
char desc[DescriptionSize];
memset(&desc, 0, DescriptionSize);
strlcpy(desc, description, DescriptionSize);
fp.seek(DescIndex + index * DescriptionSize);
fp.write((uint8*)&desc[0], DescriptionSize);
fp.seek(HeaderSize + index * system.serialize_size);
fp.write(s.data(), s.size());
for(unsigned n = 0; n < system.serialize_size - s.size(); n++) fp.write(0x00);
fp.close();
return true;
}
bool StateManager::erase(const char *filename, uint8 slot) {
if(load(filename) == false) return false;
uint8 index = findslot(slot);
if(index == SlotInvalid) return false;
file fp;
if(fp.open(filename, file::mode_readwrite) == false) return false;
if(info.slotcount <= slot) return false;
//copy the very last state to the slot that is to be erased
uint8 lastslot = info.slotcount - 1;
info.slot[index] = info.slot[lastslot];
info.slot[lastslot] = SlotInvalid;
fp.seek(DateTimeIndex + index * DateTimeSize);
fp.write((uint8*)&info.datetime[lastslot * DateTimeSize], DateTimeSize);
fp.seek(DescIndex + index * DescriptionSize);
fp.write((uint8*)&info.description[lastslot * DescriptionSize], DescriptionSize);
fp.seek(HeaderSize + system.serialize_size * lastslot);
uint8 *data = new uint8[system.serialize_size];
fp.read(data, system.serialize_size);
fp.seek(HeaderSize + system.serialize_size * index);
fp.write(data, system.serialize_size);
delete[] data;
//decrement all IDs after the deleted one (removes empty slot ID from deletion)
for(unsigned n = 0; n < lastslot; n++) {
if(info.slot[n] > slot) info.slot[n]--;
}
fp.seek(SlotIndex);
fp.write(info.slot, 256);
unsigned size = fp.size();
fp.truncate(size - system.serialize_size);
return true;
}
bool StateManager::load(const char *filename) {
file fp;
if(fp.open(filename, file::mode_read) == false) return false;
unsigned filesize = fp.size();
if(filesize < HeaderSize) return false;
fp.seek(0);
if(fp.readl(4) != 0x31415342) return false;
if(fp.readl(4) != bsnesSaveStateVersion) return false;
fp.read((uint8*)&info.slot[0], 256);
fp.read((uint8*)&info.datetime[0], 256 * DateTimeSize);
fp.read((uint8*)&info.description[0], 256 * DescriptionSize);
info.slotcount = (filesize - HeaderSize) / system.serialize_size;
return true;
}
bool StateManager::create(const char *filename) const {
file fp;
if(fp.open(filename, file::mode_write) == false) return false;
fp.writel(0x31415342, 4); //signature ('BSA1')
fp.writel(bsnesSaveStateVersion, 4); //version
for(unsigned i = 0; i < 256 * SlotSize; i++) fp.write(SlotInvalid); //slot index
for(unsigned i = 0; i < 256 * DateTimeSize; i++) fp.write(0x20); //date / time
for(unsigned i = 0; i < 256 * DescriptionSize; i++) fp.write(0x00); //description
fp.close();
return true;
}
uint8 StateManager::findslot(uint8 slot) const {
if(slot == SlotInvalid) return SlotInvalid;
for(unsigned n = 0; n < info.slotcount; n++) {
if(info.slot[n] == slot) return n;
}
return SlotInvalid;
}

View File

@@ -1,35 +0,0 @@
class StateManager : noncopyable {
public:
enum {
SlotInvalid = 0xff,
SlotSize = 1,
DateTimeSize = 19,
DescriptionSize = 512,
HeaderSize = 8 + (256 * SlotSize) + (256 * DateTimeSize) + (256 * DescriptionSize),
SlotIndex = 8,
DateTimeIndex = SlotIndex + (256 * SlotSize),
DescIndex = DateTimeIndex + (256 * DateTimeSize),
};
void list(lstring&) const;
bool load(const char *filename);
bool set_description(const char *filename, uint8 slot, const char *description);
serializer load(const char *filename, uint8 slot);
bool save(const char *filename, uint8 slot, serializer&, const char *description);
bool erase(const char *filename, uint8 slot);
private:
struct Info {
unsigned slotcount;
uint8 slot[256 * SlotSize];
char datetime[256 * DateTimeSize];
char description[256 * DescriptionSize];
} info;
bool create(const char *filename) const;
uint8 findslot(uint8 slot) const;
};
extern StateManager statemanager;

View File

@@ -9,16 +9,16 @@ System system;
#include "debugger/debugger.cpp"
#include "serialization.cpp"
#include "scheduler/scheduler.cpp"
#include "statemanager/statemanager.cpp"
#include "video/video.cpp"
#include "audio/audio.cpp"
#include "input/input.cpp"
void System::coprocessor_enter() {
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) sgb.enter();
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) supergameboy.enter();
if(cartridge.has_superfx()) superfx.enter();
if(cartridge.has_sa1()) sa1.enter();
if(cartridge.has_21fx()) s21fx.enter();
while(true) {
scheduler.addclocks_cop(64 * 1024 * 1024);
@@ -60,7 +60,7 @@ void System::init(Interface *interface_) {
interface = interface_;
assert(interface != 0);
sgb.init();
supergameboy.init();
sa1.init();
superfx.init();
bsxbase.init();
@@ -78,6 +78,7 @@ void System::init(Interface *interface_) {
st010.init();
st011.init();
st018.init();
s21fx.init();
video.init();
audio.init();
@@ -95,6 +96,8 @@ void System::power() {
snes_region = (cartridge.region() == Cartridge::NTSC ? NTSC : PAL);
}
audio.coprocessor_enable(false);
scheduler.init();
bus.power();
@@ -108,7 +111,7 @@ void System::power() {
if(expansion() == ExpansionBSX) bsxbase.enable();
if(memory::bsxflash.data()) bsxflash.enable();
if(cartridge.mode() == Cartridge::ModeBsx) bsxcart.enable();
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) sgb.enable();
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) supergameboy.enable();
if(cartridge.has_superfx()) superfx.enable();
if(cartridge.has_sa1()) sa1.enable();
@@ -124,11 +127,12 @@ void System::power() {
if(cartridge.has_st010()) st010.enable();
if(cartridge.has_st011()) st011.enable();
if(cartridge.has_st018()) st018.enable();
if(cartridge.has_21fx()) s21fx.enable();
if(expansion() == ExpansionBSX) bsxbase.power();
if(memory::bsxflash.data()) bsxflash.power();
if(cartridge.mode() == Cartridge::ModeBsx) bsxcart.power();
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) sgb.power();
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) supergameboy.power();
if(cartridge.has_superfx()) superfx.power();
if(cartridge.has_sa1()) sa1.power();
@@ -144,8 +148,8 @@ void System::power() {
if(cartridge.has_st010()) st010.power();
if(cartridge.has_st011()) st011.power();
if(cartridge.has_st018()) st018.power();
if(cartridge.has_21fx()) s21fx.power();
//ppu.PPUcounter::reset();
cpu.power();
smp.power();
dsp.power();
@@ -160,7 +164,6 @@ void System::power() {
void System::reset() {
scheduler.init();
//ppu.PPUcounter::reset();
cpu.reset();
smp.reset();
dsp.reset();
@@ -170,7 +173,7 @@ void System::reset() {
if(expansion() == ExpansionBSX) bsxbase.reset();
if(memory::bsxflash.data()) bsxflash.reset();
if(cartridge.mode() == Cartridge::ModeBsx) bsxcart.reset();
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) sgb.reset();
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) supergameboy.reset();
if(cartridge.has_superfx()) superfx.reset();
if(cartridge.has_sa1()) sa1.reset();
@@ -186,6 +189,7 @@ void System::reset() {
if(cartridge.has_st010()) st010.reset();
if(cartridge.has_st011()) st011.reset();
if(cartridge.has_st018()) st018.reset();
if(cartridge.has_21fx()) s21fx.reset();
input.port_set_device(0, config.controller_port1);
input.port_set_device(1, config.controller_port2);
@@ -193,6 +197,10 @@ void System::reset() {
video.update();
}
void System::unload() {
if(cartridge.mode() == Cartridge::ModeSuperGameBoy) supergameboy.unload();
}
void System::scanline() {
video.scanline();
if(cpu.vcounter() == 241) scheduler.exit();

View File

@@ -2,7 +2,6 @@
#include "debugger/debugger.hpp"
#include "interface/interface.hpp"
#include "scheduler/scheduler.hpp"
#include "statemanager/statemanager.hpp"
#include "video/video.hpp"
#include "audio/audio.hpp"
@@ -17,22 +16,24 @@ public:
enum ExpansionPortDevice { ExpansionNone = 0, ExpansionBSX = 1 };
//system functions
virtual void run();
virtual void runtosave();
void run();
void runtosave();
virtual void init(Interface*);
virtual void term();
virtual void power();
virtual void reset();
void init(Interface*);
void term();
void power();
void reset();
void unload();
virtual void frame();
virtual void scanline();
void frame();
void scanline();
//return *active* region / expansion port device information
//settings cached upon power-on
Region region() const;
ExpansionPortDevice expansion() const;
unsigned serialize_size() const;
serializer serialize();
bool unserialize(serializer&);
@@ -40,7 +41,7 @@ public:
virtual ~System() {}
private:
unsigned serialize_size;
unsigned serializer_size;
void serialize(serializer&);
void serialize_all(serializer&);
void serialize_init();

View File

@@ -1,23 +1,38 @@
objects := ui-main $(objects)
objects := ui-main ui-base ui-debugger ui-input ui-movie ui-settings ui-state ui-tools $(objects)
objects += $(if $(call streq,$(platform),win),resource)
link += $(qtlib)
headers := $(call rwildcard,$(ui)/,%.hpp)
moc_headers := $(call rwildcard,$(ui)/,%.moc.hpp)
moc_objects := $(patsubst %.moc.hpp,%.moc,$(moc_headers))
moc_objects := $(foreach f,$(moc_headers),obj/$(notdir $(patsubst %.moc.hpp,%.moc,$f)))
qt_compile = $(call compile,-Iobj $(qtinc))
#############
### rules ###
#############
# automatically run moc on all .moc.hpp (MOC header) files
%.moc: $<; $(moc) -f $< -o $@
$(foreach f,$(moc_objects),$(eval $f: $(patsubst %.moc,%.moc.hpp,$f)))
%.moc: $<; $(moc) -i $< -o $@
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/)
$(call compile,$(qtinc))
# automatically generate %.moc build rules
__list = $(moc_headers)
$(foreach f,$(moc_objects), \
$(eval __file = $(word 1,$(__list))) \
$(eval __list = $(wordlist 2,$(words $(__list)),$(__list))) \
$(eval $f: $(__file)) \
)
$(ui)/resource/resource.rcc: $(ui)/resource/resource.qrc data/*
$(rcc) $(ui)/resource/resource.qrc -o $(ui)/resource/resource.rcc
obj/ui-main.o: $(ui)/main.cpp $(headers) $(wildcard $(ui)/*.cpp) $(wildcard $(ui)/platform/*.cpp) $(wildcard $(ui)/utility/*.cpp); $(qt_compile)
obj/ui-base.o: $(ui)/base/base.cpp $(headers) $(wildcard $(ui)/base/*.cpp); $(qt_compile)
obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(headers) $(wildcard $(ui)/debugger/*.cpp); $(qt_compile)
obj/ui-input.o: $(ui)/input/input.cpp $(headers) $(wildcard $(ui)/input/*.cpp); $(qt_compile)
obj/ui-movie.o: $(ui)/movie/movie.cpp $(headers) $(wildcard $(ui)/movie/*.cpp); $(qt_compile)
obj/ui-settings.o: $(ui)/settings/settings.cpp $(headers) $(wildcard $(ui)/settings/*.cpp); $(qt_compile)
obj/ui-state.o: $(ui)/state/state.cpp $(headers) $(wildcard $(ui)/state/*.cpp); $(qt_compile)
obj/ui-tools.o: $(ui)/tools/tools.cpp $(headers) $(wildcard $(ui)/tools/*.cpp); $(qt_compile)
obj/resource.rcc: $(ui)/resource/resource.qrc data/*
$(rcc) $(ui)/resource/resource.qrc -o obj/resource.rcc
obj/resource.o: $(ui)/resource/resource.rc
windres $(ui)/resource/resource.rc obj/resource.o
@@ -26,7 +41,7 @@ obj/resource.o: $(ui)/resource/resource.rc
### targets ###
###############
ui_build: $(ui)/resource/resource.rcc $(moc_objects);
ui_build: obj/resource.rcc $(moc_objects);
ui_clean:
-$(foreach f,$(moc_objects),@$(call delete,$f))
-@$(call delete,$(ui)/resource/resource.rcc)
-@$(call delete,obj/*.rcc)
-@$(call delete,obj/*.moc)

View File

@@ -1,3 +1,6 @@
#include "application.moc"
Application application;
#include "init.cpp"
#include "qb.cpp"
@@ -15,30 +18,30 @@ void Application::initPaths(const char *basename) {
}
if(strend(temp, "/") == false) strcat(temp, "/");
config.path.base = temp;
config().path.base = temp;
} else {
config.path.base = "";
config().path.base = "";
}
if(userpath(temp)) {
strtr(temp, "\\", "/");
if(strend(temp, "/") == false) strcat(temp, "/");
config.path.user = temp;
config().path.user = temp;
} else {
config.path.user = "";
config().path.user = "";
}
char cwd[PATH_MAX];
config.path.current = getcwd(cwd);
config().path.startup = getcwd(cwd);
}
void Application::locateFile(string &filename, bool createDataDirectory) {
//first, check if file exists in executable directory (single-user mode)
string temp = string() << config.path.base << filename;
string temp = string() << config().path.base << filename;
if(file::exists(temp) == false) {
//if not, use user data path (multi-user mode)
temp = config.path.user;
temp = config().path.user;
temp << ".bsnes";
if(createDataDirectory) mkdir(temp); //ensure directory exists
temp << "/" << filename;
@@ -66,9 +69,11 @@ int Application::main(int &argc, char **argv) {
app->setStyleSheet(defaultStylesheet);
}
config.load(configFilename);
config().load(configFilename);
mapper().bind();
init();
SNES::system.init(&interface);
mainWindow->system_loadSpecial_superGameBoy->setVisible(SNES::supergameboy.opened());
if(argc == 2) {
//if valid file was specified on the command-line, attempt to load it now
@@ -81,23 +86,12 @@ int Application::main(int &argc, char **argv) {
app->exec();
//QbWindow::hide() saves window geometry for next run
loaderWindow->window->hide();
htmlViewerWindow->window->hide();
aboutWindow->window->hide();
diskBrowser->window->hide();
folderCreator->window->hide();
settingsWindow->window->hide();
inputCaptureWindow->window->hide();
inputMouseCaptureWindow->window->hide();
inputCalibrationWindow->window->hide();
toolsWindow->window->hide();
debugger->window->hide();
breakpointEditor->window->hide();
memoryEditor->window->hide();
vramViewer->window->hide();
for(unsigned i = 0; i < windowList.size(); i++) {
windowList[i]->hide();
}
utility.unloadCartridge();
config.save(configFilename);
config().save(configFilename);
return 0;
}
@@ -110,9 +104,9 @@ void Application::run() {
QApplication::processEvents();
utility.updateSystemState();
inputManager.refresh();
mapper().poll();
if(config.input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation) {
if(config().input.focusPolicy == Configuration::Input::FocusPolicyPauseEmulation) {
bool active = mainWindow->isActive();
if(!autopause && !active) {
autopause = true;
@@ -126,6 +120,7 @@ void Application::run() {
if(SNES::cartridge.loaded() && !pause && !autopause && (!debug || debugrun)) {
SNES::system.run();
#if defined(DEBUGGER)
if(SNES::debugger.break_event != SNES::Debugger::None) {
debug = true;
debugrun = false;
@@ -133,6 +128,7 @@ void Application::run() {
debugger->event();
SNES::debugger.break_event = SNES::Debugger::None;
}
#endif
} else {
usleep(20 * 1000);
}
@@ -145,7 +141,7 @@ void Application::run() {
if(autosaveTime >= CLOCKS_PER_SEC * 60) {
//auto-save RAM once per minute in case of emulator crash
autosaveTime = 0;
if(config.system.autoSaveMemory == true) utility.saveMemory();
if(config().system.autoSaveMemory == true) utility.saveMemory();
}
if(screensaverTime >= CLOCKS_PER_SEC * 30) {

View File

@@ -29,6 +29,8 @@ public:
string configFilename;
string styleSheetFilename;
array<QbWindow*> windowList;
int main(int &argc, char **argv);
void locateFile(string &filename, bool createDataDirectory = false);
void initPaths(const char *basename);
@@ -39,4 +41,6 @@ public:
public slots:
void run();
} application;
};
extern Application application;

View File

@@ -1,25 +1,7 @@
#include "../base/main.moc"
#include "../base/diskbrowser.moc"
#include "../base/loader.moc"
#include "../base/htmlviewer.moc"
#include "../base/about.moc"
#include "../settings/settings.moc"
#include "../tools/tools.moc"
#include "../base/main.cpp"
#include "../base/diskbrowser.cpp"
#include "../base/loader.cpp"
#include "../base/htmlviewer.cpp"
#include "../base/about.cpp"
#include "../settings/settings.cpp"
#include "../tools/tools.cpp"
void Application::init() {
if(config.system.crashedOnLastRun == true) {
if(config().system.crashedOnLastRun == true) {
//emulator crashed on last run, disable all drivers
QMessageBox::warning(0, "bsnes Crash Notification", utf8() <<
QMessageBox::warning(0, "bsnes Crash Notification", string() <<
"<p><b>Warning:</b><br>bsnes crashed while attempting to initialize device "
"drivers the last time it was run.</p>"
"<p>To prevent this from occurring again, all drivers have been disabled. Please "
@@ -27,19 +9,19 @@ void Application::init() {
"restart the emulator for the changes to take effect. <i>Video, audio and input "
"will not work until you do this!</i></p>"
"<p><b>Settings that caused failure on last run:</b><br>"
<< "Video driver: " << config.system.video << "<br>"
<< "Audio driver: " << config.system.audio << "<br>"
<< "Input driver: " << config.system.input << "<br></p>"
<< "Video driver: " << config().system.video << "<br>"
<< "Audio driver: " << config().system.audio << "<br>"
<< "Input driver: " << config().system.input << "<br></p>"
);
config.system.video = "None";
config.system.audio = "None";
config.system.input = "None";
config().system.video = "None";
config().system.audio = "None";
config().system.input = "None";
}
if(config.system.video == "") config.system.video = video.default_driver();
if(config.system.audio == "") config.system.audio = audio.default_driver();
if(config.system.input == "") config.system.input = input.default_driver();
if(config().system.video == "") config().system.video = video.default_driver();
if(config().system.audio == "") config().system.audio = audio.default_driver();
if(config().system.input == "") config().system.input = input.default_driver();
mainWindow = new MainWindow;
loaderWindow = new LoaderWindow;
@@ -53,21 +35,23 @@ void Application::init() {
utility.updateFullscreenState();
QApplication::processEvents();
#if defined(DEBUGGER)
debugger = new Debugger;
#endif
settingsWindow = new SettingsWindow;
toolsWindow = new ToolsWindow;
//if emulator crashes while initializing drivers, next run will disable them all.
//this will allow user to choose different driver settings.
config.system.crashedOnLastRun = true;
config.save(configFilename);
config().system.crashedOnLastRun = true;
config().save(configFilename);
video.driver(config.system.video);
video.driver(config().system.video);
video.set(Video::Handle, (uintptr_t)mainWindow->canvas->winId());
video.set("QWidget", (QWidget*)mainWindow->canvas);
if(video.init() == false) {
QMessageBox::warning(0, "bsnes", utf8() <<
"<p><b>Warning:</b> " << config.system.video << " video driver failed to initialize. "
QMessageBox::warning(0, "bsnes", string() <<
"<p><b>Warning:</b> " << config().system.video << " video driver failed to initialize. "
"Video driver has been disabled.</p>"
"<p>Please go to Settings->Configuration->Advanced and choose a different driver, and "
"then restart the emulator for the changes to take effect.</p>"
@@ -76,14 +60,14 @@ void Application::init() {
video.init();
}
audio.driver(config.system.audio);
audio.driver(config().system.audio);
audio.set(Audio::Handle, (uintptr_t)mainWindow->canvas->winId());
audio.set(Audio::Frequency, config.audio.outputFrequency);
audio.set(Audio::Latency, config.audio.latency);
audio.set(Audio::Volume, config.audio.volume);
audio.set(Audio::Frequency, config().audio.outputFrequency);
audio.set(Audio::Latency, config().audio.latency);
audio.set(Audio::Volume, config().audio.volume);
if(audio.init() == false) {
QMessageBox::warning(0, "bsnes", utf8() <<
"<p><b>Warning:</b> " << config.system.audio << " audio driver failed to initialize. "
QMessageBox::warning(0, "bsnes", string() <<
"<p><b>Warning:</b> " << config().system.audio << " audio driver failed to initialize. "
"Audio driver has been disabled.</p>"
"<p>Please go to Settings->Configuration->Advanced and choose a different driver, and "
"then restart the emulator for the changes to take effect.</p>"
@@ -92,11 +76,11 @@ void Application::init() {
audio.init();
}
input.driver(config.system.input);
input.driver(config().system.input);
input.set("Handle", (uintptr_t)mainWindow->canvas->winId());
if(input.init() == false) {
QMessageBox::warning(0, "bsnes", utf8() <<
"<p><b>Warning:</b> " << config.system.input << " input driver failed to initialize. "
QMessageBox::warning(0, "bsnes", string() <<
"<p><b>Warning:</b> " << config().system.input << " input driver failed to initialize. "
"Input driver has been disabled.</p>"
"<p>Please go to Settings->Configuration->Advanced and choose a different driver, and "
"then restart the emulator for the changes to take effect.</p>"
@@ -106,18 +90,17 @@ void Application::init() {
}
//didn't crash, note this in the config file now in case a different kind of crash occurs later
config.system.crashedOnLastRun = false;
config.save(configFilename);
config().system.crashedOnLastRun = false;
config().save(configFilename);
inputManager.bind();
inputManager.refresh();
inputManager.refresh();
inputManager.onInput = bind(&Utility::inputEvent, &utility);
//no sense showing unusable options ...
pixelShaderWindow->setVisible(video.cap(Video::FragmentShader) || video.cap(Video::VertexShader));
utility.resizeMainWindow();
utility.updateAvSync();
utility.updateVideoMode();
utility.updateColorFilter();
utility.updatePixelShader();
utility.updateHardwareFilter();
utility.updateSoftwareFilter();
utility.updateEmulationSpeed();

View File

@@ -1,8 +1,10 @@
void QbWindow::shrink() {
for(unsigned i = 0; i < 2; i++) {
resize(0, 0);
usleep(2000);
QApplication::processEvents();
if(config().video.isFullscreen == false) {
for(unsigned i = 0; i < 2; i++) {
resize(0, 0);
usleep(2000);
QApplication::processEvents();
}
}
}
@@ -42,7 +44,14 @@ void QbWindow::closeEvent(QCloseEvent *event) {
QWidget::hide();
}
void QbWindow::keyReleaseEvent(QKeyEvent *event) {
if(event->key() == Qt::Key_Escape) close();
QWidget::keyReleaseEvent(event);
}
QbWindow::QbWindow(string &geometryString_) : geometryString(geometryString_) {
//keep track of all created windows (for geometry save on exit, always-on-top control, etc)
application.windowList.add(this);
}
//

View File

@@ -4,6 +4,7 @@ public:
void show();
void hide();
void closeEvent(QCloseEvent*);
void keyReleaseEvent(QKeyEvent*);
QbWindow(string&);
private:

View File

@@ -1,19 +1,21 @@
AboutWindow::AboutWindow() {
window = new QbWindow(config.geometry.aboutWindow);
window->setObjectName("about-window");
window->setWindowTitle("About bsnes ...");
#include "about.moc"
AboutWindow *aboutWindow;
AboutWindow::AboutWindow() : QbWindow(config().geometry.aboutWindow) {
setObjectName("about-window");
setWindowTitle("About bsnes ...");
layout = new QVBoxLayout;
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
window->setLayout(layout);
setLayout(layout);
logo = new Logo;
logo->setFixedSize(600, 106);
layout->addWidget(logo);
info = new QLabel(utf8() <<
info = new QLabel(string() <<
"<table>"
"<tr><td align='right'><b>Version: </b></td><td>" << bsnesVersion << "</td></tr>"
"<tr><td align='right'><b>Author: </b></td><td>byuu</td></tr>"

View File

@@ -1,15 +1,14 @@
class AboutWindow : public QObject {
class AboutWindow : public QbWindow {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
struct Logo : public QWidget {
void paintEvent(QPaintEvent*);
} *logo;
QLabel *info;
struct Logo : public QWidget {
void paintEvent(QPaintEvent*);
} *logo;
QLabel *info;
AboutWindow();
};
public slots:
} *aboutWindow;
extern AboutWindow *aboutWindow;

7
src/ui_qt/base/base.cpp Normal file
View File

@@ -0,0 +1,7 @@
#include "../ui-base.hpp"
#include "about.cpp"
#include "diskbrowser.cpp"
#include "htmlviewer.cpp"
#include "loader.cpp"
#include "main.cpp"

View File

@@ -1,17 +1,20 @@
#include "diskbrowser.moc"
FolderCreator *folderCreator;
DiskBrowser *diskBrowser;
//=============
//FolderCreator
//=============
FolderCreator::FolderCreator() {
window = new QbWindow(config.geometry.folderCreator);
window->setObjectName("folder-creator");
window->setWindowTitle("Create New Folder");
FolderCreator::FolderCreator() : QbWindow(config().geometry.folderCreator) {
setObjectName("folder-creator");
setWindowTitle("Create New Folder");
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
layout->setAlignment(Qt::AlignTop);
window->setLayout(layout);
setLayout(layout);
label = new QLabel("Folder name:");
layout->addWidget(label);
@@ -31,12 +34,12 @@ FolderCreator::FolderCreator() {
connect(name, SIGNAL(returnPressed()), this, SLOT(createFolder()));
connect(ok, SIGNAL(released()), this, SLOT(createFolder()));
connect(cancel, SIGNAL(released()), window, SLOT(hide()));
connect(cancel, SIGNAL(released()), this, SLOT(close()));
}
void FolderCreator::show() {
name->setText("");
window->show();
QbWindow::show();
name->setFocus();
}
@@ -45,12 +48,12 @@ void FolderCreator::createFolder() {
QMessageBox::warning(0, "Create New Folder", "<b>Note:</b> you must enter a folder name.");
} else {
string folderName = string()
<< diskBrowser->path->currentText().toUtf8().constData()
<< diskBrowser->model->rootPath().toUtf8().constData()
<< "/"
<< name->text().toUtf8().constData();
if(mkdir(folderName) == 0) {
window->hide();
hide();
} else {
QMessageBox::warning(0, "Create new Folder", "<b>Error:</b> failed to create folder. Please ensure only valid characters were used in the folder name.");
}
@@ -78,17 +81,6 @@ void DiskBrowserView::keyPressEvent(QKeyEvent *event) {
QTreeView::keyPressEvent(event);
}
void DiskBrowserView::keyReleaseEvent(QKeyEvent *event) {
//act like a modal dialog; close window on escape keypress
if(event->key() == Qt::Key_Escape) {
emit escape();
return;
}
//fallback: unrecognized keypresses get handled by the widget itself
QTreeView::keyReleaseEvent(event);
}
void DiskBrowserView::currentChanged(const QModelIndex &current, const QModelIndex &previous) {
QAbstractItemView::currentChanged(current, previous);
emit changed(current);
@@ -101,7 +93,7 @@ void DiskBrowserView::currentChanged(const QModelIndex &current, const QModelInd
void DiskBrowserImage::paintEvent(QPaintEvent*) {
QPainter painter(this);
if(name != "") {
QImage image(name);
QImage image(QString::fromUtf8(name));
painter.drawImage(0, 0, image);
}
}
@@ -110,82 +102,161 @@ void DiskBrowserImage::paintEvent(QPaintEvent*) {
//DiskBrowser
//===========
void DiskBrowser::chooseFolder(PathSettingWidget *widget, const char *title) {
void DiskBrowser::inputEvent(uint16_t scancode) {
if(!isActiveWindow() || isMinimized()) return;
//provide very simple support for controlling the window via gamepads
if(Joypad::isAnyHat(scancode)) {
int16_t state = mapper().state(scancode);
if(state == Joypad::HatUp) {
QKeyEvent event((QEvent::Type)6, Qt::Key_Up, Qt::NoModifier);
view->keyPressEvent(&event);
}
if(state == Joypad::HatDown) {
QKeyEvent event((QEvent::Type)6, Qt::Key_Down, Qt::NoModifier);
view->keyPressEvent(&event);
}
if(state == Joypad::HatLeft) {
QKeyEvent event((QEvent::Type)6, Qt::Key_Backspace, Qt::NoModifier);
view->keyPressEvent(&event);
}
if(state == Joypad::HatRight) {
QKeyEvent event((QEvent::Type)6, Qt::Key_Return, Qt::NoModifier);
view->keyPressEvent(&event);
}
}
}
void DiskBrowser::chooseFolder(const function<void (string)> &callback_, string &currentPath_, const char *title) {
callback = callback_;
currentPath = &currentPath_;
browseMode = Folder;
activePath = widget;
window->hide();
hide();
group->hide();
ok->setText("Choose");
window->setWindowTitle(utf8() << title);
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setWindowTitle(string() << title);
setPath(*currentPath);
setNameFilters("Folders ()");
window->show();
show();
}
void DiskBrowser::chooseFile(const function<void (string)> &callback_, string &currentPath_, const char *title) {
callback = callback_;
currentPath = &currentPath_;
browseMode = File;
hide();
group->hide();
ok->setText("Choose");
setWindowTitle(string() << title);
setPath(*currentPath);
setNameFilters("All Files (*)");
show();
}
void DiskBrowser::loadCartridge() {
currentPath = &config().path.current.cartridge;
browseMode = Cartridge;
window->hide();
group->show();
hide();
group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
window->setWindowTitle("Load Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "SNES cartridges (*.sfc *.smc" << reader.filterList << ");;All files (*)");
window->show();
setWindowTitle("Load Cartridge");
setPath(config().path.rom == "" ? *currentPath : config().path.rom);
setNameFilters(string()
<< "SNES cartridges (*.sfc" << reader.extensionList << reader.compressionList << ");;"
<< "BS-X cartridges (*.bs" << reader.compressionList << ");;"
<< "Sufami Turbo cartridges (*.st" << reader.compressionList << ");;"
<< "Game Boy cartridges (*.gb *.sgb *.gbc" << reader.compressionList << ");;"
<< "All files (*)"
);
filter->setCurrentIndex(config().path.current.filter);
show();
}
void DiskBrowser::loadBaseCartridge() {
currentPath = &config().path.current.cartridge;
browseMode = BaseCartridge;
window->hide();
group->show();
hide();
group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
window->setWindowTitle("Load Base Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "SNES cartridges (*.sfc *.smc" << reader.filterList << ");;All files (*)");
window->show();
setWindowTitle("Load Base Cartridge");
setPath(config().path.rom == "" ? *currentPath : config().path.rom);
setNameFilters(string()
<< "SNES cartridges (*.sfc" << reader.extensionList << reader.compressionList << ");;"
<< "All files (*)"
);
show();
}
void DiskBrowser::loadBsxCartridge() {
currentPath = &config().path.current.bsx;
browseMode = BsxCartridge;
window->hide();
group->show();
hide();
group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
window->setWindowTitle("Load BS-X Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "BS-X cartridges (*.bs" << reader.filterList << ");;All files (*)");
window->show();
setWindowTitle("Load BS-X Cartridge");
setPath(config().path.rom == "" ? *currentPath : config().path.rom);
setNameFilters(string()
<< "BS-X cartridges (*.bs" << reader.compressionList << ");;"
<< "All files (*)"
);
show();
}
void DiskBrowser::loadSufamiTurboCartridge1() {
currentPath = &config().path.current.st;
browseMode = SufamiTurboCartridge1;
window->hide();
group->show();
hide();
group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
window->setWindowTitle("Load Slot-A Sufami Turbo Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "Sufami Turbo cartridges (*.st" << reader.filterList << ");;All files (*)");
window->show();
setWindowTitle("Load Slot-A Sufami Turbo Cartridge");
setPath(config().path.rom == "" ? *currentPath : config().path.rom);
setNameFilters(string()
<< "Sufami Turbo cartridges (*.st" << reader.compressionList << ");;"
<< "All files (*)"
);
show();
}
void DiskBrowser::loadSufamiTurboCartridge2() {
currentPath = &config().path.current.st;
browseMode = SufamiTurboCartridge2;
window->hide();
group->show();
hide();
group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
window->setWindowTitle("Load Slot-B Sufami Turbo Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "Sufami Turbo Cartridges (*.st" << reader.filterList << ");;All files (*)");
window->show();
setWindowTitle("Load Slot-B Sufami Turbo Cartridge");
setPath(config().path.rom == "" ? *currentPath : config().path.rom);
setNameFilters(string()
<< "Sufami Turbo Cartridges (*.st" << reader.compressionList << ");;"
<< "All files (*)"
);
show();
}
void DiskBrowser::loadSuperGameBoyCartridge() {
currentPath = &config().path.current.sgb;
browseMode = SuperGameBoyCartridge;
window->hide();
group->show();
hide();
group->setVisible(config().diskBrowser.showPanel);
ok->setText("Load");
window->setWindowTitle("Load Super Game Boy Cartridge");
setPath(utf8() << (config.path.rom != "" ? config.path.rom : config.path.current));
setNameFilters(utf8() << "Game Boy cartridges (*.gb *.gbc" << reader.filterList << ");;All files (*)");
window->show();
setWindowTitle("Load Super Game Boy Cartridge");
setPath(config().path.rom == "" ? *currentPath : config().path.rom);
setNameFilters(string()
<< "Game Boy cartridges (*.gb *.sgb *.gbc" << reader.compressionList << ");;"
<< "All files (*)"
);
show();
}
string DiskBrowser::queryImageInformation() {
@@ -231,7 +302,7 @@ void DiskBrowser::changeItem(const QModelIndex &item) {
ok->setEnabled(true);
image->name = nall::basename(filename) << ".png";
if(file::exists(image->name) == false) image->name = "";
info->setText(utf8() << queryImageInformation());
info->setText(string() << queryImageInformation());
string patch = nall::basename(filename) << ".ups";
applyPatch->setVisible(file::exists(patch));
}
@@ -246,17 +317,48 @@ void DiskBrowser::loadSelected() {
if(browseMode == Folder || loadable == true) {
QModelIndex item = view->currentIndex();
config.path.current = dir(model->filePath(item).toUtf8().constData());
window->hide();
if(currentPath) *currentPath = dir(model->filePath(item).toUtf8().constData());
hide();
switch(browseMode) { default:
case Folder: activePath->selectPath(filename); break;
case Cartridge: utility.loadCartridgeNormal(filename); break;
case BaseCartridge: loaderWindow->selectBaseCartridge(filename); break;
case BsxCartridge: loaderWindow->selectSlot1Cartridge(filename); break;
case SufamiTurboCartridge1: loaderWindow->selectSlot1Cartridge(filename); break;
case SufamiTurboCartridge2: loaderWindow->selectSlot2Cartridge(filename); break;
case SuperGameBoyCartridge: loaderWindow->selectSlot1Cartridge(filename); break;
if(browseMode == Folder || browseMode == File) {
callback(filename);
} else if(browseMode == Cartridge) {
//quick-loading mode: determine load type via active filter
config().path.current.filter = filter->currentIndex();
if(config().path.current.filter == 1) { //"BS-X cartridges"
if(config().path.bsx == "") {
loaderWindow->loadBsxCartridge("", filename);
} else {
utility.loadCartridgeBsx(config().path.bsx, filename);
}
} else if(config().path.current.filter == 2) { //"Sufami Turbo cartridges"
if(config().path.st == "") {
loaderWindow->loadSufamiTurboCartridge("", filename, "");
} else {
utility.loadCartridgeSufamiTurbo(config().path.st, filename, "");
}
} else if(config().path.current.filter == 3) { //"Game Boy cartridges"
if(SNES::supergameboy.opened() == false) {
QMessageBox::warning(0, "Warning", "Super Game Boy support missing - cartridge cannot be loaded.");
} else if(config().path.sgb == "") {
loaderWindow->loadSuperGameBoyCartridge("", filename);
} else {
utility.loadCartridgeSuperGameBoy(config().path.sgb, filename);
}
} else { //"SNES cartridges" (0) or "All files" (4)
utility.loadCartridgeNormal(filename);
}
} else if(browseMode == BaseCartridge) {
loaderWindow->selectBaseCartridge(filename);
} else if(browseMode == BsxCartridge) {
loaderWindow->selectSlot1Cartridge(filename);
} else if(browseMode == SufamiTurboCartridge1) {
loaderWindow->selectSlot1Cartridge(filename);
} else if(browseMode == SufamiTurboCartridge2) {
loaderWindow->selectSlot2Cartridge(filename);
} else if(browseMode == SuperGameBoyCartridge) {
loaderWindow->selectSlot1Cartridge(filename);
}
} else {
//this is a standard folder in ROM loading mode; enter into the folder
@@ -271,7 +373,10 @@ void DiskBrowser::setPath(const QString &reqPath) {
disconnect(path, SIGNAL(currentIndexChanged(int)), this, SLOT(updatePath()));
QString effectivePath = reqPath;
if(effectivePath == "<root>") {
if(effectivePath == "") {
effectivePath = QString::fromUtf8(config().path.startup);
}
if(effectivePath == "<root>" || QDir(reqPath).exists() == false) {
effectivePath = "";
newFolder->setEnabled(false);
} else {
@@ -306,7 +411,7 @@ void DiskBrowser::setNameFilters(const QString &filters) {
filterPart.split(";;", filterData);
for(unsigned i = 0; i < filterPart.size(); i++) {
filter->addItem(utf8() << filterPart[i]);
filter->addItem(filterPart[i]);
}
connect(filter, SIGNAL(currentIndexChanged(int)), this, SLOT(updateFilter()));
@@ -314,7 +419,7 @@ void DiskBrowser::setNameFilters(const QString &filters) {
}
void DiskBrowser::cdUp() {
folderCreator->window->hide();
folderCreator->hide();
//if we aren't already at the root node, select the second node, which is one path higher than the current
if(path->count() > 1) path->setCurrentIndex(1);
}
@@ -349,8 +454,8 @@ bool DiskBrowser::currentFilename(string &filename) {
if(browseMode != Folder) {
if(model->isDir(item) == true) {
QDir directory(utf8() << filename);
directory.setNameFilters(QStringList() << "*.sfc" << "*.smc");
QDir directory(filename);
directory.setNameFilters(QStringList() << "*.sfc");
QStringList list = directory.entryList(QDir::Files | QDir::NoDotAndDotDot);
if(list.count() == 1) {
filename << "/" << list[0].toUtf8().constData();
@@ -364,15 +469,20 @@ bool DiskBrowser::currentFilename(string &filename) {
return loadable;
}
DiskBrowser::DiskBrowser() {
window = new QbWindow(config.geometry.diskBrowser);
window->setObjectName("disk-browser");
window->resize(720, 480);
void DiskBrowser::toggleShowPanel() {
showPanel->setChecked(!showPanel->isChecked());
config().diskBrowser.showPanel = showPanel->isChecked();
group->setVisible(config().diskBrowser.showPanel);
}
DiskBrowser::DiskBrowser() : QbWindow(config().geometry.diskBrowser) {
setObjectName("disk-browser");
resize(720, 480);
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
window->setLayout(layout);
setLayout(layout);
topLayout = new QHBoxLayout;
layout->addLayout(topLayout);
@@ -384,6 +494,7 @@ DiskBrowser::DiskBrowser() {
browseLayout->addLayout(pathLayout);
path = new QComboBox;
path->setEditable(true);
path->setMinimumContentsLength(16);
path->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
path->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
@@ -434,12 +545,14 @@ DiskBrowser::DiskBrowser() {
controlLayout->addWidget(filter);
options = new QPushButton("Options");
options->setEnabled(false);
controlLayout->addWidget(options);
QMenu *menu = new QMenu;
menu = new QMenu;
options->setMenu(menu);
menu->addAction(showPanel = new QbCheckAction("Show Side Panel", 0));
showPanel->setChecked(config().diskBrowser.showPanel);
ok = new QPushButton("Ok");
ok->setEnabled(false);
controlLayout->addWidget(ok);
@@ -468,7 +581,8 @@ DiskBrowser::DiskBrowser() {
connect(view, SIGNAL(cdUp()), this, SLOT(cdUp()));
connect(view, SIGNAL(activated(const QModelIndex&)), this, SLOT(activateItem(const QModelIndex&)));
connect(view, SIGNAL(changed(const QModelIndex&)), this, SLOT(changeItem(const QModelIndex&)));
connect(view, SIGNAL(escape()), window, SLOT(hide()));
connect(ok, SIGNAL(released()), this, SLOT(loadSelected()));
connect(cancel, SIGNAL(released()), window, SLOT(hide()));
connect(cancel, SIGNAL(released()), this, SLOT(close()));
connect(showPanel, SIGNAL(triggered()), this, SLOT(toggleShowPanel()));
}

View File

@@ -1,10 +1,7 @@
class PathSettingWidget;
class FolderCreator : public QObject {
class FolderCreator : public QbWindow {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QLabel *label;
QLineEdit *name;
@@ -17,19 +14,19 @@ public:
public slots:
void show();
void createFolder();
} *folderCreator;
};
extern FolderCreator *folderCreator;
class DiskBrowserView : public QTreeView {
Q_OBJECT
public:
void keyPressEvent(QKeyEvent*);
void keyReleaseEvent(QKeyEvent*);
signals:
void cdUp();
void changed(const QModelIndex&);
void escape();
public slots:
void currentChanged(const QModelIndex&, const QModelIndex&);
@@ -41,11 +38,10 @@ public:
void paintEvent(QPaintEvent*);
};
class DiskBrowser : public QObject {
class DiskBrowser : public QbWindow {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QHBoxLayout *topLayout;
QVBoxLayout *browseLayout;
@@ -66,15 +62,22 @@ public:
QPushButton *ok;
QPushButton *cancel;
QFileSystemModel *model;
PathSettingWidget *activePath;
void chooseFolder(PathSettingWidget*, const char*);
QMenu *menu;
QbCheckAction *showPanel;
void inputEvent(uint16_t scancode);
void chooseFolder(const function<void (string)>&, string&, const char*);
void chooseFile(const function<void (string)>&, string&, const char*);
void loadCartridge();
void loadBaseCartridge();
void loadBsxCartridge();
void loadSufamiTurboCartridge1();
void loadSufamiTurboCartridge2();
void loadSuperGameBoyCartridge();
string queryImageInformation();
void setPath(const QString&);
@@ -90,9 +93,15 @@ public slots:
void changeItem(const QModelIndex&);
void loadSelected();
void toggleShowPanel();
private:
function<void (string)> callback;
string *currentPath;
enum BrowseMode {
Folder,
File,
Cartridge,
BaseCartridge,
BsxCartridge,
@@ -102,4 +111,6 @@ private:
} browseMode;
bool currentFilename(string&);
} *diskBrowser;
};
extern DiskBrowser *diskBrowser;

View File

@@ -1,19 +1,21 @@
HtmlViewerWindow::HtmlViewerWindow() {
window = new QbWindow(config.geometry.htmlViewerWindow);
window->setObjectName("html-window");
window->resize(560, 480);
#include "htmlviewer.moc"
HtmlViewerWindow *htmlViewerWindow;
HtmlViewerWindow::HtmlViewerWindow() : QbWindow(config().geometry.htmlViewerWindow) {
setObjectName("html-window");
resize(560, 480);
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0);
window->setLayout(layout);
setLayout(layout);
document = new QTextBrowser;
layout->addWidget(document);
}
void HtmlViewerWindow::show(const char *title, const char *htmlData) {
document->setHtml(utf8() << htmlData);
window->setWindowTitle(title);
window->show();
document->setHtml(string() << htmlData);
setWindowTitle(title);
QbWindow::show();
}

View File

@@ -1,13 +1,14 @@
class HtmlViewerWindow : public QObject {
class HtmlViewerWindow : public QbWindow {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QTextBrowser *document;
QTextBrowser *document;
void show(const char *title, const char *htmlData);
HtmlViewerWindow();
public slots:
} *htmlViewerWindow;
};
extern HtmlViewerWindow *htmlViewerWindow;

View File

@@ -1,70 +1,63 @@
LoaderWindow::LoaderWindow() {
window = new QbWindow(config.geometry.loaderWindow);
window->setObjectName("loader-window");
window->setMinimumWidth(520);
#include "loader.moc"
LoaderWindow *loaderWindow;
LoaderWindow::LoaderWindow() : QbWindow(config().geometry.loaderWindow) {
setObjectName("loader-window");
setMinimumWidth(520);
layout = new QVBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(0);
window->setLayout(layout);
layout->setSpacing(Style::WidgetSpacing);
layout->setAlignment(Qt::AlignTop);
setLayout(layout);
grid = new QGridLayout; {
baseLabel = new QLabel("Base cartridge:");
grid->addWidget(baseLabel, 0, 0);
baseFile = new QLineEdit;
baseFile->setReadOnly(true);
grid->addWidget(baseFile, 0, 1);
baseBrowse = new QPushButton("Browse ...");
grid->addWidget(baseBrowse, 0, 2);
baseClear = new QPushButton("Clear");
grid->addWidget(baseClear, 0, 3);
slot1Label = new QLabel("Slot A cartridge:");
grid->addWidget(slot1Label, 1, 0);
slot1File = new QLineEdit;
slot1File->setReadOnly(true);
grid->addWidget(slot1File, 1, 1);
slot1Browse = new QPushButton("Browse ...");
grid->addWidget(slot1Browse, 1, 2);
slot1Clear = new QPushButton("Clear");
grid->addWidget(slot1Clear, 1, 3);
slot2Label = new QLabel("Slot B cartridge:");
grid->addWidget(slot2Label, 2, 0);
slot2File = new QLineEdit;
slot2File->setReadOnly(true);
grid->addWidget(slot2File, 2, 1);
slot2Browse = new QPushButton("Browse ...");
grid->addWidget(slot2Browse, 2, 2);
slot2Clear = new QPushButton("Clear");
grid->addWidget(slot2Clear, 2, 3);
}
grid->setSpacing(Style::WidgetSpacing);
grid = new QGridLayout;
layout->addLayout(grid);
layout->addSpacing(Style::WidgetSpacing);
controls = new QHBoxLayout; {
load = new QPushButton("Load");
controls->addWidget(load);
baseLabel = new QLabel("Base cartridge:");
grid->addWidget(baseLabel, 0, 0);
cancel = new QPushButton("Cancel");
controls->addWidget(cancel);
}
controls->setSpacing(Style::WidgetSpacing);
layout->addLayout(controls);
baseFile = new QLineEdit;
baseFile->setReadOnly(true);
grid->addWidget(baseFile, 0, 1);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
layout->addWidget(spacer);
baseBrowse = new QPushButton("Browse ...");
grid->addWidget(baseBrowse, 0, 2);
baseClear = new QPushButton("Clear");
grid->addWidget(baseClear, 0, 3);
slot1Label = new QLabel("Slot A cartridge:");
grid->addWidget(slot1Label, 1, 0);
slot1File = new QLineEdit;
slot1File->setReadOnly(true);
grid->addWidget(slot1File, 1, 1);
slot1Browse = new QPushButton("Browse ...");
grid->addWidget(slot1Browse, 1, 2);
slot1Clear = new QPushButton("Clear");
grid->addWidget(slot1Clear, 1, 3);
slot2Label = new QLabel("Slot B cartridge:");
grid->addWidget(slot2Label, 2, 0);
slot2File = new QLineEdit;
slot2File->setReadOnly(true);
grid->addWidget(slot2File, 2, 1);
slot2Browse = new QPushButton("Browse ...");
grid->addWidget(slot2Browse, 2, 2);
slot2Clear = new QPushButton("Clear");
grid->addWidget(slot2Clear, 2, 3);
load = new QPushButton("Load");
grid->addWidget(load, 3, 2);
cancel = new QPushButton("Cancel");
grid->addWidget(cancel, 3, 3);
connect(baseBrowse, SIGNAL(released()), this, SLOT(selectBaseCartridge()));
connect(baseClear, SIGNAL(released()), this, SLOT(clearBaseCartridge()));
@@ -73,7 +66,7 @@ LoaderWindow::LoaderWindow() {
connect(slot2Browse, SIGNAL(released()), this, SLOT(selectSlot2Cartridge()));
connect(slot2Clear, SIGNAL(released()), this, SLOT(clearSlot2Cartridge()));
connect(load, SIGNAL(released()), this, SLOT(onLoad()));
connect(cancel, SIGNAL(released()), this, SLOT(onCancel()));
connect(cancel, SIGNAL(released()), this, SLOT(close()));
}
void LoaderWindow::syncUi() {
@@ -82,7 +75,7 @@ void LoaderWindow::syncUi() {
}
void LoaderWindow::loadBsxSlottedCartridge(const char *filebase, const char *fileSlot1) {
window->hide();
hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->hide(), slot2File->hide(), slot2Browse->hide(), slot2Clear->hide();
@@ -98,7 +91,7 @@ void LoaderWindow::loadBsxSlottedCartridge(const char *filebase, const char *fil
}
void LoaderWindow::loadBsxCartridge(const char *fileBase, const char *fileSlot1) {
window->hide();
hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->hide(), slot2File->hide(), slot2Browse->hide(), slot2Clear->hide();
@@ -114,7 +107,7 @@ void LoaderWindow::loadBsxCartridge(const char *fileBase, const char *fileSlot1)
}
void LoaderWindow::loadSufamiTurboCartridge(const char *fileBase, const char *fileSlot1, const char *fileSlot2) {
window->hide();
hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->show(), slot2File->show(), slot2Browse->show(), slot2Clear->show();
@@ -132,7 +125,7 @@ void LoaderWindow::loadSufamiTurboCartridge(const char *fileBase, const char *fi
}
void LoaderWindow::loadSuperGameBoyCartridge(const char *fileBase, const char *fileSlot1) {
window->hide();
hide();
baseLabel->show(), baseFile->show(), baseBrowse->show(), baseClear->show();
slot1Label->show(), slot1File->show(), slot1Browse->show(), slot1Clear->show();
slot2Label->hide(), slot2File->hide(), slot2Browse->hide(), slot2Clear->hide();
@@ -148,24 +141,24 @@ void LoaderWindow::loadSuperGameBoyCartridge(const char *fileBase, const char *f
}
void LoaderWindow::showWindow(const char *title) {
window->setWindowTitle(title);
window->show();
window->shrink();
setWindowTitle(title);
show();
shrink();
load->setFocus();
}
void LoaderWindow::selectBaseCartridge(const char *filename) {
baseFile->setText(utf8() << filename);
baseFile->setText(string() << filename);
syncUi();
}
void LoaderWindow::selectSlot1Cartridge(const char *filename) {
slot1File->setText(utf8() << filename);
slot1File->setText(string() << filename);
syncUi();
}
void LoaderWindow::selectSlot2Cartridge(const char *filename) {
slot2File->setText(utf8() << filename);
slot2File->setText(string() << filename);
syncUi();
}
@@ -208,7 +201,7 @@ void LoaderWindow::clearSlot2Cartridge() {
}
void LoaderWindow::onLoad() {
window->hide();
hide();
string base = baseFile->text().toUtf8().data();
string slot1 = slot1File->text().toUtf8().data();
string slot2 = slot2File->text().toUtf8().data();
@@ -219,22 +212,18 @@ void LoaderWindow::onLoad() {
} break;
case SNES::Cartridge::ModeBsx: {
config.path.bsx = base;
config().path.bsx = base;
utility.loadCartridgeBsx(base, slot1);
} break;
case SNES::Cartridge::ModeSufamiTurbo: {
config.path.st = base;
config().path.st = base;
utility.loadCartridgeSufamiTurbo(base, slot1, slot2);
} break;
case SNES::Cartridge::ModeSuperGameBoy: {
config.path.sgb = base;
config().path.sgb = base;
utility.loadCartridgeSuperGameBoy(base, slot1);
} break;
}
}
void LoaderWindow::onCancel() {
window->hide();
}

View File

@@ -1,26 +1,23 @@
class LoaderWindow : public QObject {
class LoaderWindow : public QbWindow {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
QGridLayout *grid;
QLabel *baseLabel;
QLineEdit *baseFile;
QPushButton *baseBrowse;
QPushButton *baseClear;
QLabel *slot1Label;
QLineEdit *slot1File;
QPushButton *slot1Browse;
QPushButton *slot1Clear;
QLabel *slot2Label;
QLineEdit *slot2File;
QPushButton *slot2Browse;
QPushButton *slot2Clear;
QHBoxLayout *controls;
QPushButton *load;
QPushButton *cancel;
QWidget *spacer;
QGridLayout *grid;
QLabel *baseLabel;
QLineEdit *baseFile;
QPushButton *baseBrowse;
QPushButton *baseClear;
QLabel *slot1Label;
QLineEdit *slot1File;
QPushButton *slot1Browse;
QPushButton *slot1Clear;
QLabel *slot2Label;
QLineEdit *slot2File;
QPushButton *slot2Browse;
QPushButton *slot2Clear;
QPushButton *load;
QPushButton *cancel;
void syncUi();
void loadBsxSlottedCartridge(const char*, const char*);
@@ -40,11 +37,11 @@ public slots:
void clearSlot1Cartridge();
void selectSlot2Cartridge();
void clearSlot2Cartridge();
void onLoad();
void onCancel();
private:
SNES::Cartridge::Mode mode;
void showWindow(const char *title);
} *loaderWindow;
};
extern LoaderWindow *loaderWindow;

View File

@@ -1,7 +1,9 @@
MainWindow::MainWindow() {
window = new Window(config.geometry.mainWindow);
window->setObjectName("main-window");
window->setWindowTitle(utf8() << bsnesTitle << " v" << bsnesVersion);
#include "main.moc"
MainWindow *mainWindow;
MainWindow::MainWindow() : QbWindow(config().geometry.mainWindow) {
setObjectName("main-window");
setWindowTitle(string() << bsnesTitle << " v" << bsnesVersion);
//menu bar
#if defined(PLATFORM_OSX)
@@ -10,127 +12,183 @@ MainWindow::MainWindow() {
menuBar = new QMenuBar;
#endif
system = menuBar->addMenu("System");
system_load = system->addAction("Load Cartridge ...");
system_load->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial = system->addMenu("Load Special");
system_loadSpecial->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_bsxSlotted = system_loadSpecial->addAction("Load BS-X Slotted Cartridge ...");
system_loadSpecial_bsxSlotted->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_bsx = system_loadSpecial->addAction("Load BS-X Cartridge ...");
system_loadSpecial_bsx->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_sufamiTurbo = system_loadSpecial->addAction("Load Sufami Turbo Cartridge ...");
system_loadSpecial_sufamiTurbo->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_superGameBoy = system_loadSpecial->addAction("Load Super Game Boy Cartridge ...");
system_loadSpecial_superGameBoy->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_superGameBoy->setVisible(false);
system->addSeparator();
system->addAction(system_power = new QbCheckAction("Power", 0));
system_reset = system->addAction("Reset");
system_reset->setIcon(QIcon(":/16x16/view-refresh.png"));
system->addSeparator();
system_port1 = system->addMenu("Controller Port 1");
system_port1->setIcon(QIcon(":/16x16/input-gaming.png"));
system_port1->addAction(system_port1_none = new QbRadioAction("None", 0));
system_port1->addAction(system_port1_joypad = new QbRadioAction("Joypad", 0));
system_port1->addAction(system_port1_multitap = new QbRadioAction("Multitap", 0));
system_port1->addAction(system_port1_mouse = new QbRadioAction("Mouse", 0));
system_port2 = system->addMenu("Controller Port 2");
system_port2->setIcon(QIcon(":/16x16/input-gaming.png"));
system_port2->addAction(system_port2_none = new QbRadioAction("None", 0));
system_port2->addAction(system_port2_joypad = new QbRadioAction("Joypad", 0));
system_port2->addAction(system_port2_multitap = new QbRadioAction("Multitap", 0));
system_port2->addAction(system_port2_mouse = new QbRadioAction("Mouse", 0));
system_port2->addAction(system_port2_superscope = new QbRadioAction("Super Scope", 0));
system_port2->addAction(system_port2_justifier = new QbRadioAction("Justifier", 0));
system_port2->addAction(system_port2_justifiers = new QbRadioAction("Two Justifiers", 0));
#if !defined(PLATFORM_OSX)
system->addSeparator();
#endif
system_exit = system->addAction("Exit");
system_exit->setIcon(QIcon(":/16x16/process-stop.png"));
system_exit->setMenuRole(QAction::QuitRole);
system = menuBar->addMenu("&System");
settings = menuBar->addMenu("Settings");
settings_videoMode = settings->addMenu("Video Mode");
settings_videoMode->setIcon(QIcon(":/16x16/video-display.png"));
settings_videoMode->addAction(settings_videoMode_1x = new QbRadioAction("Scale 1x", 0));
settings_videoMode->addAction(settings_videoMode_2x = new QbRadioAction("Scale 2x", 0));
settings_videoMode->addAction(settings_videoMode_3x = new QbRadioAction("Scale 3x", 0));
settings_videoMode->addAction(settings_videoMode_4x = new QbRadioAction("Scale 4x", 0));
settings_videoMode->addAction(settings_videoMode_max = new QbRadioAction("Scale Max", 0));
settings_videoMode->addSeparator();
settings_videoMode->addAction(settings_videoMode_correctAspectRatio = new QbCheckAction("Correct Aspect Ratio", 0));
settings_videoMode->addAction(settings_videoMode_fullscreen = new QbCheckAction("Fullscreen", 0));
settings_videoMode->addSeparator();
settings_videoMode->addAction(settings_videoMode_ntsc = new QbRadioAction("NTSC", 0));
settings_videoMode->addAction(settings_videoMode_pal = new QbRadioAction("PAL", 0));
system_load = system->addAction("Load &Cartridge ...");
system_load->setIcon(QIcon(":/16x16/document-open.png"));
if(filter.opened()) {
settings_videoFilter = settings->addMenu("Video Filter");
settings_videoFilter->setIcon(QIcon(":/16x16/image-x-generic.png"));
system_loadSpecial = system->addMenu("Load &Special");
system_loadSpecial->setIcon(QIcon(":/16x16/document-open.png"));
settings_videoFilter_configure = settings_videoFilter->addAction("Configure Active Filter ...");
settings_videoFilter_configure->setIcon(QIcon(":/16x16/preferences-desktop.png"));
settings_videoFilter->addSeparator();
system_loadSpecial_bsxSlotted = system_loadSpecial->addAction("Load BS-X &Slotted Cartridge ...");
system_loadSpecial_bsxSlotted->setIcon(QIcon(":/16x16/document-open.png"));
settings_videoFilter->addAction(settings_videoFilter_none = new QbRadioAction("None", 0));
settings_videoFilter_list.add(settings_videoFilter_none);
system_loadSpecial_bsx = system_loadSpecial->addAction("Load &BS-X Cartridge ...");
system_loadSpecial_bsx->setIcon(QIcon(":/16x16/document-open.png"));
lstring filterlist;
filterlist.split(";", filter.dl_supported());
for(unsigned i = 0; i < filterlist.size(); i++) {
QbRadioAction *action = new QbRadioAction(utf8() << filterlist[i], 0);
settings_videoFilter->addAction(action);
settings_videoFilter_list.add(action);
}
system_loadSpecial_sufamiTurbo = system_loadSpecial->addAction("Load Sufami &Turbo Cartridge ...");
system_loadSpecial_sufamiTurbo->setIcon(QIcon(":/16x16/document-open.png"));
system_loadSpecial_superGameBoy = system_loadSpecial->addAction("Load Super &Game Boy Cartridge ...");
system_loadSpecial_superGameBoy->setIcon(QIcon(":/16x16/document-open.png"));
system->addSeparator();
system->addAction(system_power = new QbCheckAction("&Power", 0));
system_reset = system->addAction("&Reset");
system_reset->setIcon(QIcon(":/16x16/view-refresh.png"));
system->addSeparator();
system_port1 = system->addMenu("Controller Port &1");
system_port1->setIcon(QIcon(":/16x16/input-gaming.png"));
system_port1->addAction(system_port1_none = new QbRadioAction("&None", 0));
system_port1->addAction(system_port1_gamepad = new QbRadioAction("&Gamepad", 0));
system_port1->addAction(system_port1_asciipad = new QbRadioAction("&asciiPad", 0));
system_port1->addAction(system_port1_multitap = new QbRadioAction("&Multitap", 0));
system_port1->addAction(system_port1_mouse = new QbRadioAction("&Mouse", 0));
system_port2 = system->addMenu("Controller Port &2");
system_port2->setIcon(QIcon(":/16x16/input-gaming.png"));
system_port2->addAction(system_port2_none = new QbRadioAction("&None", 0));
system_port2->addAction(system_port2_gamepad = new QbRadioAction("&Gamepad", 0));
system_port2->addAction(system_port2_asciipad = new QbRadioAction("&asciiPad", 0));
system_port2->addAction(system_port2_multitap = new QbRadioAction("&Multitap", 0));
system_port2->addAction(system_port2_mouse = new QbRadioAction("&Mouse", 0));
system_port2->addAction(system_port2_superscope = new QbRadioAction("&Super Scope", 0));
system_port2->addAction(system_port2_justifier = new QbRadioAction("&Justifier", 0));
system_port2->addAction(system_port2_justifiers = new QbRadioAction("Two &Justifiers", 0));
#if !defined(PLATFORM_OSX)
system->addSeparator();
#endif
system_exit = system->addAction("E&xit");
system_exit->setIcon(QIcon(":/16x16/process-stop.png"));
system_exit->setMenuRole(QAction::QuitRole);
settings = menuBar->addMenu("S&ettings");
settings_videoMode = settings->addMenu("Video &Mode");
settings_videoMode->setIcon(QIcon(":/16x16/video-display.png"));
settings_videoMode->addAction(settings_videoMode_1x = new QbRadioAction("Scale &1x", 0));
settings_videoMode->addAction(settings_videoMode_2x = new QbRadioAction("Scale &2x", 0));
settings_videoMode->addAction(settings_videoMode_3x = new QbRadioAction("Scale &3x", 0));
settings_videoMode->addAction(settings_videoMode_4x = new QbRadioAction("Scale &4x", 0));
settings_videoMode->addAction(settings_videoMode_5x = new QbRadioAction("Scale &5x", 0));
settings_videoMode->addSeparator();
settings_videoMode->addAction(settings_videoMode_correctAspectRatio = new QbCheckAction("Correct &Aspect Ratio", 0));
settings_videoMode->addSeparator();
settings_videoMode->addAction(settings_videoMode_ntsc = new QbRadioAction("&NTSC", 0));
settings_videoMode->addAction(settings_videoMode_pal = new QbRadioAction("&PAL", 0));
if(filter.opened()) {
settings_videoFilter = settings->addMenu("Video &Filter");
settings_videoFilter->setIcon(QIcon(":/16x16/image-x-generic.png"));
settings_videoFilter_configure = settings_videoFilter->addAction("&Configure Active Filter ...");
settings_videoFilter_configure->setIcon(QIcon(":/16x16/preferences-desktop.png"));
settings_videoFilter->addSeparator();
settings_videoFilter->addAction(settings_videoFilter_none = new QbRadioAction("&None", 0));
settings_videoFilter_list.add(settings_videoFilter_none);
lstring filterlist;
filterlist.split(";", filter.dl_supported());
for(unsigned i = 0; i < filterlist.size(); i++) {
QbRadioAction *action = new QbRadioAction(filterlist[i], 0);
settings_videoFilter->addAction(action);
settings_videoFilter_list.add(action);
}
}
settings->addAction(settings_smoothVideo = new QbCheckAction("Smooth Video Output", 0));
settings->addSeparator();
settings->addAction(settings_muteAudio = new QbCheckAction("Mute Audio Output", 0));
settings->addSeparator();
settings_emulationSpeed = settings->addMenu("Emulation Speed");
settings_emulationSpeed->setIcon(QIcon(":/16x16/appointment-new.png"));
settings_emulationSpeed->addAction(settings_emulationSpeed_slowest = new QbRadioAction("50%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_slow = new QbRadioAction("75%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_normal = new QbRadioAction("100%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_fast = new QbRadioAction("150%", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_fastest = new QbRadioAction("200%", 0));
settings_emulationSpeed->addSeparator();
settings_emulationSpeed->addAction(settings_emulationSpeed_syncVideo = new QbCheckAction("Sync Video", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_syncAudio = new QbCheckAction("Sync Audio", 0));
settings_configuration = settings->addAction("Configuration ...");
settings_configuration->setIcon(QIcon(":/16x16/preferences-desktop.png"));
settings_configuration->setMenuRole(QAction::PreferencesRole);
settings->addAction(settings_smoothVideo = new QbCheckAction("&Smooth Video Output", 0));
tools = menuBar->addMenu("Tools");
tools_cheatEditor = tools->addAction("Cheat Editor ...");
tools_cheatEditor->setIcon(QIcon(":/16x16/accessories-text-editor.png"));
tools_cheatFinder = tools->addAction("Cheat Finder ...");
tools_cheatFinder->setIcon(QIcon(":/16x16/system-search.png"));
tools_stateManager = tools->addAction("State Manager ...");
tools_stateManager->setIcon(QIcon(":/16x16/system-file-manager.png"));
#if defined(DEBUGGER)
tools->addSeparator();
#endif
tools_debugger = tools->addAction("Debugger ...");
tools_debugger->setIcon(QIcon(":/16x16/utilities-terminal.png"));
#if !defined(DEBUGGER)
tools_debugger->setVisible(false);
#endif
settings->addSeparator();
help = menuBar->addMenu("Help");
help_documentation = help->addAction("Documentation ...");
help_documentation->setIcon(QIcon(":/16x16/text-x-generic.png"));
help_license = help->addAction("License ...");
help_license->setIcon(QIcon(":/16x16/text-x-generic.png"));
#if !defined(PLATFORM_OSX)
help->addSeparator();
#endif
help_about = help->addAction("About ...");
help_about->setIcon(QIcon(":/16x16/help-browser.png"));
help_about->setMenuRole(QAction::AboutRole);
settings->addAction(settings_muteAudio = new QbCheckAction("&Mute Audio Output", 0));
settings->addSeparator();
settings_emulationSpeed = settings->addMenu("Emulation &Speed");
settings_emulationSpeed->setIcon(QIcon(":/16x16/appointment-new.png"));
settings_emulationSpeed->addAction(settings_emulationSpeed_slowest = new QbRadioAction("Slowest", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_slow = new QbRadioAction("Slow", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_normal = new QbRadioAction("Normal", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_fast = new QbRadioAction("Fast", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_fastest = new QbRadioAction("Fastest", 0));
settings_emulationSpeed->addSeparator();
settings_emulationSpeed->addAction(settings_emulationSpeed_syncVideo = new QbCheckAction("Sync &Video", 0));
settings_emulationSpeed->addAction(settings_emulationSpeed_syncAudio = new QbCheckAction("Sync &Audio", 0));
settings_configuration = settings->addAction("&Configuration ...");
settings_configuration->setIcon(QIcon(":/16x16/preferences-desktop.png"));
settings_configuration->setMenuRole(QAction::PreferencesRole);
tools = menuBar->addMenu("&Tools");
tools_movies = tools->addMenu("&Movies");
tools_movies->setIcon(QIcon(":/16x16/applications-multimedia.png"));
tools_movies_play = tools_movies->addAction("Play Movie ...");
tools_movies_play->setIcon(QIcon(":/16x16/media-playback-start.png"));
tools_movies_stop = tools_movies->addAction("Stop");
tools_movies_stop->setIcon(QIcon(":/16x16/media-playback-stop.png"));
tools_movies_recordFromPowerOn = tools_movies->addAction("Record Movie (and restart system)");
tools_movies_recordFromPowerOn->setIcon(QIcon(":/16x16/media-record.png"));
tools_movies_recordFromHere = tools_movies->addAction("Record Movie (starting from here)");
tools_movies_recordFromHere->setIcon(QIcon(":/16x16/media-record.png"));
tools_captureScreenshot = tools->addAction("&Capture Screenshot");
tools_captureScreenshot->setIcon(QIcon(":/16x16/image-x-generic.png"));
tools->addSeparator();
tools_debugger = tools->addAction("&Debugger ...");
tools_debugger->setIcon(QIcon(":/16x16/utilities-terminal.png"));
#if !defined(DEBUGGER)
tools_debugger->setVisible(false);
#endif
tools_dialog = tools->addAction("&Tools Dialog ...");
tools_dialog->setIcon(QIcon(":/16x16/preferences-desktop.png"));
help = menuBar->addMenu("&Help");
help_documentation = help->addAction("&Documentation ...");
help_documentation->setIcon(QIcon(":/16x16/text-x-generic.png"));
help_license = help->addAction("&License ...");
help_license->setIcon(QIcon(":/16x16/text-x-generic.png"));
#if !defined(PLATFORM_OSX)
help->addSeparator();
#endif
help_about = help->addAction("&About ...");
help_about->setIcon(QIcon(":/16x16/help-browser.png"));
help_about->setMenuRole(QAction::AboutRole);
//canvas
canvasContainer = new CanvasObject;
@@ -171,7 +229,7 @@ MainWindow::MainWindow() {
#endif
layout->addWidget(canvasContainer);
layout->addWidget(statusBar);
window->setLayout(layout);
setLayout(layout);
//slots
connect(system_load, SIGNAL(triggered()), this, SLOT(loadCartridge()));
@@ -182,11 +240,13 @@ MainWindow::MainWindow() {
connect(system_power, SIGNAL(triggered()), this, SLOT(power()));
connect(system_reset, SIGNAL(triggered()), this, SLOT(reset()));
connect(system_port1_none, SIGNAL(triggered()), this, SLOT(setPort1None()));
connect(system_port1_joypad, SIGNAL(triggered()), this, SLOT(setPort1Joypad()));
connect(system_port1_gamepad, SIGNAL(triggered()), this, SLOT(setPort1Gamepad()));
connect(system_port1_asciipad, SIGNAL(triggered()), this, SLOT(setPort1Asciipad()));
connect(system_port1_multitap, SIGNAL(triggered()), this, SLOT(setPort1Multitap()));
connect(system_port1_mouse, SIGNAL(triggered()), this, SLOT(setPort1Mouse()));
connect(system_port2_none, SIGNAL(triggered()), this, SLOT(setPort2None()));
connect(system_port2_joypad, SIGNAL(triggered()), this, SLOT(setPort2Joypad()));
connect(system_port2_gamepad, SIGNAL(triggered()), this, SLOT(setPort2Gamepad()));
connect(system_port2_asciipad, SIGNAL(triggered()), this, SLOT(setPort2Asciipad()));
connect(system_port2_multitap, SIGNAL(triggered()), this, SLOT(setPort2Multitap()));
connect(system_port2_mouse, SIGNAL(triggered()), this, SLOT(setPort2Mouse()));
connect(system_port2_superscope, SIGNAL(triggered()), this, SLOT(setPort2SuperScope()));
@@ -197,9 +257,8 @@ MainWindow::MainWindow() {
connect(settings_videoMode_2x, SIGNAL(triggered()), this, SLOT(setVideoMode2x()));
connect(settings_videoMode_3x, SIGNAL(triggered()), this, SLOT(setVideoMode3x()));
connect(settings_videoMode_4x, SIGNAL(triggered()), this, SLOT(setVideoMode4x()));
connect(settings_videoMode_max, SIGNAL(triggered()), this, SLOT(setVideoModeMax()));
connect(settings_videoMode_5x, SIGNAL(triggered()), this, SLOT(setVideoMode5x()));
connect(settings_videoMode_correctAspectRatio, SIGNAL(triggered()), this, SLOT(toggleAspectCorrection()));
connect(settings_videoMode_fullscreen, SIGNAL(triggered()), this, SLOT(toggleFullscreen()));
connect(settings_videoMode_ntsc, SIGNAL(triggered()), this, SLOT(setVideoNtsc()));
connect(settings_videoMode_pal, SIGNAL(triggered()), this, SLOT(setVideoPal()));
if(filter.opened()) {
@@ -218,10 +277,13 @@ MainWindow::MainWindow() {
connect(settings_emulationSpeed_syncVideo, SIGNAL(triggered()), this, SLOT(syncVideo()));
connect(settings_emulationSpeed_syncAudio, SIGNAL(triggered()), this, SLOT(syncAudio()));
connect(settings_configuration, SIGNAL(triggered()), this, SLOT(showConfigWindow()));
connect(tools_cheatEditor, SIGNAL(triggered()), this, SLOT(showCheatEditor()));
connect(tools_cheatFinder, SIGNAL(triggered()), this, SLOT(showCheatFinder()));
connect(tools_stateManager, SIGNAL(triggered()), this, SLOT(showStateManager()));
connect(tools_movies_play, SIGNAL(triggered()), this, SLOT(playMovie()));
connect(tools_movies_stop, SIGNAL(triggered()), this, SLOT(stopMovie()));
connect(tools_movies_recordFromPowerOn, SIGNAL(triggered()), this, SLOT(recordMovieFromPowerOn()));
connect(tools_movies_recordFromHere, SIGNAL(triggered()), this, SLOT(recordMovieFromHere()));
connect(tools_captureScreenshot, SIGNAL(triggered()), this, SLOT(saveScreenshot()));
connect(tools_debugger, SIGNAL(triggered()), this, SLOT(showDebugger()));
connect(tools_dialog, SIGNAL(triggered()), this, SLOT(showToolsDialog()));
connect(help_documentation, SIGNAL(triggered()), this, SLOT(showDocumentation()));
connect(help_license, SIGNAL(triggered()), this, SLOT(showLicense()));
connect(help_about, SIGNAL(triggered()), this, SLOT(showAbout()));
@@ -235,53 +297,64 @@ void MainWindow::syncUi() {
system_power->setEnabled(SNES::cartridge.loaded());
system_reset->setEnabled(SNES::cartridge.loaded() && application.power);
system_port1_none->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceNone);
system_port1_joypad->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceJoypad);
system_port1_multitap->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceMultitap);
system_port1_mouse->setChecked (SNES::config.controller_port1 == SNES::Input::DeviceMouse);
system_port2_none->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceNone);
system_port2_joypad->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceJoypad);
system_port2_multitap->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceMultitap);
system_port2_mouse->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceMouse);
system_port2_superscope->setChecked(SNES::config.controller_port2 == SNES::Input::DeviceSuperScope);
system_port2_justifier->setChecked (SNES::config.controller_port2 == SNES::Input::DeviceJustifier);
system_port2_justifiers->setChecked(SNES::config.controller_port2 == SNES::Input::DeviceJustifiers);
system_port1_none->setChecked (config().input.port1 == ControllerPort1::None);
system_port1_gamepad->setChecked (config().input.port1 == ControllerPort1::Gamepad);
system_port1_asciipad->setChecked (config().input.port1 == ControllerPort1::Asciipad);
system_port1_multitap->setChecked (config().input.port1 == ControllerPort1::Multitap);
system_port1_mouse->setChecked (config().input.port1 == ControllerPort1::Mouse);
settings_videoMode_1x->setChecked (config.video.context->multiplier == 1);
settings_videoMode_2x->setChecked (config.video.context->multiplier == 2);
settings_videoMode_3x->setChecked (config.video.context->multiplier == 3);
settings_videoMode_4x->setChecked (config.video.context->multiplier == 4);
settings_videoMode_max->setChecked(config.video.context->multiplier >= 5);
system_port2_none->setChecked (config().input.port2 == ControllerPort2::None);
system_port2_gamepad->setChecked (config().input.port2 == ControllerPort2::Gamepad);
system_port2_asciipad->setChecked (config().input.port2 == ControllerPort2::Asciipad);
system_port2_multitap->setChecked (config().input.port2 == ControllerPort2::Multitap);
system_port2_mouse->setChecked (config().input.port2 == ControllerPort2::Mouse);
system_port2_superscope->setChecked(config().input.port2 == ControllerPort2::SuperScope);
system_port2_justifier->setChecked (config().input.port2 == ControllerPort2::Justifier);
system_port2_justifiers->setChecked(config().input.port2 == ControllerPort2::Justifiers);
settings_videoMode_correctAspectRatio->setChecked(config.video.context->correctAspectRatio);
settings_videoMode_fullscreen->setChecked(config.video.isFullscreen);
settings_videoMode_ntsc->setChecked(config.video.context->region == 0);
settings_videoMode_pal->setChecked (config.video.context->region == 1);
settings_videoMode_1x->setChecked(config().video.context->multiplier == 1);
settings_videoMode_2x->setChecked(config().video.context->multiplier == 2);
settings_videoMode_3x->setChecked(config().video.context->multiplier == 3);
settings_videoMode_4x->setChecked(config().video.context->multiplier == 4);
settings_videoMode_5x->setChecked(config().video.context->multiplier == 5);
settings_videoMode_correctAspectRatio->setChecked(config().video.context->correctAspectRatio);
settings_videoMode_ntsc->setChecked(config().video.context->region == 0);
settings_videoMode_pal->setChecked (config().video.context->region == 1);
if(filter.opened()) {
//only enable configuration option if the active filter supports it ...
settings_videoFilter_configure->setEnabled(filter.settings());
for(unsigned i = 0; i < settings_videoFilter_list.size(); i++) {
settings_videoFilter_list[i]->setChecked(config.video.context->swFilter == i);
settings_videoFilter_list[i]->setChecked(config().video.context->swFilter == i);
}
}
settings_smoothVideo->setChecked(config.video.context->hwFilter == 1);
settings_muteAudio->setChecked(config.audio.mute);
settings_smoothVideo->setChecked(config().video.context->hwFilter == 1);
settings_muteAudio->setChecked(config().audio.mute);
settings_emulationSpeed_slowest->setChecked(config.system.speed == 0);
settings_emulationSpeed_slow->setChecked (config.system.speed == 1);
settings_emulationSpeed_normal->setChecked (config.system.speed == 2);
settings_emulationSpeed_fast->setChecked (config.system.speed == 3);
settings_emulationSpeed_fastest->setChecked(config.system.speed == 4);
settings_emulationSpeed_slowest->setChecked(config().system.speed == 0);
settings_emulationSpeed_slow->setChecked (config().system.speed == 1);
settings_emulationSpeed_normal->setChecked (config().system.speed == 2);
settings_emulationSpeed_fast->setChecked (config().system.speed == 3);
settings_emulationSpeed_fastest->setChecked(config().system.speed == 4);
settings_emulationSpeed_syncVideo->setChecked(config.video.synchronize);
settings_emulationSpeed_syncAudio->setChecked(config.audio.synchronize);
settings_emulationSpeed_syncVideo->setChecked(config().video.synchronize);
settings_emulationSpeed_syncAudio->setChecked(config().audio.synchronize);
//movies contian save states to synchronize playback to recorded input
tools_movies->setEnabled(SNES::cartridge.loaded() && utility.saveStatesSupported());
if(tools_movies->isEnabled()) {
tools_movies_play->setEnabled(movie.state == Movie::Inactive);
tools_movies_stop->setEnabled(movie.state != Movie::Inactive);
tools_movies_recordFromPowerOn->setEnabled(movie.state == Movie::Inactive);
tools_movies_recordFromHere->setEnabled(movie.state == Movie::Inactive);
}
}
bool MainWindow::isActive() {
return window->isActiveWindow() && !window->isMinimized();
return isActiveWindow() && !isMinimized();
}
void MainWindow::loadCartridge() {
@@ -293,15 +366,15 @@ void MainWindow::loadBsxSlottedCartridge() {
}
void MainWindow::loadBsxCartridge() {
loaderWindow->loadBsxCartridge(config.path.bsx, "");
loaderWindow->loadBsxCartridge(config().path.bsx, "");
}
void MainWindow::loadSufamiTurboCartridge() {
loaderWindow->loadSufamiTurboCartridge(config.path.st, "", "");
loaderWindow->loadSufamiTurboCartridge(config().path.st, "", "");
}
void MainWindow::loadSuperGameBoyCartridge() {
loaderWindow->loadSuperGameBoyCartridge(config.path.sgb, "");
loaderWindow->loadSuperGameBoyCartridge(config().path.sgb, "");
}
void MainWindow::power() {
@@ -317,52 +390,101 @@ void MainWindow::reset() {
utility.modifySystemState(Utility::Reset);
}
void MainWindow::setPort1None() { SNES::config.controller_port1 = SNES::Input::DeviceNone; utility.updateControllers(); syncUi(); }
void MainWindow::setPort1Joypad() { SNES::config.controller_port1 = SNES::Input::DeviceJoypad; utility.updateControllers(); syncUi(); }
void MainWindow::setPort1Multitap() { SNES::config.controller_port1 = SNES::Input::DeviceMultitap; utility.updateControllers(); syncUi(); }
void MainWindow::setPort1Mouse() { SNES::config.controller_port1 = SNES::Input::DeviceMouse; utility.updateControllers(); syncUi(); }
void MainWindow::setPort2None() { SNES::config.controller_port2 = SNES::Input::DeviceNone; utility.updateControllers(); syncUi(); }
void MainWindow::setPort2Joypad() { SNES::config.controller_port2 = SNES::Input::DeviceJoypad; utility.updateControllers(); syncUi(); }
void MainWindow::setPort2Multitap() { SNES::config.controller_port2 = SNES::Input::DeviceMultitap; utility.updateControllers(); syncUi(); }
void MainWindow::setPort2Mouse() { SNES::config.controller_port2 = SNES::Input::DeviceMouse; utility.updateControllers(); syncUi(); }
void MainWindow::setPort2SuperScope() { SNES::config.controller_port2 = SNES::Input::DeviceSuperScope; utility.updateControllers(); syncUi(); }
void MainWindow::setPort2Justifier() { SNES::config.controller_port2 = SNES::Input::DeviceJustifier; utility.updateControllers(); syncUi(); }
void MainWindow::setPort2Justifiers() { SNES::config.controller_port2 = SNES::Input::DeviceJustifiers; utility.updateControllers(); syncUi(); }
void MainWindow::setPort1None() {
config().input.port1 = ControllerPort1::None;
SNES::config.controller_port1 = SNES::Input::DeviceNone;
utility.updateControllers();
}
void MainWindow::setPort1Gamepad() {
config().input.port1 = ControllerPort1::Gamepad;
SNES::config.controller_port1 = SNES::Input::DeviceJoypad;
utility.updateControllers();
}
void MainWindow::setPort1Asciipad() {
config().input.port1 = ControllerPort1::Asciipad;
SNES::config.controller_port1 = SNES::Input::DeviceJoypad;
utility.updateControllers();
}
void MainWindow::setPort1Multitap() {
config().input.port1 = ControllerPort1::Multitap;
SNES::config.controller_port1 = SNES::Input::DeviceMultitap;
utility.updateControllers();
}
void MainWindow::setPort1Mouse() {
config().input.port1 = ControllerPort1::Mouse;
SNES::config.controller_port1 = SNES::Input::DeviceMouse;
utility.updateControllers();
}
void MainWindow::setPort2None() {
config().input.port2 = ControllerPort2::None;
SNES::config.controller_port2 = SNES::Input::DeviceNone;
utility.updateControllers();
}
void MainWindow::setPort2Gamepad() {
config().input.port2 = ControllerPort2::Gamepad;
SNES::config.controller_port2 = SNES::Input::DeviceJoypad;
utility.updateControllers();
}
void MainWindow::setPort2Asciipad() {
config().input.port2 = ControllerPort2::Asciipad;
SNES::config.controller_port2 = SNES::Input::DeviceJoypad;
utility.updateControllers();
}
void MainWindow::setPort2Multitap() {
config().input.port2 = ControllerPort2::Multitap;
SNES::config.controller_port2 = SNES::Input::DeviceMultitap;
utility.updateControllers();
}
void MainWindow::setPort2Mouse() {
config().input.port2 = ControllerPort2::Mouse;
SNES::config.controller_port2 = SNES::Input::DeviceMouse;
utility.updateControllers();
}
void MainWindow::setPort2SuperScope() {
config().input.port2 = ControllerPort2::SuperScope;
SNES::config.controller_port2 = SNES::Input::DeviceSuperScope;
utility.updateControllers();
}
void MainWindow::setPort2Justifier() {
config().input.port2 = ControllerPort2::Justifier;
SNES::config.controller_port2 = SNES::Input::DeviceJustifier;
utility.updateControllers();
}
void MainWindow::setPort2Justifiers() {
config().input.port2 = ControllerPort2::Justifiers;
SNES::config.controller_port2 = SNES::Input::DeviceJustifiers;
utility.updateControllers();
}
void MainWindow::quit() {
window->hide();
hide();
application.terminate = true;
}
void MainWindow::setVideoMode1x() { config.video.context->multiplier = 1; utility.resizeMainWindow(); syncUi(); }
void MainWindow::setVideoMode2x() { config.video.context->multiplier = 2; utility.resizeMainWindow(); syncUi(); }
void MainWindow::setVideoMode3x() { config.video.context->multiplier = 3; utility.resizeMainWindow(); syncUi(); }
void MainWindow::setVideoMode4x() { config.video.context->multiplier = 4; utility.resizeMainWindow(); syncUi(); }
void MainWindow::setVideoModeMax() { config.video.context->multiplier = 9; utility.resizeMainWindow(); syncUi(); }
void MainWindow::setVideoMode1x() { utility.setScale(1); }
void MainWindow::setVideoMode2x() { utility.setScale(2); }
void MainWindow::setVideoMode3x() { utility.setScale(3); }
void MainWindow::setVideoMode4x() { utility.setScale(4); }
void MainWindow::setVideoMode5x() { utility.setScale(5); }
void MainWindow::toggleAspectCorrection() {
settings_videoMode_correctAspectRatio->toggleChecked();
config.video.context->correctAspectRatio = settings_videoMode_correctAspectRatio->isChecked();
utility.resizeMainWindow();
}
void MainWindow::toggleAspectCorrection() { utility.toggleAspectCorrection(); }
void MainWindow::toggleFullscreen() {
settings_videoMode_fullscreen->toggleChecked();
config.video.isFullscreen = settings_videoMode_fullscreen->isChecked();
utility.updateFullscreenState();
utility.resizeMainWindow();
syncUi();
}
void MainWindow::setVideoNtsc() { utility.setNtscMode(); }
void MainWindow::setVideoPal() { utility.setPalMode(); }
void MainWindow::setVideoNtsc() { config.video.context->region = 0; utility.updateVideoMode(); utility.resizeMainWindow(); syncUi(); }
void MainWindow::setVideoPal() { config.video.context->region = 1; utility.updateVideoMode(); utility.resizeMainWindow(); syncUi(); }
void MainWindow::toggleSmoothVideo() {
settings_smoothVideo->toggleChecked();
config.video.context->hwFilter = settings_smoothVideo->isChecked();
utility.updateHardwareFilter();
syncUi();
}
void MainWindow::toggleSmoothVideo() { utility.toggleSmoothVideoOutput(); }
void MainWindow::configureFilter() {
QWidget *widget = filter.settings();
@@ -376,7 +498,7 @@ void MainWindow::configureFilter() {
void MainWindow::setFilter() {
for(unsigned i = 0; i < settings_videoFilter_list.size(); i++) {
if(sender() == settings_videoFilter_list[i]) {
config.video.context->swFilter = i;
config().video.context->swFilter = i;
utility.updateSoftwareFilter();
syncUi();
return;
@@ -386,33 +508,53 @@ void MainWindow::setFilter() {
void MainWindow::muteAudio() {
settings_muteAudio->toggleChecked();
config.audio.mute = settings_muteAudio->isChecked();
config().audio.mute = settings_muteAudio->isChecked();
}
void MainWindow::setSpeedSlowest() { config.system.speed = 0; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedSlow() { config.system.speed = 1; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedNormal() { config.system.speed = 2; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedFast() { config.system.speed = 3; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedFastest() { config.system.speed = 4; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedSlowest() { config().system.speed = 0; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedSlow() { config().system.speed = 1; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedNormal() { config().system.speed = 2; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedFast() { config().system.speed = 3; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::setSpeedFastest() { config().system.speed = 4; utility.updateEmulationSpeed(); syncUi(); }
void MainWindow::syncVideo() {
settings_emulationSpeed_syncVideo->toggleChecked();
config.video.synchronize = settings_emulationSpeed_syncVideo->isChecked();
utility.updateAvSync();
void MainWindow::syncVideo() { utility.toggleSynchronizeVideo(); }
void MainWindow::syncAudio() { utility.toggleSynchronizeAudio(); }
void MainWindow::showConfigWindow() { settingsWindow->show(); }
void MainWindow::playMovie() {
movie.chooseFile();
syncUi();
}
void MainWindow::syncAudio() {
settings_emulationSpeed_syncAudio->toggleChecked();
config.audio.synchronize = settings_emulationSpeed_syncAudio->isChecked();
utility.updateAvSync();
void MainWindow::stopMovie() {
movie.stop();
syncUi();
}
void MainWindow::showConfigWindow() { settingsWindow->window->show(); }
void MainWindow::recordMovieFromPowerOn() {
utility.modifySystemState(Utility::PowerCycle);
movie.record();
syncUi();
}
void MainWindow::showCheatEditor() { toolsWindow->showCheatEditor(); }
void MainWindow::showCheatFinder() { toolsWindow->showCheatFinder(); }
void MainWindow::showStateManager() { toolsWindow->showStateManager(); }
void MainWindow::showDebugger() { debugger->window->show(); }
void MainWindow::recordMovieFromHere() {
movie.record();
syncUi();
}
void MainWindow::saveScreenshot() {
//tell SNES::Interface to save a screenshot at the next video_refresh() event
interface.saveScreenshot = true;
}
void MainWindow::showDebugger() {
#if defined(DEBUGGER)
debugger->show();
#endif
}
void MainWindow::showToolsDialog() { toolsWindow->show(); }
void MainWindow::showDocumentation() {
QFile file(":/documentation.html");
@@ -430,14 +572,12 @@ void MainWindow::showLicense() {
}
}
void MainWindow::showAbout() {
aboutWindow->window->show();
aboutWindow->show();
}
void MainWindow::Window::closeEvent(QCloseEvent*) {
mainWindow->quit();
}
MainWindow::Window::Window(string &geometry) : QbWindow(geometry) {
void MainWindow::closeEvent(QCloseEvent *event) {
QbWindow::closeEvent(event);
quit();
}
//============

View File

@@ -13,14 +13,10 @@ public:
void paintEvent(QPaintEvent*);
};
class MainWindow : public QObject {
class MainWindow : public QbWindow {
Q_OBJECT
public:
struct Window : public QbWindow {
void closeEvent(QCloseEvent*);
Window(string&);
} *window;
QMenuBar *menuBar;
QStatusBar *statusBar;
QVBoxLayout *layout;
@@ -35,12 +31,14 @@ public:
QAction *system_reset;
QMenu *system_port1;
QbRadioAction *system_port1_none;
QbRadioAction *system_port1_joypad;
QbRadioAction *system_port1_gamepad;
QbRadioAction *system_port1_asciipad;
QbRadioAction *system_port1_multitap;
QbRadioAction *system_port1_mouse;
QMenu *system_port2;
QbRadioAction *system_port2_none;
QbRadioAction *system_port2_joypad;
QbRadioAction *system_port2_gamepad;
QbRadioAction *system_port2_asciipad;
QbRadioAction *system_port2_multitap;
QbRadioAction *system_port2_mouse;
QbRadioAction *system_port2_superscope;
@@ -53,9 +51,8 @@ public:
QbRadioAction *settings_videoMode_2x;
QbRadioAction *settings_videoMode_3x;
QbRadioAction *settings_videoMode_4x;
QbRadioAction *settings_videoMode_max;
QbRadioAction *settings_videoMode_5x;
QbCheckAction *settings_videoMode_correctAspectRatio;
QbCheckAction *settings_videoMode_fullscreen;
QbRadioAction *settings_videoMode_ntsc;
QbRadioAction *settings_videoMode_pal;
QMenu *settings_videoFilter;
@@ -74,22 +71,27 @@ public:
QbCheckAction *settings_emulationSpeed_syncAudio;
QAction *settings_configuration;
QMenu *tools;
QAction *tools_cheatEditor;
QAction *tools_cheatFinder;
QAction *tools_stateManager;
QMenu *tools_movies;
QAction *tools_movies_play;
QAction *tools_movies_stop;
QAction *tools_movies_recordFromPowerOn;
QAction *tools_movies_recordFromHere;
QAction *tools_captureScreenshot;
QAction *tools_debugger;
QAction *tools_dialog;
QMenu *help;
QAction *help_documentation;
QAction *help_license;
QAction *help_about;
//
CanvasObject *canvasContainer;
QVBoxLayout *canvasLayout;
CanvasWidget *canvas;
QVBoxLayout *canvasLayout;
CanvasWidget *canvas;
QLabel *systemState;
void syncUi();
bool isActive();
void closeEvent(QCloseEvent*);
MainWindow();
public slots:
@@ -101,11 +103,13 @@ public slots:
void power();
void reset();
void setPort1None();
void setPort1Joypad();
void setPort1Gamepad();
void setPort1Asciipad();
void setPort1Multitap();
void setPort1Mouse();
void setPort2None();
void setPort2Joypad();
void setPort2Gamepad();
void setPort2Asciipad();
void setPort2Multitap();
void setPort2Mouse();
void setPort2SuperScope();
@@ -116,9 +120,8 @@ public slots:
void setVideoMode2x();
void setVideoMode3x();
void setVideoMode4x();
void setVideoModeMax();
void setVideoMode5x();
void toggleAspectCorrection();
void toggleFullscreen();
void setVideoNtsc();
void setVideoPal();
void configureFilter();
@@ -133,11 +136,16 @@ public slots:
void syncVideo();
void syncAudio();
void showConfigWindow();
void showCheatEditor();
void showCheatFinder();
void showStateManager();
void playMovie();
void stopMovie();
void recordMovieFromPowerOn();
void recordMovieFromHere();
void saveScreenshot();
void showDebugger();
void showToolsDialog();
void showDocumentation();
void showLicense();
void showAbout();
} *mainWindow;
};
extern MainWindow *mainWindow;

View File

@@ -1,3 +1,8 @@
Configuration &config() {
static Configuration configuration;
return configuration;
}
bool Configuration::load(const char *filename) {
if(configuration::load(filename) == false) return false;
SNES::config.superfx.speed = max(0, min(2, SNES::config.superfx.speed));
@@ -5,21 +10,6 @@ bool Configuration::load(const char *filename) {
return true;
}
void Configuration::attachJoypad(Configuration::Input::Joypad &joypad, const char *name) {
attach(joypad.up = "none", string() << name << ".up");
attach(joypad.down = "none", string() << name << ".down");
attach(joypad.left = "none", string() << name << ".left");
attach(joypad.right = "none", string() << name << ".right");
attach(joypad.a = "none", string() << name << ".a");
attach(joypad.b = "none", string() << name << ".b");
attach(joypad.x = "none", string() << name << ".x");
attach(joypad.y = "none", string() << name << ".y");
attach(joypad.l = "none", string() << name << ".l");
attach(joypad.r = "none", string() << name << ".r");
attach(joypad.select = "none", string() << name << ".select");
attach(joypad.start = "none", string() << name << ".start");
}
Configuration::Configuration() {
//========
//external
@@ -54,22 +44,39 @@ Configuration::Configuration() {
attach(system.input = "", "system.input");
attach(system.crashedOnLastRun = false, "system.crashedOnLastRun");
attach(system.speed = 2, "system.speed");
attach(system.speedSlowest = 50, "system.speedSlowest");
attach(system.speedSlow = 75, "system.speedSlow");
attach(system.speedNormal = 100, "system.speedNormal");
attach(system.speedFast = 150, "system.speedFast");
attach(system.speedFastest = 200, "system.speedFastest");
attach(system.autoSaveMemory = false, "system.autoSaveMemory", "Automatically save cartridge back-up RAM once every minute");
attach(system.autoHideMenus = false, "system.autoHideMenus", "Automatically hide the menu and status bars when entering fullscreen mode");
attach(system.rewindEnabled = false, "system.rewindEnabled", "Automatically save states periodically to allow auto-rewind support");
attach(diskBrowser.showPanel = true, "diskBrowser.showPanel");
attach(file.autodetect_type = false, "file.autodetectType");
attach(file.bypass_patch_crc32 = false, "file.bypassPatchCrc32");
attach(path.current = "", "path.current");
attach(path.rom = "", "path.rom");
attach(path.save = "", "path.save");
attach(path.state = "", "path.state");
attach(path.patch = "", "path.patch");
attach(path.cheat = "", "path.cheat");
attach(path.data = "", "path.data");
attach(path.bsx = "", "path.bsx");
attach(path.st = "", "path.st");
attach(path.sgb = "", "path.sgb");
attach(path.rom = "", "path.rom");
attach(path.save = "", "path.save");
attach(path.state = "", "path.state");
attach(path.patch = "", "path.patch");
attach(path.cheat = "", "path.cheat");
attach(path.data = "", "path.data");
attach(path.bsx = "", "path.bsx");
attach(path.st = "", "path.st");
attach(path.sgb = "", "path.sgb");
attach(path.fragmentShader = "", "path.fragmentShader");
attach(path.vertexShader = "", "path.vertexShader");
attach(path.current.folder = "", "path.current.folder");
attach(path.current.movie = "", "path.current.movie");
attach(path.current.shader = "", "path.current.shader");
attach(path.current.cartridge = "", "path.current.cartridge");
attach(path.current.bsx = "", "path.current.bsx");
attach(path.current.st = "", "path.current.st");
attach(path.current.sgb = "", "path.current.sgb");
attach(path.current.filter = 0, "path.current.filter");
video.context = &video.windowed;
attach(video.isFullscreen = false, "video.isFullscreen");
@@ -78,6 +85,7 @@ Configuration::Configuration() {
attach(video.contrastAdjust = 0, "video.contrastAdjust");
attach(video.brightnessAdjust = 0, "video.brightnessAdjust");
attach(video.gammaAdjust = 0, "video.gammaAdjust");
attach(video.scanlineAdjust = 100, "video.scanlineAdjust");
attach(video.enableGammaRamp = true, "video.enableGammaRamp");
attach(video.ntscAspectRatio = 54.0 / 47.0, "video.ntscAspectRatio", "NTSC aspect ratio (x / y)");
@@ -105,98 +113,22 @@ Configuration::Configuration() {
attach(audio.outputFrequency = 48000, "audio.outputFrequency");
attach(audio.inputFrequency = 32000, "audio.inputFrequency");
attach(input.port1 = ControllerPort1::Gamepad, "input.port1");
attach(input.port2 = ControllerPort2::Gamepad, "input.port2");
attach(input.focusPolicy = Input::FocusPolicyIgnoreInput, "input.focusPolicy");
attach(input.allowInvalidInput = false, "input.allowInvalidInput", "Allow up+down / left+right combinations; may trigger bugs in some games");
attach(input.joypad1.up = "keyboard00.up", "input.joypad1.up");
attach(input.joypad1.down = "keyboard00.down", "input.joypad1.down");
attach(input.joypad1.left = "keyboard00.left", "input.joypad1.left");
attach(input.joypad1.right = "keyboard00.right", "input.joypad1.right");
attach(input.joypad1.a = "keyboard00.x", "input.joypad1.a");
attach(input.joypad1.b = "keyboard00.z", "input.joypad1.b");
attach(input.joypad1.x = "keyboard00.s", "input.joypad1.x");
attach(input.joypad1.y = "keyboard00.a", "input.joypad1.y");
attach(input.joypad1.l = "keyboard00.d", "input.joypad1.l");
attach(input.joypad1.r = "keyboard00.c", "input.joypad1.r");
attach(input.joypad1.select = "keyboard00.rshift", "input.joypad1.select");
attach(input.joypad1.start = "keyboard00.return", "input.joypad1.start");
//these are all mapped to "none" by default
attachJoypad(input.joypad2, "input.joypad2");
attachJoypad(input.multitap1a, "input.multitap1a");
attachJoypad(input.multitap1b, "input.multitap1b");
attachJoypad(input.multitap1c, "input.multitap1c");
attachJoypad(input.multitap1d, "input.multitap1d");
attachJoypad(input.multitap2a, "input.multitap2a");
attachJoypad(input.multitap2b, "input.multitap2b");
attachJoypad(input.multitap2c, "input.multitap2c");
attachJoypad(input.multitap2d, "input.multitap2d");
attach(input.mouse1.x = "mouse00.x", "input.mouse1.x");
attach(input.mouse1.y = "mouse00.y", "input.mouse1.y");
attach(input.mouse1.left = "mouse00.button00", "input.mouse1.left");
attach(input.mouse1.right = "mouse00.button02", "input.mouse1.right");
//more likely a user will only use one mouse at a time, than for a system to have two mice
attach(input.mouse2.x = "mouse00.x", "input.mouse2.x");
attach(input.mouse2.y = "mouse00.y", "input.mouse2.y");
attach(input.mouse2.left = "mouse00.button00", "input.mouse2.left");
attach(input.mouse2.right = "mouse00.button02", "input.mouse2.right");
//unlikely a user will have a five-button mouse for turbo / pause mapping
attach(input.superscope.x = "mouse00.x", "input.superscope.x");
attach(input.superscope.y = "mouse00.y", "input.superscope.y");
attach(input.superscope.trigger = "mouse00.button00", "input.superscope.trigger");
attach(input.superscope.cursor = "mouse00.button02", "input.superscope.cursor");
attach(input.superscope.turbo = "keyboard00.t", "input.superscope.turbo");
attach(input.superscope.pause = "keyboard00.p", "input.superscope.pause");
attach(input.justifier1.x = "mouse00.x", "input.justifier1.x");
attach(input.justifier1.y = "mouse00.y", "input.justifier1.y");
attach(input.justifier1.trigger = "mouse00.button00", "input.justifier1.trigger");
attach(input.justifier1.start = "mouse00.button02", "input.jusitifer1.start");
attach(input.justifier2.x = "mouse01.x", "input.justifier2.x");
attach(input.justifier2.y = "mouse01.y", "input.justifier2.y");
attach(input.justifier2.trigger = "mouse01.button00", "input.justifier2.trigger");
attach(input.justifier2.start = "mouse01.button02", "input.justifier2.start");
attach(input.uiGeneral.loadCartridge = "none", "input.uiGeneral.loadCartridge");
attach(input.uiGeneral.pauseEmulation = "keyboard00.pause", "input.uiGeneral.pauseEmulation");
attach(input.uiGeneral.resetSystem = "none", "input.uiGeneral.resetSystem");
attach(input.uiGeneral.powerCycleSystem = "none", "input.uiGeneral.powerCycleSystem");
attach(input.uiGeneral.saveScreenshot = "none", "input.uiGeneral.saveScreenshot");
attach(input.uiGeneral.showStateManager = "keyboard00.f3", "input.uiGeneral.showStateManager");
attach(input.uiGeneral.quickLoad1 = "keyboard00.f4", "input.uiGeneral.quickLoad1");
attach(input.uiGeneral.quickLoad2 = "none", "input.uiGeneral.quickLoad2");
attach(input.uiGeneral.quickLoad3 = "none", "input.uiGeneral.quickLoad3");
attach(input.uiGeneral.quickSave1 = "keyboard00.f2", "input.uiGeneral.quickSave1");
attach(input.uiGeneral.quickSave2 = "none", "input.uiGeneral.quickSave2");
attach(input.uiGeneral.quickSave3 = "none", "input.uiGeneral.quickSave3");
attach(input.uiGeneral.lowerSpeed = "keyboard00.divide", "input.uiGeneral.lowerSpeed");
attach(input.uiGeneral.raiseSpeed = "keyboard00.multiply", "input.uiGeneral.raiseSpeed");
attach(input.uiGeneral.toggleCheatSystem = "none", "input.uiGeneral.toggleCheatSystem");
attach(input.uiGeneral.toggleFullscreen = "keyboard00.f11", "input.uiGeneral.toggleFullscreen");
attach(input.uiGeneral.toggleMenu = "keyboard00.escape", "input.uiGeneral.toggleMenu");
attach(input.uiGeneral.toggleStatus = "keyboard00.escape", "input.uiGeneral.toggleStatus");
attach(input.uiGeneral.exitEmulator = "none", "input.uiGeneral.exitEmulator");
attach(geometry.mainWindow = "", "geometry.mainWindow");
attach(geometry.loaderWindow = "", "geometry.loaderWindow");
attach(geometry.htmlViewerWindow = "", "geometry.htmlViewerWindow");
attach(geometry.aboutWindow = "", "geometry.aboutWindow");
attach(geometry.diskBrowser = "", "geometry.diskBrowser");
attach(geometry.folderCreator = "", "geometry.folderCreator");
attach(geometry.settingsWindow = "", "geometry.settingsWindow");
attach(geometry.inputCaptureWindow = "", "geometry.inputCaptureWindow");
attach(geometry.inputMouseCaptureWindow = "", "geometry.inputMouseCaptureWindow");
attach(geometry.inputCalibrationWindow = "", "geometry.inputCalibrationWindow");
attach(geometry.toolsWindow = "", "geometry.toolsWindow");
attach(geometry.debugger = "", "geometry.debugger");
attach(geometry.breakpointEditor = "", "geometry.breakpointEditor");
attach(geometry.memoryEditor = "", "geometry.memoryEditor");
attach(geometry.vramViewer = "", "geometry.vramViewer");
attach(geometry.mainWindow = "", "geometry.mainWindow");
attach(geometry.loaderWindow = "", "geometry.loaderWindow");
attach(geometry.htmlViewerWindow = "", "geometry.htmlViewerWindow");
attach(geometry.aboutWindow = "", "geometry.aboutWindow");
attach(geometry.diskBrowser = "", "geometry.diskBrowser");
attach(geometry.folderCreator = "", "geometry.folderCreator");
attach(geometry.settingsWindow = "", "geometry.settingsWindow");
attach(geometry.toolsWindow = "", "geometry.toolsWindow");
attach(geometry.debugger = "", "geometry.debugger");
attach(geometry.disassembler = "", "geometry.disassembler");
attach(geometry.breakpointEditor = "", "geometry.breakpointEditor");
attach(geometry.memoryEditor = "", "geometry.memoryEditor");
attach(geometry.vramViewer = "", "geometry.vramViewer");
}

View File

@@ -4,8 +4,13 @@ public:
string video, audio, input;
bool crashedOnLastRun;
unsigned speed;
unsigned speedSlowest;
unsigned speedSlow;
unsigned speedNormal;
unsigned speedFast;
unsigned speedFastest;
bool autoSaveMemory;
bool autoHideMenus;
bool rewindEnabled;
} system;
struct File {
@@ -13,18 +18,28 @@ public:
bool bypass_patch_crc32;
} file;
struct DiskBrowser {
bool showPanel;
} diskBrowser;
struct Path {
string base; //binary path
string user; //user profile path (bsnes.cfg, ...)
string current; //current working directory (path to currently loaded cartridge)
string startup; //startup path
string rom, save, state, patch, cheat, data;
string bsx, st, sgb;
string fragmentShader, vertexShader;
struct Current {
string folder, movie, shader, cartridge, bsx, st, sgb;
unsigned filter; //current active filter for "Load Cartridge"
} current;
} path;
struct Video {
bool isFullscreen;
bool synchronize;
signed contrastAdjust, brightnessAdjust, gammaAdjust;
signed contrastAdjust, brightnessAdjust, gammaAdjust, scanlineAdjust;
bool enableGammaRamp;
double ntscAspectRatio, palAspectRatio;
@@ -42,49 +57,11 @@ public:
} audio;
struct Input {
unsigned port1;
unsigned port2;
enum policy_t { FocusPolicyPauseEmulation, FocusPolicyIgnoreInput, FocusPolicyAllowInput };
unsigned focusPolicy;
bool allowInvalidInput;
struct Joypad {
string up, down, left, right, a, b, x, y, l, r, select, start;
} joypad1, joypad2,
multitap1a, multitap1b, multitap1c, multitap1d,
multitap2a, multitap2b, multitap2c, multitap2d;
struct Mouse {
string x, y, left, right;
} mouse1, mouse2;
struct SuperScope {
string x, y, trigger, turbo, cursor, pause;
} superscope;
struct Justifier {
string x, y, trigger, start;
} justifier1, justifier2;
struct UiGeneral {
string loadCartridge;
string pauseEmulation;
string resetSystem;
string powerCycleSystem;
string saveScreenshot;
string showStateManager;
string quickLoad1;
string quickLoad2;
string quickLoad3;
string quickSave1;
string quickSave2;
string quickSave3;
string lowerSpeed;
string raiseSpeed;
string toggleCheatSystem;
string toggleFullscreen;
string toggleMenu;
string toggleStatus;
string exitEmulator;
} uiGeneral;
} input;
struct Geometry {
@@ -94,21 +71,17 @@ public:
string aboutWindow;
string diskBrowser;
string folderCreator;
string settingsWindow;
string inputCaptureWindow;
string inputMouseCaptureWindow;
string inputCalibrationWindow;
string toolsWindow;
string debugger;
string disassembler;
string breakpointEditor;
string memoryEditor;
string vramViewer;
} geometry;
bool load(const char *filename);
void attachJoypad(Configuration::Input::Joypad &joypad, const char *name);
Configuration();
} config;
};
Configuration &config();

View File

@@ -1,3 +1,6 @@
#include "breakpoint.moc"
BreakpointEditor *breakpointEditor;
BreakpointItem::BreakpointItem(unsigned id_) : id(id_) {
layout = new QHBoxLayout;
layout->setMargin(0);
@@ -58,16 +61,15 @@ void BreakpointItem::toggle() {
}
}
BreakpointEditor::BreakpointEditor() {
window = new QbWindow(config.geometry.breakpointEditor);
window->setObjectName("breakpoint-editor");
window->setWindowTitle("Breakpoint Editor");
BreakpointEditor::BreakpointEditor() : QbWindow(config().geometry.breakpointEditor) {
setObjectName("breakpoint-editor");
setWindowTitle("Breakpoint Editor");
layout = new QVBoxLayout;
layout->setSizeConstraint(QLayout::SetFixedSize);
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
window->setLayout(layout);
setLayout(layout);
for(unsigned n = 0; n < SNES::Debugger::Breakpoints; n++) {
breakpoint[n] = new BreakpointItem(n);

View File

@@ -17,13 +17,14 @@ private:
const unsigned id;
};
class BreakpointEditor : public QObject {
class BreakpointEditor : public QbWindow {
Q_OBJECT
public:
QbWindow *window;
QVBoxLayout *layout;
BreakpointItem *breakpoint[SNES::Debugger::Breakpoints];
BreakpointEditor();
} *breakpointEditor;
};
extern BreakpointEditor *breakpointEditor;

View File

@@ -1,32 +1,37 @@
#include "../ui-base.hpp"
#if defined(DEBUGGER)
#include "debugger.moc"
Debugger *debugger;
#include "hexeditor.cpp"
#include "disassembler.cpp"
#include "breakpoint.cpp"
#include "memory.cpp"
#include "vramviewer.cpp"
#include "tracer.cpp"
Debugger::Debugger() {
window = new QbWindow(config.geometry.debugger);
window->setObjectName("debugger");
window->setWindowTitle("Debugger");
Debugger::Debugger() : QbWindow(config().geometry.debugger) {
setObjectName("debugger");
setWindowTitle("Debugger");
layout = new QHBoxLayout;
layout->setMargin(Style::WindowMargin);
layout->setSpacing(Style::WidgetSpacing);
window->setLayout(layout);
setLayout(layout);
menu = new QMenuBar;
layout->setMenuBar(menu);
tools = menu->addMenu("Tools");
tools_disassembler = tools->addAction("Disassembler ...");
tools_breakpoint = tools->addAction("Breakpoint Editor ...");
tools_breakpoint->setIcon(QIcon(":/16x16/process-stop.png"));
tools_memory = tools->addAction("Memory Editor ...");
tools_memory->setIcon(QIcon(":/16x16/text-x-generic.png"));
tools_vramViewer = tools->addAction("Video RAM Viewer ...");
tools_vramViewer->setIcon(QIcon(":/16x16/image-x-generic.png"));
miscOptions = menu->addMenu("Misc");
miscOptions_clear = miscOptions->addAction("Clear Console");
miscOptions_clear->setIcon(QIcon(":/16x16/document-new.png"));
console = new QTextEdit;
console->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -53,22 +58,32 @@ Debugger::Debugger() {
controlLayout->addSpacing(Style::WidgetSpacing);
stepCPU = new QCheckBox("Step CPU");
stepCPU = new QCheckBox("Step S-CPU");
controlLayout->addWidget(stepCPU);
stepSMP = new QCheckBox("Step SMP");
stepSMP = new QCheckBox("Step S-SMP");
controlLayout->addWidget(stepSMP);
traceCPU = new QCheckBox("Trace CPU opcodes");
traceCPU = new QCheckBox("Trace S-CPU opcodes");
controlLayout->addWidget(traceCPU);
traceSMP = new QCheckBox("Trace SMP opcodes");
traceSMP = new QCheckBox("Trace S-SMP opcodes");
controlLayout->addWidget(traceSMP);
traceMask = new QCheckBox("Enable trace mask");
controlLayout->addWidget(traceMask);
spacer = new QWidget;
spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
controlLayout->addWidget(spacer);
disassembler = new Disassembler;
breakpointEditor = new BreakpointEditor;
memoryEditor = new MemoryEditor;
vramViewer = new VramViewer;
tracer = new Tracer;
connect(tools_disassembler, SIGNAL(triggered()), this, SLOT(showDisassembler()));
connect(tools_breakpoint, SIGNAL(triggered()), this, SLOT(showBreakpointEditor()));
connect(tools_memory, SIGNAL(triggered()), this, SLOT(showMemoryEditor()));
connect(tools_vramViewer, SIGNAL(triggered()), this, SLOT(showVramViewer()));
@@ -78,16 +93,37 @@ Debugger::Debugger() {
connect(stepInstruction, SIGNAL(released()), this, SLOT(stepAction()));
connect(stepCPU, SIGNAL(released()), this, SLOT(synchronize()));
connect(stepSMP, SIGNAL(released()), this, SLOT(synchronize()));
connect(traceCPU, SIGNAL(released()), this, SLOT(toggleTraceCPU()));
connect(traceSMP, SIGNAL(released()), this, SLOT(toggleTraceSMP()));
breakpointEditor = new BreakpointEditor;
memoryEditor = new MemoryEditor;
vramViewer = new VramViewer;
connect(traceCPU, SIGNAL(stateChanged(int)), tracer, SLOT(setCpuTraceState(int)));
connect(traceSMP, SIGNAL(stateChanged(int)), tracer, SLOT(setSmpTraceState(int)));
connect(traceMask, SIGNAL(stateChanged(int)), tracer, SLOT(setTraceMaskState(int)));
frameCounter = 0;
synchronize();
window->resize(855, 425);
resize(855, 425);
}
void Debugger::modifySystemState(unsigned state) {
string usagefile = string() << dir(utility.cartridge.baseName) << "usage.bin";
file fp;
if(state == Utility::LoadCartridge) {
if(fp.open(usagefile, file::mode_read)) {
fp.read(SNES::cpu.usage, 1 << 24);
fp.read(SNES::smp.usage, 1 << 16);
fp.close();
} else {
memset(SNES::cpu.usage, 0x00, 1 << 24);
memset(SNES::smp.usage, 0x00, 1 << 16);
}
}
if(state == Utility::UnloadCartridge) {
if(fp.open(usagefile, file::mode_write)) {
fp.write(SNES::cpu.usage, 1 << 24);
fp.write(SNES::smp.usage, 1 << 16);
fp.close();
}
}
}
void Debugger::synchronize() {
@@ -108,16 +144,20 @@ void Debugger::clear() {
console->setHtml("");
}
void Debugger::showDisassembler() {
disassembler->show();
}
void Debugger::showBreakpointEditor() {
breakpointEditor->window->show();
breakpointEditor->show();
}
void Debugger::showMemoryEditor() {
memoryEditor->window->show();
memoryEditor->show();
}
void Debugger::showVramViewer() {
vramViewer->window->show();
vramViewer->show();
vramViewer->refresh();
}
@@ -131,63 +171,47 @@ void Debugger::stepAction() {
application.debugrun = true;
}
void Debugger::tracerUpdate() {
if(SNES::debugger.trace_cpu || SNES::debugger.trace_smp) {
if(SNES::debugger.tracefile.open() == false) {
SNES::debugger.tracefile.open(utf8() << config.path.data << "trace.log", file::mode_write);
}
} else if(!SNES::debugger.trace_cpu && !SNES::debugger.trace_smp) {
if(SNES::debugger.tracefile.open() == true) {
SNES::debugger.tracefile.close();
}
}
}
void Debugger::toggleTraceCPU() {
SNES::debugger.trace_cpu = traceCPU->isChecked();
tracerUpdate();
}
void Debugger::toggleTraceSMP() {
SNES::debugger.trace_smp = traceSMP->isChecked();
tracerUpdate();
}
void Debugger::event() {
char t[256];
switch(SNES::debugger.break_event) {
case SNES::Debugger::BreakpointHit: {
unsigned n = SNES::debugger.breakpoint_hit;
echo(utf8() << "Breakpoint " << n << " hit (" << SNES::debugger.breakpoint[n].counter << ").<br>");
echo(string() << "Breakpoint " << n << " hit (" << SNES::debugger.breakpoint[n].counter << ").<br>");
if(SNES::debugger.breakpoint[n].mode == SNES::Debugger::Breakpoint::Exec) {
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::CPUBus) {
SNES::debugger.step_cpu = true;
SNES::cpu.disassemble_opcode(t);
echo(utf8() << t << "<br>");
}
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::CPUBus) {
SNES::debugger.step_cpu = true;
SNES::cpu.disassemble_opcode(t, SNES::cpu.opcode_pc);
string s = t;
s.replace(" ", "&nbsp;");
echo(string() << "<font color='#a00000'>" << s << "</font><br>");
disassembler->refresh(Disassembler::CPU, SNES::cpu.opcode_pc);
}
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::APURAM) {
SNES::debugger.step_smp = true;
SNES::smp.disassemble_opcode(t);
echo(utf8() << t << "<br>");
}
if(SNES::debugger.breakpoint[n].source == SNES::Debugger::Breakpoint::APURAM) {
SNES::debugger.step_smp = true;
SNES::smp.disassemble_opcode(t, SNES::smp.opcode_pc);
string s = t;
s.replace(" ", "&nbsp;");
echo(string() << "<font color='#a00000'>" << t << "</font><br>");
disassembler->refresh(Disassembler::SMP, SNES::smp.opcode_pc);
}
} break;
case SNES::Debugger::CPUStep: {
SNES::cpu.disassemble_opcode(t);
SNES::cpu.disassemble_opcode(t, SNES::cpu.regs.pc);
string s = t;
s.replace(" ", "&nbsp;");
echo(utf8() << "<font color='#0000a0'>" << s << "</font><br>");
echo(string() << "<font color='#0000a0'>" << s << "</font><br>");
disassembler->refresh(Disassembler::CPU, SNES::cpu.regs.pc);
} break;
case SNES::Debugger::SMPStep: {
SNES::smp.disassemble_opcode(t);
SNES::smp.disassemble_opcode(t, SNES::smp.regs.pc);
string s = t;
s.replace(" ", "&nbsp;");
echo(utf8() << "<font color='#a00000'>" << s << "</font><br>");
echo(string() << "<font color='#a00000'>" << s << "</font><br>");
disassembler->refresh(Disassembler::SMP, SNES::smp.regs.pc);
} break;
}
}
@@ -200,3 +224,5 @@ void Debugger::frameTick() {
vramViewer->autoUpdate();
}
}
#endif

View File

@@ -1,39 +1,37 @@
#include "hexeditor.moc"
#include "breakpoint.moc"
#include "memory.moc"
#include "vramviewer.moc"
class Debugger : public QObject {
class Debugger : public QbWindow {
Q_OBJECT
public:
QbWindow *window;
QMenuBar *menu;
QMenu *tools;
QAction *tools_breakpoint;
QAction *tools_memory;
QAction *tools_vramViewer;
QMenu *miscOptions;
QAction *miscOptions_clear;
QHBoxLayout *layout;
QTextEdit *console;
QVBoxLayout *controlLayout;
QHBoxLayout *commandLayout;
QPushButton *runBreak;
QPushButton *stepInstruction;
QCheckBox *stepCPU;
QCheckBox *stepSMP;
QCheckBox *traceCPU;
QCheckBox *traceSMP;
QWidget *spacer;
QMenu *tools;
QAction *tools_disassembler;
QAction *tools_breakpoint;
QAction *tools_memory;
QAction *tools_vramViewer;
QMenu *miscOptions;
QAction *miscOptions_clear;
QHBoxLayout *layout;
QTextEdit *console;
QVBoxLayout *controlLayout;
QHBoxLayout *commandLayout;
QPushButton *runBreak;
QPushButton *stepInstruction;
QCheckBox *stepCPU;
QCheckBox *stepSMP;
QCheckBox *traceCPU;
QCheckBox *traceSMP;
QCheckBox *traceMask;
QWidget *spacer;
void modifySystemState(unsigned);
void echo(const char *message);
void tracerUpdate();
void event();
void frameTick();
Debugger();
public slots:
void showDisassembler();
void showBreakpointEditor();
void showMemoryEditor();
void showVramViewer();
@@ -42,9 +40,9 @@ public slots:
void toggleRunStatus();
void stepAction();
void toggleTraceCPU();
void toggleTraceSMP();
private:
unsigned frameCounter;
} *debugger;
};
extern Debugger *debugger;

Some files were not shown because too many files have changed in this diff Show More