Compare commits

..

6 Commits
v053 ... v059

Author SHA1 Message Date
byuu
97a3a28d86 Update to bsnes v059 release.
**Known issues:**
- button menus do not show up with Windows Vista/7 theme
- snesreader's multi-file archive dialog box doesn't redraw itself on
Windows when you choose different games

Windows Qt is buggy as always. Nothing we can do but keep waiting. I'm
also going to hold off on including pixel shaders until Direct3D PS
support is in. It's just going to annoy the 98% of users who can't use
them if I include them now. Yes, Windows OpenGL support is that bad.

Anyway, from v058 wip10, the following changes were made:
- cheat code editor grays out the slot#s when they are empty. I can't
put "Empty" in the text boxes for various reasons.
- added "Clear Selected" button and multi-selection support to cheat
editor. This is meant to quickly erase all slots.
- settings and tools windows start at 600x360 when bsnes.cfg is not
found / empty
- fixed the emulationSpeed section to start with input. instead of
config.
- open-folder concept requires the folders to end in .sfc to work now,
once again doesn't care what the ROM inside is named
(this is meant to mimic OS X .app folders)
- 21fx API extended to map to $2200, $2201 for now; mostly as a test
for A-bus access (21fx->VRAM DMA, etc)
(old $21fx registers remain for now)

I intend to release this on Saturday as-is even if a few small bugs
are reported. But if there's something major we can make another RC
build.
2010-01-07 13:07:56 +00:00
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
byuu
6a17b5ed4f Update to bsnes v054 release.
After a half-dozen hours of installing and compiling various combinations of MinGW and Qt, I've finally found a combination that once again allows for profile-guided optimizations: MinGW GCC 4.3.3 and Qt 4.6.0-beta 1. Though Qt 4.4 still has broken PGO, the latest Qt beta no longer has the process freeze issue upon termination.
This release is essentially the same as v053, but it's now at least as fast as v052 was, and ~10% faster than v053, which lacked profiling.
I did add in two quick changes, however: first, when starting in fullscreen mode, the video output size was being incorrectly set to the windowed size; second, by requiring save states to match the CRC32 of games, it made debugging with them impossible, so I've turned off the CRC32 matching.
2009-10-19 16:58:29 +00:00
252 changed files with 10848 additions and 6342 deletions

View File

@@ -26,7 +26,7 @@ ifeq ($(platform),x)
link += -s
ruby := video.glx video.xv video.qtraster video.sdl
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.pulseaudiosimple audio.ao
ruby += input.sdl input.x
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
@@ -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.053";
static const char bsnesVersion[] = "0.059";
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)
@@ -15,6 +15,7 @@ static const unsigned bsnesSaveStateVersion = 3;
#include <libco/libco.h>
#include <nall/algorithm.hpp>
#include <nall/any.hpp>
#include <nall/array.hpp>
#include <nall/bit.hpp>
#include <nall/detect.hpp>

View File

@@ -6,44 +6,49 @@
namespace SNES {
#include "header.cpp"
#include "gameboyheader.cpp"
#include "serialization.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;
void Cartridge::load(Mode cartridge_mode) {
cartinfo_t cartinfo;
read_header(cartinfo, memory::cartrom.data(), memory::cartrom.size());
set_cartinfo(cartinfo);
mode = cartridge_mode;
read_header(memory::cartrom.data(), memory::cartrom.size());
set(mode, cartridge_mode);
if(cartinfo.ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(cartinfo.ram_size, 0xff), cartinfo.ram_size);
if(ram_size > 0) {
memory::cartram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
}
if(cartinfo.srtc || cartinfo.spc7110rtc) {
if(has_srtc || has_spc7110rtc) {
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
}
if(mode() == ModeBsx) {
if(mode == ModeBsx) {
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
}
if(mode() == ModeSufamiTurbo) {
if(mode == ModeSufamiTurbo) {
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
}
if(mode() == ModeSuperGameBoy) {
if(memory::gbrom.data()) memory::gbram.map(allocate<uint8_t>(64 * 1024, 0xff), 64 * 1024);
if(mode == ModeSuperGameBoy) {
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 +63,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]);
@@ -69,10 +75,10 @@ void Cartridge::load(Mode cartridge_mode) {
for(unsigned n = 0; n < memory::stBrom.size(); n++) checksum = crc32_adjust(checksum, memory::stBrom[n]);
if(memory::gbrom.size() != 0 && memory::gbrom.size() != ~0)
for(unsigned n = 0; n < memory::gbrom.size(); n++) checksum = crc32_adjust(checksum, memory::gbrom[n]);
set(crc32, ~checksum);
crc32 = ~checksum;
#if 0
fprintf(stdout, "crc32 = %.8x\n", crc32());
fprintf(stdout, "crc32 = %.8x\n", (unsigned)crc32);
sha256_ctx sha;
uint8_t shahash[32];
@@ -88,7 +94,7 @@ void Cartridge::load(Mode cartridge_mode) {
bus.load_cart();
system.serialize_init();
set(loaded, true);
loaded = true;
}
void Cartridge::unload() {
@@ -104,50 +110,19 @@ void Cartridge::unload() {
memory::stBram.reset();
memory::gbrom.reset();
memory::gbram.reset();
memory::gbrtc.reset();
if(loaded() == false) return;
if(loaded == false) return;
bus.unload_cart();
set(loaded, false);
loaded = false;
}
Cartridge::Type Cartridge::detect_image_type(uint8_t *data, unsigned size) const {
cartinfo_t info;
read_header(info, data, size);
return info.type;
}
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
}
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
s.array(memory::cartrtc.data(), memory::cartrtc.size());
}
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
s.array(memory::bsxram.data(), memory::bsxram.size());
}
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
s.array(memory::bsxpram.data(), memory::bsxpram.size());
}
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
s.array(memory::stAram.data(), memory::stAram.size());
}
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
s.array(memory::stBram.data(), memory::stBram.size());
}
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
s.array(memory::gbram.data(), memory::gbram.size());
}
bool Cartridge::has_21fx() const {
return s21fx.exists();
}
Cartridge::Cartridge() {
set(loaded, false);
loaded = false;
unload();
}
@@ -155,63 +130,4 @@ Cartridge::~Cartridge() {
unload();
}
void Cartridge::set_cartinfo(const Cartridge::cartinfo_t &source) {
set(region, source.region);
set(mapper, source.mapper);
set(dsp1_mapper, source.dsp1_mapper);
set(has_bsx_slot, source.bsx_slot);
set(has_superfx, source.superfx);
set(has_sa1, source.sa1);
set(has_srtc, source.srtc);
set(has_sdd1, source.sdd1);
set(has_spc7110, source.spc7110);
set(has_spc7110rtc, source.spc7110rtc);
set(has_cx4, source.cx4);
set(has_dsp1, source.dsp1);
set(has_dsp2, source.dsp2);
set(has_dsp3, source.dsp3);
set(has_dsp4, source.dsp4);
set(has_obc1, source.obc1);
set(has_st010, source.st010);
set(has_st011, source.st011);
set(has_st018, source.st018);
}
//==========
//cartinfo_t
//==========
void Cartridge::cartinfo_t::reset() {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
rom_size = 0;
ram_size = 0;
bsx_slot = false;
superfx = false;
sa1 = false;
srtc = false;
sdd1 = false;
spc7110 = false;
spc7110rtc = false;
cx4 = false;
dsp1 = false;
dsp2 = false;
dsp3 = false;
dsp4 = false;
obc1 = false;
st010 = false;
st011 = false;
st018 = false;
}
Cartridge::cartinfo_t::cartinfo_t() {
reset();
}
};

View File

@@ -1,4 +1,4 @@
class Cartridge : public property {
class Cartridge : property<Cartridge> {
public:
enum Mode {
ModeNormal,
@@ -15,7 +15,8 @@ public:
TypeBsx,
TypeSufamiTurboBios,
TypeSufamiTurbo,
TypeSuperGameBoyBios,
TypeSuperGameBoy1Bios,
TypeSuperGameBoy2Bios,
TypeGameBoy,
TypeUnknown,
};
@@ -46,60 +47,41 @@ public:
DSP1HiROM,
};
//properties can be read via operator(), eg "if(cartridge.loaded() == true)";
//warning: if loaded() == false, no other property is considered valid!
readonly<bool> loaded; //is a base cartridge inserted?
readonly<unsigned> crc32; //crc32 of all cartridges (base+slot(s))
property_t<bool> loaded; //is a base cartridge inserted?
property_t<unsigned> crc32; //crc32 of all files sans headers
readonly<Mode> mode;
readonly<Type> type;
readonly<Region> region;
readonly<MemoryMapper> mapper;
readonly<DSP1MemoryMapper> dsp1_mapper;
property_t<Mode> mode;
property_t<Region> region;
property_t<MemoryMapper> mapper;
property_t<DSP1MemoryMapper> dsp1_mapper;
readonly<bool> has_bsx_slot;
readonly<bool> has_superfx;
readonly<bool> has_sa1;
readonly<bool> has_srtc;
readonly<bool> has_sdd1;
readonly<bool> has_spc7110;
readonly<bool> has_spc7110rtc;
readonly<bool> has_cx4;
readonly<bool> has_dsp1;
readonly<bool> has_dsp2;
readonly<bool> has_dsp3;
readonly<bool> has_dsp4;
readonly<bool> has_obc1;
readonly<bool> has_st010;
readonly<bool> has_st011;
readonly<bool> has_st018;
bool has_21fx() const;
property_t<bool> has_bsx_slot;
property_t<bool> has_superfx;
property_t<bool> has_sa1;
property_t<bool> has_srtc;
property_t<bool> has_sdd1;
property_t<bool> has_spc7110, has_spc7110rtc;
property_t<bool> has_cx4;
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;
//main interface
void load(Mode);
void unload();
Type detect_image_type(uint8_t *data, unsigned size) const;
void serialize(serializer&);
Cartridge();
~Cartridge();
private:
struct cartinfo_t {
Type type;
Region region;
MemoryMapper mapper;
DSP1MemoryMapper dsp1_mapper;
unsigned rom_size, ram_size;
bool bsx_slot;
bool superfx;
bool sa1;
bool srtc;
bool sdd1;
bool spc7110, spc7110rtc;
bool cx4;
bool dsp1, dsp2, dsp3, dsp4;
bool obc1;
bool st010, st011, st018;
void reset();
cartinfo_t();
};
enum HeaderField {
CartName = 0x00,
Mapper = 0x15,
@@ -114,10 +96,13 @@ private:
ResetVector = 0x3c,
};
void read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const;
unsigned ram_size;
void read_header(const uint8_t *data, unsigned size);
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 +110,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

View File

@@ -1,7 +1,28 @@
#ifdef CARTRIDGE_CPP
void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size) const {
info.reset();
void Cartridge::read_header(const uint8_t *data, unsigned size) {
type = TypeUnknown;
mapper = LoROM;
dsp1_mapper = DSP1Unmapped;
region = NTSC;
ram_size = 0;
has_bsx_slot = false;
has_superfx = false;
has_sa1 = false;
has_srtc = false;
has_sdd1 = false;
has_spc7110 = false;
has_spc7110rtc = false;
has_cx4 = false;
has_dsp1 = false;
has_dsp2 = false;
has_dsp3 = false;
has_dsp4 = false;
has_obc1 = false;
has_st010 = false;
has_st011 = false;
has_st018 = false;
//=====================
//detect Game Boy carts
@@ -10,23 +31,23 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(size >= 0x0140) {
if(data[0x0104] == 0xce && data[0x0105] == 0xed && data[0x0106] == 0x66 && data[0x0107] == 0x66
&& data[0x0108] == 0xcc && data[0x0109] == 0x0d && data[0x010a] == 0x00 && data[0x010b] == 0x0b) {
info.type = TypeGameBoy;
type = TypeGameBoy;
return;
}
}
const unsigned index = find_header(data, size);
const uint8 mapper = data[index + Mapper];
const uint8 mapperid = data[index + Mapper];
const uint8 rom_type = data[index + RomType];
const uint8 rom_size = data[index + RomSize];
const uint8 company = data[index + Company];
const uint8 region = data[index + CartRegion] & 0x7f;
const uint8 regionid = data[index + CartRegion] & 0x7f;
info.ram_size = 1024 << (data[index + RamSize] & 7);
if(info.ram_size == 1024) info.ram_size = 0; //no RAM present, eg RamSize == 0
ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
//0, 1, 13 = NTSC; 2 - 12 = PAL
info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
region = (regionid <= 1 || regionid >= 13) ? NTSC : PAL;
//=======================
//detect BS-X flash carts
@@ -37,9 +58,9 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
const uint8_t n15 = data[index + 0x15];
if(n15 == 0x00 || n15 == 0x80 || n15 == 0x84 || n15 == 0x9c || n15 == 0xbc || n15 == 0xfc) {
if(data[index + 0x1a] == 0x33 || data[index + 0x1a] == 0xff) {
info.type = TypeBsx;
info.mapper = BSXROM;
info.region = NTSC; //BS-X only released in Japan
type = TypeBsx;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return;
}
}
@@ -52,21 +73,26 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(!memcmp(data, "BANDAI SFC-ADX", 14)) {
if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) {
info.type = TypeSufamiTurboBios;
type = TypeSufamiTurboBios;
} else {
info.type = TypeSufamiTurbo;
type = TypeSufamiTurbo;
}
info.mapper = STROM;
info.region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled internally by load_cart_st();
mapper = STROM;
region = NTSC; //Sufami Turbo only released in Japan
return; //RAM size handled outside this routine
}
//==========================
//detect Super Game Boy BIOS
//==========================
if(!memcmp(data + index, "Super GAMEBOY2", 14)) {
type = TypeSuperGameBoy2Bios;
return;
}
if(!memcmp(data + index, "Super GAMEBOY", 13)) {
info.type = TypeSuperGameBoyBios;
type = TypeSuperGameBoy1Bios;
return;
}
@@ -80,118 +106,119 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
uint8 n13 = data[index - 13];
if((n13 >= 'A' && n13 <= 'Z') || (n13 >= '0' && n13 <= '9')) {
if(company == 0x33 || (data[index - 10] == 0x00 && data[index - 4] == 0x00)) {
info.bsx_slot = true;
has_bsx_slot = true;
}
}
}
}
if(info.bsx_slot == true) {
if(has_bsx_slot) {
if(!memcmp(data + index, "Satellaview BS-X ", 21)) {
//BS-X base cart
info.type = TypeBsxBios;
info.mapper = BSXROM;
info.region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
type = TypeBsxBios;
mapper = BSXROM;
region = NTSC; //BS-X only released in Japan
return; //RAM size handled internally by load_cart_bsx() -> BSXCart class
} else {
info.type = TypeBsxSlotted;
info.mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
type = TypeBsxSlotted;
mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM);
region = NTSC; //BS-X slotted cartridges only released in Japan
}
} else {
//standard cart
info.type = TypeNormal;
type = TypeNormal;
if(index == 0x7fc0 && size >= 0x401000) {
info.mapper = ExLoROM;
} else if(index == 0x7fc0 && mapper == 0x32) {
info.mapper = ExLoROM;
mapper = ExLoROM;
} else if(index == 0x7fc0 && mapperid == 0x32) {
mapper = ExLoROM;
} else if(index == 0x7fc0) {
info.mapper = LoROM;
mapper = LoROM;
} else if(index == 0xffc0) {
info.mapper = HiROM;
mapper = HiROM;
} else { //index == 0x40ffc0
info.mapper = ExHiROM;
mapper = ExHiROM;
}
}
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
info.superfx = true;
info.mapper = SuperFXROM;
info.ram_size = 1024 << (data[index - 3] & 7);
if(info.ram_size == 1024) info.ram_size = 0;
if(mapperid == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
has_superfx = true;
mapper = SuperFXROM;
ram_size = 1024 << (data[index - 3] & 7);
if(ram_size == 1024) ram_size = 0;
}
if(mapper == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
info.sa1 = true;
info.mapper = SA1ROM;
if(mapperid == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {
has_sa1 = true;
mapper = SA1ROM;
}
if(mapper == 0x35 && rom_type == 0x55) {
info.srtc = true;
if(mapperid == 0x35 && rom_type == 0x55) {
has_srtc = true;
}
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
info.sdd1 = true;
if(mapperid == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
has_sdd1 = true;
}
if(mapper == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
info.spc7110 = true;
info.spc7110rtc = (rom_type == 0xf9);
info.mapper = SPC7110ROM;
if(mapperid == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
has_spc7110 = true;
has_spc7110rtc = (rom_type == 0xf9);
mapper = SPC7110ROM;
}
if(mapper == 0x20 && rom_type == 0xf3) {
info.cx4 = true;
if(mapperid == 0x20 && rom_type == 0xf3) {
has_cx4 = true;
}
if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
info.dsp1 = true;
if((mapperid == 0x20 || mapperid == 0x21) && rom_type == 0x03) {
has_dsp1 = true;
}
if(mapper == 0x30 && rom_type == 0x05 && company != 0xb2) {
info.dsp1 = true;
if(mapperid == 0x30 && rom_type == 0x05 && company != 0xb2) {
has_dsp1 = true;
}
if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
info.dsp1 = true;
if(mapperid == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
has_dsp1 = true;
}
if(info.dsp1 == true) {
if((mapper & 0x2f) == 0x20 && size <= 0x100000) {
info.dsp1_mapper = DSP1LoROM1MB;
} else if((mapper & 0x2f) == 0x20) {
info.dsp1_mapper = DSP1LoROM2MB;
} else if((mapper & 0x2f) == 0x21) {
info.dsp1_mapper = DSP1HiROM;
if(has_dsp1 == true) {
if((mapperid & 0x2f) == 0x20 && size <= 0x100000) {
dsp1_mapper = DSP1LoROM1MB;
} else if((mapperid & 0x2f) == 0x20) {
dsp1_mapper = DSP1LoROM2MB;
} else if((mapperid & 0x2f) == 0x21) {
dsp1_mapper = DSP1HiROM;
}
}
if(mapper == 0x20 && rom_type == 0x05) {
info.dsp2 = true;
if(mapperid == 0x20 && rom_type == 0x05) {
has_dsp2 = true;
}
if(mapper == 0x30 && rom_type == 0x05 && company == 0xb2) {
info.dsp3 = true;
if(mapperid == 0x30 && rom_type == 0x05 && company == 0xb2) {
has_dsp3 = true;
}
if(mapper == 0x30 && rom_type == 0x03) {
info.dsp4 = true;
if(mapperid == 0x30 && rom_type == 0x03) {
has_dsp4 = true;
}
if(mapper == 0x30 && rom_type == 0x25) {
info.obc1 = true;
if(mapperid == 0x30 && rom_type == 0x25) {
has_obc1 = true;
}
if(mapper == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
info.st010 = true;
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size >= 10) {
has_st010 = true;
}
if(mapper == 0x30 && rom_type == 0xf6 && rom_size < 10) {
info.st011 = true;
if(mapperid == 0x30 && rom_type == 0xf6 && rom_size < 10) {
has_st011 = true;
}
if(mapper == 0x30 && rom_type == 0xf5) {
info.st018 = true;
if(mapperid == 0x30 && rom_type == 0xf5) {
has_st018 = true;
}
}

View File

@@ -0,0 +1,37 @@
#ifdef CARTRIDGE_CPP
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
}
if(memory::cartrtc.size() != 0 && memory::cartrtc.size() != ~0) {
s.array(memory::cartrtc.data(), memory::cartrtc.size());
}
if(memory::bsxram.size() != 0 && memory::bsxram.size() != ~0) {
s.array(memory::bsxram.data(), memory::bsxram.size());
}
if(memory::bsxpram.size() != 0 && memory::bsxpram.size() != ~0) {
s.array(memory::bsxpram.data(), memory::bsxpram.size());
}
if(memory::stAram.size() != 0 && memory::stAram.size() != ~0) {
s.array(memory::stAram.data(), memory::stAram.size());
}
if(memory::stBram.size() != 0 && memory::stBram.size() != ~0) {
s.array(memory::stBram.data(), memory::stBram.size());
}
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());
}
}
#endif

View File

@@ -1,3 +1,2 @@
unsigned Cheat::count() const { return code.size(); }
bool Cheat::active() const { return cheat_enabled; }
bool Cheat::exists(unsigned addr) const { return mask[addr >> 3] & 1 << (addr & 7); }
bool Cheat::exists(unsigned addr) const { return bitmask[addr >> 3] & 1 << (addr & 7); }

View File

@@ -5,230 +5,73 @@ namespace SNES {
Cheat cheat;
Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) {
enabled = source.enabled;
code = source.code;
desc = source.desc;
count = source.count;
addr.reset();
data.reset();
for(unsigned n = 0; n < count; n++) {
addr[n] = source.addr[n];
data[n] = source.data[n];
}
return *this;
bool Cheat::enabled() const {
return system_enabled;
}
//used to sort cheat code list by description
bool Cheat::cheat_t::operator<(const Cheat::cheat_t& source) {
return strcmp(desc, source.desc) < 0;
void Cheat::enable(bool state) {
system_enabled = state;
cheat_enabled = system_enabled && code_enabled;
}
//parse item ("0123-4567+89AB-CDEF"), return cheat_t item
//return true if code is valid, false otherwise
bool Cheat::decode(const char *s, Cheat::cheat_t &item) const {
item.enabled = false;
item.count = 0;
void Cheat::synchronize() {
memset(bitmask, 0x00, sizeof bitmask);
code_enabled = false;
string code = s;
code.replace(" ", "");
for(unsigned i = 0; i < size(); i++) {
const CheatCode &code = operator[](i);
if(code.enabled == false) continue;
lstring list;
list.split("+", code);
for(unsigned n = 0; n < code.addr.size(); n++) {
code_enabled = true;
for(unsigned n = 0; n < list.size(); n++) {
unsigned addr;
uint8_t data;
type_t type;
if(decode(list[n], addr, data, type) == false) {
item.count = 0;
return false;
unsigned addr = mirror(code.addr[n]);
bitmask[addr >> 3] |= 1 << (addr & 7);
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
unsigned mirroraddr;
for(unsigned x = 0; x <= 0x3f; x++) {
mirroraddr = ((0x00 + x) << 16) + (addr & 0x1fff);
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
mirroraddr = ((0x80 + x) << 16) + (addr & 0x1fff);
bitmask[mirroraddr >> 3] |= 1 << (mirroraddr & 7);
}
}
}
item.addr[item.count] = addr;
item.data[item.count] = data;
item.count++;
}
return true;
cheat_enabled = system_enabled && code_enabled;
}
//read() is used by MemBus::read() if Cheat::enabled(addr) returns true to look up cheat code.
//returns true if cheat code was found, false if it was not.
//when true, cheat code substitution value is stored in data.
bool Cheat::read(unsigned addr, uint8_t &data) const {
addr = mirror_address(addr);
for(unsigned i = 0; i < code.size(); i++) {
if(enabled(i) == false) continue;
bool Cheat::read(unsigned addr, uint8 &data) const {
addr = mirror(addr);
for(unsigned n = 0; n < code[i].count; n++) {
if(addr == mirror_address(code[i].addr[n])) {
data = code[i].data[n];
for(unsigned i = 0; i < size(); i++) {
const CheatCode &code = operator[](i);
if(code.enabled == false) continue;
for(unsigned n = 0; n < code.addr.size(); n++) {
if(addr == mirror(code.addr[n])) {
data = code.data[n];
return true;
}
}
}
//code not found, or code is disabled
return false;
}
//==============
//master control
//==============
//global cheat system enable/disable:
//if disabled, *all* cheat codes are disabled;
//otherwise only individually disabled codes are.
bool Cheat::enabled() const {
return cheat_system_enabled;
Cheat::Cheat() {
system_enabled = true;
synchronize();
}
void Cheat::enable() {
cheat_system_enabled = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
}
//===============
//encode / decode
//===============
void Cheat::disable() {
cheat_system_enabled = false;
cheat_enabled = false;
}
//================================
//cheat list manipulation routines
//================================
void Cheat::add(bool enable, const char *code_, const char *desc_) {
cheat_t item;
decode(code_, item);
unsigned i = code.size();
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
}
void Cheat::edit(unsigned i, bool enable, const char *code_, const char *desc_) {
cheat_t item;
decode(code_, item);
//disable current code and clear from code lookup table
code[i].enabled = false;
update(code[i]);
code[i] = item;
code[i].enabled = enable;
code[i].desc = desc_;
code[i].code = code_;
encode_description(code[i].desc);
update(code[i]);
update_cheat_status();
}
bool Cheat::remove(unsigned i) {
unsigned size = code.size();
if(i >= size) return false; //also verifies size cannot be < 1
for(unsigned n = i; n < size - 1; n++) code[n] = code[n + 1];
code.resize(size - 1);
update_cheat_status();
return true;
}
bool Cheat::get(unsigned i, cheat_t &item) const {
if(i >= code.size()) return false;
item = code[i];
decode_description(item.desc);
return true;
}
//==============================
//cheat status modifier routines
//==============================
bool Cheat::enabled(unsigned i) const {
return (i < code.size() ? code[i].enabled : false);
}
void Cheat::enable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = true;
update(code[i]);
update_cheat_status();
}
void Cheat::disable(unsigned i) {
if(i >= code.size()) return;
code[i].enabled = false;
update(code[i]);
update_cheat_status();
}
//===============================
//cheat file load / save routines
//
//file format:
//"description", status, nnnn-nnnn[+nnnn-nnnn...]\r\n
//...
//===============================
void Cheat::load(string data) {
data.replace("\r", "");
data.qreplace(" ", "");
lstring line;
line.split("\n", data);
for(unsigned i = 0; i < line.size(); i++) {
lstring part;
part.qsplit(",", line[i]);
if(part.size() != 3) continue;
trim(part[2], "\"");
add(part[0] == "enabled", /* code = */ part[1], /* desc = */ part[2]);
}
}
string Cheat::save() const {
string data;
for(unsigned i = 0; i < code.size(); i++) {
data << (code[i].enabled ? "enabled," : "disabled,")
<< code[i].code << ","
<< "\"" << code[i].desc << "\"\r\n";
}
return data;
}
void Cheat::clear() {
cheat_enabled_code_exists = false;
memset(mask, 0, 0x200000);
code.reset();
}
Cheat::Cheat() : cheat_system_enabled(true) {
clear();
}
//==================
//internal functions
//==================
//string <> binary code translation routines
//decode() "7e123456" -> 0x7e123456
//encode() 0x7e123456 -> "7e123456"
bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) const {
bool Cheat::decode(const char *s, unsigned &addr, uint8 &data, Type &type) {
string t = s;
strlower(t);
@@ -274,9 +117,11 @@ bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) c
} else {
return false;
}
#undef ischr
}
bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
bool Cheat::encode(string &s, unsigned addr, uint8 data, Type type) {
char t[16];
if(type == ProActionReplay) {
@@ -306,90 +151,46 @@ bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const {
}
}
//speed up S-CPU memory reads by disabling cheat code lookup when either:
//a) cheat system is disabled by user, or b) no enabled cheat codes exist
void Cheat::update_cheat_status() {
for(unsigned i = 0; i < code.size(); i++) {
if(code[i].enabled) {
cheat_enabled_code_exists = true;
cheat_enabled = (cheat_system_enabled && cheat_enabled_code_exists);
return;
//========
//internal
//========
unsigned Cheat::mirror(unsigned addr) const {
//$00-3f|80-bf:0000-1fff -> $7e:0000-1fff
if((addr & 0x40e000) == 0x000000) return (0x7e0000 + (addr & 0x1fff));
return addr;
}
//=========
//CheatCode
//=========
bool CheatCode::operator=(string s) {
addr.reset();
data.reset();
lstring list;
list.split("+", s.replace(" ", ""));
for(unsigned i = 0; i < list.size(); i++) {
unsigned addr_;
uint8 data_;
Cheat::Type type_;
if(Cheat::decode(list[i], addr_, data_, type_) == false) {
addr.reset();
data.reset();
return false;
}
addr.add(addr_);
data.add(data_);
}
cheat_enabled_code_exists = false;
cheat_enabled = false;
return true;
}
//address lookup table manipulation and mirroring
//mirror_address() 0x000000 -> 0x7e0000
//set() enable specified address, mirror accordingly
//clear() disable specified address, mirror accordingly
unsigned Cheat::mirror_address(unsigned addr) const {
if((addr & 0x40e000) != 0x0000) return addr;
//8k WRAM mirror
//$[00-3f|80-bf]:[0000-1fff] -> $7e:[0000-1fff]
return (0x7e0000 + (addr & 0x1fff));
CheatCode::CheatCode() {
enabled = false;
}
//updates mask[] table enabled bits;
//must be called after modifying item.enabled state.
void Cheat::update(const cheat_t &item) {
for(unsigned n = 0; n < item.count; n++) {
(item.enabled) ? set(item.addr[n]) : clear(item.addr[n]);
}
}
void Cheat::set(unsigned addr) {
addr = mirror_address(addr);
mask[addr >> 3] |= 1 << (addr & 7);
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] |= 1 << (mirror & 7);
}
}
}
void Cheat::clear(unsigned addr) {
addr = mirror_address(addr);
//if there is more than one cheat code using the same address,
//(eg with a different override value) then do not clear code
//lookup table entry.
uint8_t r;
if(read(addr, r) == true) return;
mask[addr >> 3] &= ~(1 << (addr & 7));
if((addr & 0xffe000) == 0x7e0000) {
//mirror $7e:[0000-1fff] to $[00-3f|80-bf]:[0000-1fff]
unsigned mirror;
for(unsigned x = 0; x <= 0x3f; x++) {
mirror = ((0x00 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
mirror = ((0x80 + x) << 16) + (addr & 0x1fff);
mask[mirror >> 3] &= ~(1 << (mirror & 7));
}
}
}
//these two functions are used to safely store description text inside .cfg file format.
string& Cheat::encode_description(string &desc) const {
desc.replace("\"", "\\q");
desc.replace("\n", "\\n");
return desc;
}
string& Cheat::decode_description(string &desc) const {
desc.replace("\\q", "\"");
desc.replace("\\n", "\n");
return desc;
}
};

View File

@@ -1,69 +1,35 @@
class Cheat {
struct CheatCode {
bool enabled;
array<unsigned> addr;
array<uint8> data;
bool operator=(string);
CheatCode();
};
class Cheat : public vector<CheatCode> {
public:
enum type_t {
ProActionReplay,
GameGenie,
};
struct cheat_t {
bool enabled;
string code;
string desc;
unsigned count;
array<unsigned> addr;
array<uint8_t> data;
cheat_t& operator=(const cheat_t&);
bool operator<(const cheat_t&);
};
bool decode(const char *s, cheat_t &item) const;
bool read(unsigned addr, uint8_t &data) const;
enum Type { ProActionReplay, GameGenie };
bool enabled() const;
void enable();
void disable();
void enable(bool);
void synchronize();
bool read(unsigned, uint8&) const;
inline unsigned count() const;
inline bool active() const;
inline bool exists(unsigned addr) const;
void add(bool enable, const char *code, const char *desc);
void edit(unsigned i, bool enable, const char *code, const char *desc);
bool remove(unsigned i);
bool get(unsigned i, cheat_t &item) const;
bool enabled(unsigned i) const;
void enable(unsigned i);
void disable(unsigned i);
void load(string data);
string save() const;
void clear();
Cheat();
static bool decode(const char*, unsigned&, uint8&, Type&);
static bool encode(string&, unsigned, uint8, Type);
private:
bool cheat_enabled; //cheat_enabled == (cheat_enabled_code_exists && cheat_system_enabled);
bool cheat_enabled_code_exists;
bool cheat_system_enabled;
uint8_t mask[0x200000];
vector<cheat_t> code;
bool decode(const char *str, unsigned &addr, uint8_t &data, type_t &type) const;
bool encode(string &str, unsigned addr, uint8_t data, type_t type) const;
void update_cheat_status();
unsigned mirror_address(unsigned addr) const;
void update(const cheat_t& item);
void set(unsigned addr);
void clear(unsigned addr);
string& encode_description(string &desc) const;
string& decode_description(string &desc) const;
uint8 bitmask[0x200000];
bool system_enabled;
bool code_enabled;
bool cheat_enabled;
unsigned mirror(unsigned) const;
};
extern Cheat cheat;

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

@@ -0,0 +1,195 @@
#include <../base.hpp>
//B-bus interface
//$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 (0)
//
//
//$21f1 parameter port (w)
//-------------------------
//(shift register)
//
//
//$21f2 data port (r)
//--------------------
//(auto-increment read port)
//A-bus interface
//$2200 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 (0)
//
//$2201 data port (r/w)
//----------------------
//(shift register)
//
//(auto-increment read port)
#define S21FX_CPP
namespace SNES {
S21fx s21fx;
#include "serialization.cpp"
void S21fx::enter() {
scheduler.clock.cop_freq = 44100;
while(true) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
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);
}
memory::mmio.map(0x2200, *this);
memory::mmio.map(0x2201, *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) || (addr == 0x2200)) {
return mmio.status | 0x00;
}
if((addr == 0x21f2) || (addr == 0x2201)) {
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) || (addr == 0x2200)) {
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) || (addr == 0x2201)) {
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

@@ -4,14 +4,14 @@ VBRBus vbrbus;
SA1Bus sa1bus;
namespace memory {
static StaticRAM iram(2048);
//accessed by:
static VectorSelectionPage vectorsp; //S-CPU + SA-1
static CPUIRAM cpuiram; //S-CPU
static SA1IRAM sa1iram; //SA-1
static SA1BWRAM sa1bwram; //SA-1
static CC1BWRAM cc1bwram; //S-CPU
static BitmapRAM bitmapram; //SA-1
StaticRAM iram(2048);
//accessed by:
VectorSelectionPage vectorsp; //S-CPU + SA-1
CPUIRAM cpuiram; //S-CPU
SA1IRAM sa1iram; //SA-1
SA1BWRAM sa1bwram; //SA-1
CC1BWRAM cc1bwram; //S-CPU
BitmapRAM bitmapram; //SA-1
}
//$230c (VDPL), $230d (VDPH) use this bus to read variable-length data.

View File

@@ -43,3 +43,14 @@ struct BitmapRAM : Memory {
alwaysinline uint8 read(unsigned);
alwaysinline void write(unsigned, uint8);
};
namespace memory {
extern StaticRAM iram;
extern VectorSelectionPage vectorsp;
extern CPUIRAM cpuiram;
extern SA1IRAM sa1iram;
extern SA1BWRAM sa1bwram;
extern CC1BWRAM cc1bwram;
extern BitmapRAM bitmapram;
};

View File

@@ -5,6 +5,7 @@ namespace SNES {
SA1 sa1;
#include "serialization.cpp"
#include "bus/bus.cpp"
#include "dma/dma.cpp"
#include "memory/memory.cpp"
@@ -12,10 +13,15 @@ SA1 sa1;
void SA1::enter() {
while(true) {
while(mmio.sa1_rdyb || mmio.sa1_resb) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
if(mmio.sa1_rdyb || mmio.sa1_resb) {
//SA-1 co-processor is asleep
tick();
scheduler.sync_copcpu();
continue;
}
if(status.interrupt_pending) {
@@ -139,7 +145,7 @@ void SA1::reset() {
regs.e = 1;
regs.mdr = 0x00;
regs.wai = false;
update_table();
CPUcore::update_table();
status.tick_counter = 0;

View File

@@ -30,6 +30,7 @@ public:
void power();
void reset();
void serialize(serializer&);
SA1();
};

View File

@@ -0,0 +1,150 @@
#ifdef SA1_CPP
void SA1::serialize(serializer &s) {
CPUcore::core_serialize(s);
//sa1.hpp
s.integer(status.tick_counter);
s.integer(status.interrupt_pending);
s.integer(status.interrupt_vector);
s.integer(status.scanlines);
s.integer(status.vcounter);
s.integer(status.hcounter);
//bus/bus.hpp
s.array(memory::iram.data(), memory::iram.size());
memory::vectorsp.sync();
s.integer(memory::cc1bwram.dma);
//dma/dma.hpp
s.integer(dma.line);
//mmio/mmio.hpp
s.integer(mmio.sa1_irq);
s.integer(mmio.sa1_rdyb);
s.integer(mmio.sa1_resb);
s.integer(mmio.sa1_nmi);
s.integer(mmio.smeg);
s.integer(mmio.cpu_irqen);
s.integer(mmio.chdma_irqen);
s.integer(mmio.cpu_irqcl);
s.integer(mmio.chdma_irqcl);
s.integer(mmio.crv);
s.integer(mmio.cnv);
s.integer(mmio.civ);
s.integer(mmio.cpu_irq);
s.integer(mmio.cpu_ivsw);
s.integer(mmio.cpu_nvsw);
s.integer(mmio.cmeg);
s.integer(mmio.sa1_irqen);
s.integer(mmio.timer_irqen);
s.integer(mmio.dma_irqen);
s.integer(mmio.sa1_nmien);
s.integer(mmio.sa1_irqcl);
s.integer(mmio.timer_irqcl);
s.integer(mmio.dma_irqcl);
s.integer(mmio.sa1_nmicl);
s.integer(mmio.snv);
s.integer(mmio.siv);
s.integer(mmio.hvselb);
s.integer(mmio.ven);
s.integer(mmio.hen);
s.integer(mmio.hcnt);
s.integer(mmio.vcnt);
s.integer(mmio.cbmode);
s.integer(mmio.cb);
s.integer(mmio.dbmode);
s.integer(mmio.db);
s.integer(mmio.ebmode);
s.integer(mmio.eb);
s.integer(mmio.fbmode);
s.integer(mmio.fb);
s.integer(mmio.sbm);
s.integer(mmio.sw46);
s.integer(mmio.cbm);
s.integer(mmio.swen);
s.integer(mmio.cwen);
s.integer(mmio.bwp);
s.integer(mmio.siwp);
s.integer(mmio.ciwp);
s.integer(mmio.dmaen);
s.integer(mmio.dprio);
s.integer(mmio.cden);
s.integer(mmio.cdsel);
s.integer(mmio.dd);
s.integer(mmio.sd);
s.integer(mmio.chdend);
s.integer(mmio.dmasize);
s.integer(mmio.dmacb);
s.integer(mmio.dsa);
s.integer(mmio.dda);
s.integer(mmio.dtc);
s.integer(mmio.bbf);
s.array(mmio.brf);
s.integer(mmio.acm);
s.integer(mmio.md);
s.integer(mmio.ma);
s.integer(mmio.mb);
s.integer(mmio.hl);
s.integer(mmio.vb);
s.integer(mmio.va);
s.integer(mmio.vbit);
s.integer(mmio.cpu_irqfl);
s.integer(mmio.chdma_irqfl);
s.integer(mmio.sa1_irqfl);
s.integer(mmio.timer_irqfl);
s.integer(mmio.dma_irqfl);
s.integer(mmio.sa1_nmifl);
s.integer(mmio.hcr);
s.integer(mmio.vcr);
s.integer(mmio.mr);
s.integer(mmio.overflow);
}
#endif

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

@@ -3,11 +3,11 @@
SuperFXBus superfxbus;
namespace memory {
static SuperFXGSUROM gsurom;
static SuperFXGSURAM gsuram;
static SuperFXCPUROM fxrom;
static SuperFXCPURAM fxram;
};
SuperFXGSUROM gsurom;
SuperFXGSURAM gsuram;
SuperFXCPUROM fxrom;
SuperFXCPURAM fxram;
}
void SuperFXBus::init() {
map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
@@ -34,7 +34,7 @@ unsigned SuperFXGSUROM::size() const {
}
uint8 SuperFXGSUROM::read(unsigned addr) {
while(!superfx.regs.scmr.ron) {
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}
@@ -42,7 +42,7 @@ uint8 SuperFXGSUROM::read(unsigned addr) {
}
void SuperFXGSUROM::write(unsigned addr, uint8 data) {
while(!superfx.regs.scmr.ron) {
while(!superfx.regs.scmr.ron && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}
@@ -54,7 +54,7 @@ unsigned SuperFXGSURAM::size() const {
}
uint8 SuperFXGSURAM::read(unsigned addr) {
while(!superfx.regs.scmr.ran) {
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}
@@ -62,7 +62,7 @@ uint8 SuperFXGSURAM::read(unsigned addr) {
}
void SuperFXGSURAM::write(unsigned addr, uint8 data) {
while(!superfx.regs.scmr.ran) {
while(!superfx.regs.scmr.ran && scheduler.sync != Scheduler::SyncAll) {
superfx.add_clocks(6);
scheduler.sync_copcpu();
}

View File

@@ -25,3 +25,10 @@ struct SuperFXCPURAM : Memory {
uint8 read(unsigned);
void write(unsigned, uint8);
};
namespace memory {
extern SuperFXGSUROM gsurom;
extern SuperFXGSURAM gsuram;
extern SuperFXCPUROM fxrom;
extern SuperFXCPURAM fxram;
}

View File

@@ -114,7 +114,7 @@ void SuperFX::op_bvs() {
//$10-1f(b1): move rN
template<int n> void SuperFX::op_to_r() {
if(regs.sfr.b == 0) {
regs.dreg = &regs.r[n];
regs.dreg = n;
} else {
regs.r[n] = regs.sr();
regs.reset();
@@ -123,8 +123,8 @@ template<int n> void SuperFX::op_to_r() {
//$20-2f: with rN
template<int n> void SuperFX::op_with_r() {
regs.sreg = &regs.r[n];
regs.dreg = &regs.r[n];
regs.sreg = n;
regs.dreg = n;
regs.sfr.b = 1;
}
@@ -519,7 +519,7 @@ template<int n> void SuperFX::op_sms_r() {
//$b0-bf(b1): moves rN
template<int n> void SuperFX::op_from_r() {
if(regs.sfr.b == 0) {
regs.sreg = &regs.r[n];
regs.sreg = n;
} else {
regs.dr() = regs.r[n];
regs.sfr.ov = (regs.dr() & 0x80);

View File

@@ -149,17 +149,17 @@ struct regs_t {
uint16 ramar; //RAM buffer address register
uint8 ramdr; //RAM buffer data register
reg16_t *sreg, *dreg;
reg16_t& sr() { return *sreg; } //source register (from)
reg16_t& dr() { return *dreg; } //destination register (to)
unsigned sreg, dreg;
reg16_t& sr() { return r[sreg]; } //source register (from)
reg16_t& dr() { return r[dreg]; } //destination register (to)
void reset() {
sfr.b = 0;
sfr.alt1 = 0;
sfr.alt2 = 0;
sreg = &r[0];
dreg = &r[0];
sreg = 0;
dreg = 0;
}
} regs;

View File

@@ -1,3 +1,5 @@
#ifdef SUPERFX_CPP
void SuperFX::disassemble_opcode(char *output) {
*output = 0;
@@ -273,3 +275,5 @@ void SuperFX::disassemble_alt3(char *output) {
#undef op0
#undef op1
#undef op2
#endif

View File

@@ -1,3 +1,5 @@
#ifdef SUPERFX_CPP
uint8 SuperFX::op_read(uint16 addr) {
uint16 offset = addr - regs.cbr;
if(offset < 512) {
@@ -65,3 +67,5 @@ void SuperFX::memory_reset() {
pixelcache[n].bitpend = 0x00;
}
}
#endif

View File

@@ -0,0 +1,94 @@
#ifdef SUPERFX_CPP
void SuperFX::serialize(serializer &s) {
//superfx.hpp
s.integer(clockmode);
s.integer(instruction_counter);
//core/registers.hpp
s.integer(regs.pipeline);
s.integer(regs.ramaddr);
s.integer(regs.r[ 0].data);
s.integer(regs.r[ 1].data);
s.integer(regs.r[ 2].data);
s.integer(regs.r[ 3].data);
s.integer(regs.r[ 4].data);
s.integer(regs.r[ 5].data);
s.integer(regs.r[ 6].data);
s.integer(regs.r[ 7].data);
s.integer(regs.r[ 8].data);
s.integer(regs.r[ 9].data);
s.integer(regs.r[10].data);
s.integer(regs.r[11].data);
s.integer(regs.r[12].data);
s.integer(regs.r[13].data);
s.integer(regs.r[14].data);
s.integer(regs.r[15].data);
s.integer(regs.sfr.irq);
s.integer(regs.sfr.b);
s.integer(regs.sfr.ih);
s.integer(regs.sfr.il);
s.integer(regs.sfr.alt2);
s.integer(regs.sfr.alt1);
s.integer(regs.sfr.r);
s.integer(regs.sfr.g);
s.integer(regs.sfr.ov);
s.integer(regs.sfr.s);
s.integer(regs.sfr.cy);
s.integer(regs.sfr.z);
s.integer(regs.pbr);
s.integer(regs.rombr);
s.integer(regs.rambr);
s.integer(regs.cbr);
s.integer(regs.scbr);
s.integer(regs.scmr.ht);
s.integer(regs.scmr.ron);
s.integer(regs.scmr.ran);
s.integer(regs.scmr.md);
s.integer(regs.colr);
s.integer(regs.por.obj);
s.integer(regs.por.freezehigh);
s.integer(regs.por.highnibble);
s.integer(regs.por.dither);
s.integer(regs.por.transparent);
s.integer(regs.bramr);
s.integer(regs.vcr);
s.integer(regs.cfgr.irq);
s.integer(regs.cfgr.ms0);
s.integer(regs.clsr);
s.integer(regs.romcl);
s.integer(regs.romdr);
s.integer(regs.ramcl);
s.integer(regs.ramar);
s.integer(regs.ramdr);
s.integer(regs.sreg);
s.integer(regs.dreg);
s.array(cache.buffer);
s.array(cache.valid);
for(unsigned i = 0; i < 2; i++) {
s.integer(pixelcache[i].offset);
s.integer(pixelcache[i].bitpend);
s.array(pixelcache[i].data);
}
//timing/timing.hpp
s.integer(cache_access_speed);
s.integer(memory_access_speed);
s.integer(r15_modified);
}
#endif

View File

@@ -3,6 +3,7 @@
#define SUPERFX_CPP
namespace SNES {
#include "serialization.cpp"
#include "bus/bus.cpp"
#include "core/core.cpp"
#include "memory/memory.cpp"
@@ -14,9 +15,14 @@ SuperFX superfx;
void SuperFX::enter() {
while(true) {
while(regs.sfr.g == 0) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
if(regs.sfr.g == 0) {
add_clocks(6);
scheduler.sync_copcpu();
continue;
}
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
@@ -70,4 +76,4 @@ void SuperFX::reset() {
timing_reset();
}
};
}

View File

@@ -15,6 +15,8 @@ public:
void power();
void reset();
void serialize(serializer&);
private:
unsigned clockmode;
unsigned instruction_counter;

View File

@@ -1,3 +1,5 @@
#ifdef SUPERFX_CPP
void SuperFX::add_clocks(unsigned clocks) {
if(regs.romcl) {
regs.romcl -= min(clocks, regs.romcl);
@@ -91,3 +93,5 @@ void SuperFX::timing_reset() {
regs.ramar = 0;
regs.ramdr = 0;
}
#endif

View File

@@ -0,0 +1,140 @@
#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) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
audio.coprocessor_sample(0, 0);
scheduler.addclocks_cop(1);
scheduler.sync_copcpu();
}
while(true) {
if(scheduler.sync == Scheduler::SyncAll) {
scheduler.exit(Scheduler::SynchronizeEvent);
}
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() {
version = (cartridge.type() == Cartridge::TypeSuperGameBoy1Bios ? 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());
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

@@ -5,7 +5,7 @@ namespace SNES {
#include "serialization.cpp"
#include "algorithms.cpp"
#include "disasm/disasm.cpp"
#include "disassembler/disassembler.cpp"
#define L last_cycle();
#define A 0

View File

@@ -2,7 +2,7 @@ class CPUcore {
public:
#include "registers.hpp"
#include "memory.hpp"
#include "disasm/disasm.hpp"
#include "disassembler/disassembler.hpp"
regs_t regs;
reg24_t aa, rd;

View File

@@ -1,30 +0,0 @@
enum {
OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC, //pbr:(addr)
OPTYPE_RELB, //relb
OPTYPE_RELW, //relw
};
void disassemble_opcode(char *output);
uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);
uint32 decode(uint8 offset_type, uint32 addr);
uint8 opcode_length();

View File

@@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
uint8 CPUcore::dreadb(uint32 addr) {
if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) {
//$[00-3f|80-bf]:[2000-5fff]
@@ -102,7 +104,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 +114,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++;
@@ -477,3 +479,5 @@ uint8 CPUcore::opcode_length() {
if(len == 6) return (regs.e || regs.p.x) ? 2 : 3;
return len;
}
#endif

View File

@@ -0,0 +1,30 @@
enum {
OPTYPE_DP = 0, //dp
OPTYPE_DPX, //dp,x
OPTYPE_DPY, //dp,y
OPTYPE_IDP, //(dp)
OPTYPE_IDPX, //(dp,x)
OPTYPE_IDPY, //(dp),y
OPTYPE_ILDP, //[dp]
OPTYPE_ILDPY, //[dp],y
OPTYPE_ADDR, //addr
OPTYPE_ADDRX, //addr,x
OPTYPE_ADDRY, //addr,y
OPTYPE_IADDRX, //(addr,x)
OPTYPE_ILADDR, //[addr]
OPTYPE_LONG, //long
OPTYPE_LONGX, //long, x
OPTYPE_SR, //sr,s
OPTYPE_ISRY, //(sr,s),y
OPTYPE_ADDR_PC, //pbr:addr
OPTYPE_IADDR_PC, //pbr:(addr)
OPTYPE_RELB, //relb
OPTYPE_RELW, //relw
};
void disassemble_opcode(char *output, uint32 addr);
uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);
uint32 decode(uint8 offset_type, uint32 addr);
uint8 opcode_length();

View File

@@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
void CPUcore::op_nop() {
L op_io_irq();
}
@@ -346,3 +348,5 @@ void CPUcore::op_per_n() {
op_writestackn(rd.h);
L op_writestackn(rd.l);
}
#endif

View File

@@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<int bit, int val> void CPUcore::op_branch() {
if((bool)(regs.p & bit) != val) {
L rd.l = op_readpc();
@@ -175,3 +177,5 @@ L rd.b = op_readstackn();
regs.pc.b = rd.b;
regs.pc.w = ++rd.w;
}
#endif

View File

@@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<void (CPUcore::*op)()> void CPUcore::op_read_const_b() {
L rd.l = op_readpc();
call(op);
@@ -273,3 +275,5 @@ template<void (CPUcore::*op)()> void CPUcore::op_read_isry_w() {
L rd.h = op_readdbr(aa.w + regs.y.w + 1);
call(op);
}
#endif

View File

@@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<int n, int adjust> void CPUcore::op_adjust_imm_b() {
L op_io_irq();
regs.r[n].l += adjust;
@@ -163,3 +165,5 @@ template<void (CPUcore::*op)()> void CPUcore::op_adjust_dpx_w() {
op_writedp(dp + regs.x.w + 1, rd.h);
L op_writedp(dp + regs.x.w + 0, rd.l);
}
#endif

View File

@@ -1,3 +1,5 @@
#ifdef CPUCORE_CPP
template<int n> void CPUcore::op_write_addr_b() {
aa.l = op_readpc();
aa.h = op_readpc();
@@ -193,3 +195,5 @@ void CPUcore::op_sta_isry_w() {
op_writedbr(aa.w + regs.y.w + 0, regs.a.l);
L op_writedbr(aa.w + regs.y.w + 1, regs.a.h);
}
#endif

59
src/cpu/cpu-debugger.cpp Normal file
View File

@@ -0,0 +1,59 @@
#ifdef CPU_CPP
bool CPUDebugger::property(unsigned id, string &name, string &value) {
unsigned n = 0;
//internal
if(id == n++) { name = "S-CPU MDR"; value = string::printf("0x%.2x", mdr()); return true; }
//$2181-2183
if(id == n++) { name = "$2181-$2183"; value = ""; return true; }
if(id == n++) { name = "WRAM Address"; value = string::printf("0x%.6x", wram_address()); return true; }
//$4016
if(id == n++) { name = "$4016"; value = ""; return true; }
if(id == n++) { name = "Joypad Strobe Latch"; value = joypad_strobe_latch(); return true; }
//$4200
if(id == n++) { name = "$4200"; value = ""; return true; }
if(id == n++) { name = "NMI Enable"; value = nmi_enable(); return true; }
if(id == n++) { name = "H-IRQ Enable"; value = hirq_enable(); return true; }
if(id == n++) { name = "V-IRQ Enable"; value = virq_enable(); return true; }
if(id == n++) { name = "Auto Joypad Poll"; value = auto_joypad_poll(); return true; }
//$4201
if(id == n++) { name = "$4201"; value = ""; return true; }
if(id == n++) { name = "PIO"; value = string::printf("0x%.2x", pio_bits()); return true; }
//$4202
if(id == n++) { name = "$4202"; value = ""; return true; }
if(id == n++) { name = "Multiplicand"; value = string::printf("0x%.2x", multiplicand()); return true; }
//$4203
if(id == n++) { name = "$4203"; value = ""; return true; }
if(id == n++) { name = "Multiplier"; value = string::printf("0x%.2x", multiplier()); return true; }
//$4204-$4205
if(id == n++) { name = "$4204-$4205"; value = ""; return true; }
if(id == n++) { name = "Dividend"; value = string::printf("0x%.4x", dividend()); return true; }
//$4206
if(id == n++) { name = "$4206"; value = ""; return true; }
if(id == n++) { name = "Divisor"; value = string::printf("0x%.2x", divisor()); return true; }
//$4207-$4208
if(id == n++) { name = "$4207-$4208"; value = ""; return true; }
if(id == n++) { name = "H-Time"; value = string::printf("0x%.4x", htime()); return true; }
//$4209-$420a
if(id == n++) { name = "$4209-$420a"; value = ""; return true; }
if(id == n++) { name = "V-Time"; value = string::printf("0x%.4x", vtime()); return true; }
//$420d
if(id == n++) { name = "$420d"; value = ""; return true; }
if(id == n++) { name = "FastROM Enable"; value = fastrom_enable(); return true; }
return false;
}
#endif

42
src/cpu/cpu-debugger.hpp Normal file
View File

@@ -0,0 +1,42 @@
struct CPUDebugger : ChipDebugger {
bool property(unsigned id, string &name, string &value);
//internal
virtual unsigned mdr() { return 0; }
//$2181-2183
virtual unsigned wram_address() { return 0; }
//$4016
virtual bool joypad_strobe_latch() { return 0; }
//$4200
virtual bool nmi_enable() { return 0; }
virtual bool hirq_enable() { return 0; }
virtual bool virq_enable() { return 0; }
virtual bool auto_joypad_poll() { return 0; }
//$4201
virtual unsigned pio_bits() { return 0; }
//$4202
virtual unsigned multiplicand() { return 0; }
//$4203
virtual unsigned multiplier() { return 0; }
//$4204-$4205
virtual unsigned dividend() { return 0; }
//$4206
virtual unsigned divisor() { return 0; }
//$4207-$4208
virtual unsigned htime() { return 0; }
//$4209-$420a
virtual unsigned vtime() { return 0; }
//$420d
virtual bool fastrom_enable() { return 0; }
};

View File

@@ -3,6 +3,10 @@
#define CPU_CPP
namespace SNES {
#if defined(DEBUGGER)
#include "cpu-debugger.cpp"
#endif
void CPU::power() {
cpu_version = config.cpu.version;
}

View File

@@ -1,3 +1,7 @@
#if defined(DEBUGGER)
#include "cpu-debugger.hpp"
#endif
class CPU : public PPUcounter, public MMIO {
public:
virtual void enter() = 0;

View File

@@ -1,34 +1,88 @@
#ifdef SCPU_CPP
void sCPUDebug::op_step() {
void sCPUDebugger::op_step() {
bool break_event = false;
usage[regs.pc] &= ~(UsageFlagM | UsageFlagX);
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
opcode_pc = regs.pc;
if(debugger.step_cpu) {
debugger.break_event = Debugger::CPUStep;
scheduler.exit();
scheduler.exit(Scheduler::DebuggerEvent);
} else {
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");
}
if(step_event) step_event();
sCPU::op_step();
scheduler.sync_cpusmp();
}
uint8 sCPUDebug::op_read(uint32 addr) {
uint8 sCPUDebugger::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) {
void sCPUDebugger::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);
}
sCPUDebugger::sCPUDebugger() {
usage = new uint8[1 << 24]();
opcode_pc = 0x8000;
}
sCPUDebugger::~sCPUDebugger() {
delete[] usage;
}
//===========
//CPUDebugger
//===========
//internal
unsigned sCPUDebugger::mdr() { return regs.mdr; }
//$2181-$2183
unsigned sCPUDebugger::wram_address() { return status.wram_addr; }
//$4016
bool sCPUDebugger::joypad_strobe_latch() { return status.joypad_strobe_latch; }
//$4200
bool sCPUDebugger::nmi_enable() { return status.nmi_enabled; }
bool sCPUDebugger::hirq_enable() { return status.hirq_enabled; }
bool sCPUDebugger::virq_enable() { return status.virq_enabled; }
bool sCPUDebugger::auto_joypad_poll() { return status.auto_joypad_poll; }
//$4201
unsigned sCPUDebugger::pio_bits() { return status.pio; }
//$4202
unsigned sCPUDebugger::multiplicand() { return status.mul_a; }
//$4203
unsigned sCPUDebugger::multiplier() { return status.mul_b; }
//$4204-$4205
unsigned sCPUDebugger::dividend() { return status.div_a; }
//$4206
unsigned sCPUDebugger::divisor() { return status.div_b; }
//$4207-$4208
unsigned sCPUDebugger::htime() { return status.hirq_pos; }
//$4209-$420a
unsigned sCPUDebugger::vtime() { return status.virq_pos; }
//$420d
bool sCPUDebugger::fastrom_enable() { return status.rom_speed; }
#endif

View File

@@ -1,6 +1,64 @@
class sCPUDebug : public sCPU {
class sCPUDebugger : public sCPU, public CPUDebugger {
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);
sCPUDebugger();
~sCPUDebugger();
//===========
//CPUDebugger
//===========
//internal
unsigned mdr();
//$2181-$2183
unsigned wram_address();
//$4016
bool joypad_strobe_latch();
//$4200
bool nmi_enable();
bool hirq_enable();
bool virq_enable();
bool auto_joypad_poll();
//$4201
unsigned pio_bits();
//$4202
unsigned multiplicand();
//$4203
unsigned multiplier();
//$4204-$4205
unsigned dividend();
//$4206
unsigned divisor();
//$4207-$4208
unsigned htime();
//$4209-$420a
unsigned vtime();
//$420d
bool fastrom_enable();
};

View File

@@ -5,7 +5,7 @@ namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
sCPUDebug cpu;
sCPUDebugger cpu;
#else
sCPU cpu;
#endif
@@ -20,7 +20,7 @@ void sCPU::enter() {
while(true) {
if(scheduler.sync == Scheduler::SyncCpu) {
scheduler.sync = Scheduler::SyncAll;
scheduler.exit();
scheduler.exit(Scheduler::SynchronizeEvent);
}
if(status.interrupt_pending) {

View File

@@ -100,7 +100,7 @@ public:
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern sCPUDebug cpu;
extern sCPUDebugger cpu;
#else
extern sCPU cpu;
#endif

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.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 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.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

View File

@@ -1,7 +1,7 @@
#include <../base.hpp>
#define ADSP_CPP
namespaec SNES {
namespace SNES {
aDSP dsp;

View File

@@ -1,3 +1,3 @@
class sDSPDebug : public sDSP {
class sDSPDebugger : public sDSP {
public:
};

View File

@@ -9,7 +9,7 @@ namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
sDSPDebug dsp;
sDSPDebugger dsp;
#else
sDSP dsp;
#endif
@@ -20,7 +20,10 @@ namespace SNES {
#define VREG(n) state.regs[v.vidx + v_##n]
#if !defined(DSP_STATE_MACHINE)
#define phase_start() while(true) { if(scheduler.sync == Scheduler::SyncAll) scheduler.exit();
#define phase_start() while(true) { \
if(scheduler.sync == Scheduler::SyncAll) { \
scheduler.exit(Scheduler::SynchronizeEvent); \
}
#define phase(n)
#define tick() scheduler.addclocks_dsp(3 * 8); scheduler.sync_dspsmp()
#define phase_end() }

View File

@@ -170,7 +170,7 @@ private:
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern sDSPDebug dsp;
extern sDSPDebugger dsp;
#else
extern sDSP dsp;
#endif

View File

@@ -5,6 +5,10 @@
#endif
namespace SNES {
struct ChipDebugger {
virtual bool property(unsigned id, string &name, string &value) = 0;
};
#include "memory/memory.hpp"
#include "memory/smemory/smemory.hpp"

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

@@ -1,45 +1,91 @@
#ifndef NALL_PROPERTY_HPP
#define NALL_PROPERTY_HPP
//nall::property implements a variable container that disallows write access
//to non-derived objects. This requires use of property::set(), as C++ lacks
//the ability to make this implementation completely transparent.
//nall::property implements ownership semantics into container classes
//example: property<owner>::readonly<type> implies that only owner has full
//access to type; and all other code has readonly access.
//
//this code relies on extended friend semantics from C++0x to work, as it
//declares a friend class via a template paramter. it also exploits a bug in
//G++ 4.x to work even in C++98 mode.
//
//if compiling elsewhere, simply remove the friend class and private semantics
//property can be used either of two ways:
//struct foo {
// property<foo>::readonly<bool> x;
// property<foo>::readwrite<int> y;
//};
//-or-
//struct foo : property<foo> {
// readonly<bool> x;
// readwrite<int> y;
//};
//return types are const T& (byref) instead fo T (byval) to avoid major speed
//penalties for objects with expensive copy constructors
//operator-> provides access to underlying object type:
//readonly<Object> foo;
//foo->bar();
//... will call Object::bar();
//operator='s reference is constant so as to avoid leaking a reference handle
//that could bypass access restrictions
//both constant and non-constant operators are provided, though it may be
//necessary to cast first, for instance:
//struct foo : property<foo> { readonly<int> bar; } object;
//int main() { int value = const_cast<const foo&>(object); }
//writeonly is useful for objects that have non-const reads, but const writes.
//however, to avoid leaking handles, the interface is very restricted. the only
//way to write is via operator=, which requires conversion via eg copy
//constructor. example:
//struct foo {
// foo(bool value) { ... }
//};
//writeonly<foo> bar;
//bar = true;
namespace nall {
class property {
public:
template<typename T> class property_t;
template<typename C> struct property {
template<typename T> struct traits { typedef T type; };
protected:
template<typename T> T& get(property_t<T>&);
template<typename T> property_t<T>& set(property_t<T>&, const T);
public:
template<typename T>
class property_t {
public:
template<typename T> struct readonly {
const T* operator->() const { return &value; }
const T& operator()() const { return value; }
property_t() : value() {}
property_t(const T value_) : value(value_) {}
protected:
T value;
operator const T&() const { return value; }
private:
T* operator->() { return &value; }
operator T&() { return value; }
property_t& operator=(const T newValue) { value = newValue; return *this; }
friend T& property::get<T>(property_t<T>&);
friend property_t<T>& property::set<T>(property_t<T>&, const T);
const T& operator=(const T& value_) { return value = value_; }
T value;
friend class traits<C>::type;
};
template<typename T> struct writeonly {
void operator=(const T& value_) { value = value_; }
private:
const T* operator->() const { return &value; }
const T& operator()() const { return value; }
operator const T&() const { return value; }
T* operator->() { return &value; }
operator T&() { return value; }
T value;
friend class traits<C>::type;
};
template<typename T> struct readwrite {
const T* operator->() const { return &value; }
const T& operator()() const { return value; }
operator const T&() const { return value; }
T* operator->() { return &value; }
operator T&() { return value; }
const T& operator=(const T& value_) { return value = value_; }
T value;
};
};
template<typename T>
T& property::get(property::property_t<T> &p) {
return p.operator T&();
}
template<typename T>
property::property_t<T>& property::set(property::property_t<T> &p, const T value) {
return p.operator=(value);
}
}
#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

@@ -1,6 +1,7 @@
#ifndef NALL_STRING_BASE_HPP
#define NALL_STRING_BASE_HPP
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -48,6 +49,8 @@ namespace nall {
class string {
public:
static string printf(const char*, ...);
inline void reserve(size_t);
inline unsigned length() const;
@@ -80,6 +83,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

@@ -3,6 +3,15 @@
namespace nall {
inline string string::printf(const char *fmt, ...) {
static char text[4096];
va_list args;
va_start(args, fmt);
vsprintf(text, fmt, args);
va_end(args);
return text;
}
void string::reserve(size_t size_) {
if(size_ > size) {
size = size_;

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;
@@ -38,6 +43,18 @@ namespace nall {
}
return result;
}
// "foo/bar.c" -> "c"
inline string extension(char const *name) {
for(signed i = strlen(name); i >= 0; i--) {
if(name[i] == '.') {
name += i + 1;
break;
}
}
string result = name;
return result;
}
}
#endif

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

@@ -1,110 +1,170 @@
/*
audio.pulseaudio (2008-10-31)
author: byuu
*/
//audio.pulseaudio (2010-01-05)
//author: RedDwarf
#include <pulse/simple.h>
#include <pulse/error.h>
#include <pulse/pulseaudio.h>
namespace ruby {
class pAudioPulseAudio {
public:
struct {
pa_simple *handle;
pa_mainloop *mainloop;
pa_context *context;
pa_stream *stream;
pa_sample_spec spec;
pa_buffer_attr buffer_attr;
bool first;
} device;
struct {
uint32_t *data;
size_t size;
unsigned offset;
} buffer;
struct {
bool synchronize;
unsigned frequency;
unsigned latency;
} settings;
bool cap(const string& name) {
if(name == Audio::Synchronize) return true;
if(name == Audio::Frequency) return true;
return false;
if(name == Audio::Latency) return true;
}
any get(const string& name) {
if(name == Audio::Synchronize) return settings.synchronize;
if(name == Audio::Frequency) return settings.frequency;
return false;
if(name == Audio::Latency) return settings.latency;
}
bool set(const string& name, const any& value) {
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.handle) init();
if(name == Audio::Synchronize) {
settings.synchronize = any_cast<bool>(value);
return true;
}
return false;
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.stream) {
pa_operation_unref(pa_stream_update_sample_rate(device.stream, settings.frequency, NULL, NULL));
}
return true;
}
if(name == Audio::Latency) {
settings.latency = any_cast<unsigned>(value);
if(device.stream) {
device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec);
pa_stream_set_buffer_attr(device.stream, &device.buffer_attr, NULL, NULL);
}
return true;
}
}
void sample(uint16_t left, uint16_t right) {
if(!device.handle) return;
pa_stream_begin_write(device.stream, (void**)&buffer.data, &buffer.size);
buffer.data[buffer.offset++] = left + (right << 16);
if(buffer.offset >= 64) {
int error;
pa_simple_write(device.handle, (const void*)buffer.data, buffer.offset * sizeof(uint32_t), &error);
buffer.offset = 0;
if((buffer.offset + 1) * pa_frame_size(&device.spec) <= buffer.size) return;
while(true) {
if(device.first) {
device.first = false;
pa_mainloop_iterate(device.mainloop, 0, NULL);
} else {
pa_mainloop_iterate(device.mainloop, 1, NULL);
}
unsigned length = pa_stream_writable_size(device.stream);
if(length >= buffer.offset * pa_frame_size(&device.spec)) break;
if(settings.synchronize == false) {
buffer.offset = 0;
return;
}
}
pa_stream_write(device.stream, (const void*)buffer.data, buffer.offset * pa_frame_size(&device.spec), NULL, 0LL, PA_SEEK_RELATIVE);
buffer.data = 0;
buffer.offset = 0;
}
void clear() {
}
bool init() {
term();
device.mainloop = pa_mainloop_new();
device.spec.format = PA_SAMPLE_S16LE;
device.context = pa_context_new(pa_mainloop_get_api(device.mainloop), "ruby::pulseaudio");
pa_context_connect(device.context, NULL, PA_CONTEXT_NOFLAGS, NULL);
pa_context_state_t cstate;
do {
pa_mainloop_iterate(device.mainloop, 1, NULL);
cstate = pa_context_get_state(device.context);
if(!PA_CONTEXT_IS_GOOD(cstate)) return false;
} while(cstate != PA_CONTEXT_READY);
device.spec.format = PA_SAMPLE_S16LE;
device.spec.channels = 2;
device.spec.rate = settings.frequency;
device.spec.rate = settings.frequency;
device.stream = pa_stream_new(device.context, "audio", &device.spec, NULL);
int error = 0;
device.handle = pa_simple_new(
0, //default server
"ruby::pulseaudio", //application name
PA_STREAM_PLAYBACK, //direction
0, //default device
"audio", //stream description
&device.spec, //sample format
0, //default channel map
0, //default buffering attributes
&error //error code
);
if(!device.handle) {
fprintf(stderr, "ruby::pulseaudio failed to initialize - %s\n", pa_strerror(error));
return false;
}
device.buffer_attr.maxlength = -1;
device.buffer_attr.tlength = pa_usec_to_bytes(settings.latency * PA_USEC_PER_MSEC, &device.spec);
device.buffer_attr.prebuf = -1;
device.buffer_attr.minreq = -1;
device.buffer_attr.fragsize = -1;
buffer.data = new uint32_t[64];
pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_VARIABLE_RATE);
pa_stream_connect_playback(device.stream, NULL, &device.buffer_attr, flags, NULL, NULL);
pa_stream_state_t sstate;
do {
pa_mainloop_iterate(device.mainloop, 1, NULL);
sstate = pa_stream_get_state(device.stream);
if(!PA_STREAM_IS_GOOD(sstate)) return false;
} while(sstate != PA_STREAM_READY);
buffer.size = 960;
buffer.offset = 0;
device.first = true;
return true;
}
void term() {
if(device.handle) {
int error;
pa_simple_flush(device.handle, &error);
pa_simple_free(device.handle);
device.handle = 0;
if(buffer.data) {
pa_stream_cancel_write(device.stream);
buffer.data = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
if(device.stream) {
pa_stream_disconnect(device.stream);
pa_stream_unref(device.stream);
device.stream = 0;
}
if(device.context) {
pa_context_disconnect(device.context);
pa_context_unref(device.context);
device.context = 0;
}
if(device.mainloop) {
pa_mainloop_free(device.mainloop);
device.mainloop = 0;
}
}
pAudioPulseAudio() {
device.handle = 0;
device.mainloop = 0;
device.context = 0;
device.stream = 0;
buffer.data = 0;
settings.synchronize = false;
settings.frequency = 22050;
settings.latency = 60;
}
~pAudioPulseAudio() {
@@ -114,4 +174,4 @@ public:
DeclareAudio(PulseAudio)
};
}

View File

@@ -0,0 +1,115 @@
//audio.pulseaudiosimple (2010-01-05)
//author: byuu
#include <pulse/simple.h>
#include <pulse/error.h>
namespace ruby {
class pAudioPulseAudioSimple {
public:
struct {
pa_simple *handle;
pa_sample_spec spec;
} device;
struct {
uint32_t *data;
unsigned offset;
} buffer;
struct {
unsigned frequency;
} settings;
bool cap(const string& name) {
if(name == Audio::Frequency) return true;
return false;
}
any get(const string& name) {
if(name == Audio::Frequency) return settings.frequency;
return false;
}
bool set(const string& name, const any& value) {
if(name == Audio::Frequency) {
settings.frequency = any_cast<unsigned>(value);
if(device.handle) init();
return true;
}
return false;
}
void sample(uint16_t left, uint16_t right) {
if(!device.handle) return;
buffer.data[buffer.offset++] = left + (right << 16);
if(buffer.offset >= 64) {
int error;
pa_simple_write(device.handle, (const void*)buffer.data, buffer.offset * sizeof(uint32_t), &error);
buffer.offset = 0;
}
}
void clear() {
}
bool init() {
term();
device.spec.format = PA_SAMPLE_S16LE;
device.spec.channels = 2;
device.spec.rate = settings.frequency;
int error = 0;
device.handle = pa_simple_new(
0, //default server
"ruby::pulseaudiosimple", //application name
PA_STREAM_PLAYBACK, //direction
0, //default device
"audio", //stream description
&device.spec, //sample format
0, //default channel map
0, //default buffering attributes
&error //error code
);
if(!device.handle) {
fprintf(stderr, "ruby::pulseaudiosimple failed to initialize - %s\n", pa_strerror(error));
return false;
}
buffer.data = new uint32_t[64];
buffer.offset = 0;
return true;
}
void term() {
if(device.handle) {
int error;
pa_simple_flush(device.handle, &error);
pa_simple_free(device.handle);
device.handle = 0;
}
if(buffer.data) {
delete[] buffer.data;
buffer.data = 0;
}
}
pAudioPulseAudioSimple() {
device.handle = 0;
buffer.data = 0;
settings.frequency = 22050;
}
~pAudioPulseAudioSimple() {
term();
}
};
DeclareAudio(PulseAudioSimple)
};

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();
@@ -188,6 +190,10 @@ void AudioInterface::driver(const char *driver) {
else if(!strcmp(driver, "PulseAudio")) p = new AudioPulseAudio();
#endif
#ifdef AUDIO_PULSEAUDIOSIMPLE
else if(!strcmp(driver, "PulseAudioSimple")) p = new AudioPulseAudioSimple();
#endif
else p = new Audio();
}
@@ -201,6 +207,8 @@ const char* AudioInterface::default_driver() {
return "OpenAL";
#elif defined(AUDIO_PULSEAUDIO)
return "PulseAudio";
#elif defined(AUDIO_PULSEAUDIOSIMPLE)
return "PulseAudioSimple";
#elif defined(AUDIO_AO)
return "libao";
#elif defined(AUDIO_OSS)
@@ -238,6 +246,10 @@ const char* AudioInterface::driver_list() {
"PulseAudio;"
#endif
#if defined(AUDIO_PULSEAUDIOSIMPLE)
"PulseAudioSimple;"
#endif
#if defined(AUDIO_AO)
"libao;"
#endif

View File

@@ -128,6 +128,10 @@
#include <ruby/audio/pulseaudio.cpp>
#endif
#ifdef AUDIO_PULSEAUDIOSIMPLE
#include <ruby/audio/pulseaudiosimple.cpp>
#endif
/* Input */
#define DeclareInput(Name) \

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: 2010-01-05
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,12 @@ public:
OpenGL::init();
settings.width = 256;
settings.height = 256;
//vertical synchronization
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
if(!glSwapInterval) glSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
if( glSwapInterval) glSwapInterval(settings.synchronize);
return true;
}
@@ -197,7 +214,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

@@ -110,7 +110,7 @@ public:
display = XOpenDisplay(0);
char env[512];
sprintf(env, "SDL_WINDOWID=%ld", settings.handle);
sprintf(env, "SDL_WINDOWID=%ld", (long int)settings.handle);
putenv(env);
SDL_InitSubSystem(SDL_INIT_VIDEO);

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