Compare commits

..

6 Commits
v052 ... v058

Author SHA1 Message Date
byuu
6ec765f2c4 Update to bsnes v058 release.
We've tested the latest release on at least a dozen computers now, all seems to be in order for a release.
Changelog:
    - added 21fx support (more on this later)
    - added movie recording and playback support
    - added rewind support (enable under Settings->Configuration->Advanced, use backspace key to rewind)
    - added speedup (fast forward) and slowdown key bindings
    - audio no longer stutters on Windows when moving or resizing the main window
    - co-processors can now specify their own clock rates instead of sharing the S-CPU clock rate
    - Super Game Boy 2 now runs at the correct hardware speed, and not 2.4% faster like the Super Game Boy 1 does
    - added Vsync support to the Windows OpenGL driver (Intel graphics drivers do not support this option, because their engineers are lazy)
    - OpenGL driver no longer re-initializes when changing video synchronization, helps pixel shaders
    - refactored user interface compilation; now split into several object files, auto-generated MOC files placed under src/obj/
    - worked around a bug in the PulseAudio sound server that was causing the ALSA output driver to lock up [BearOso]
    - rewrote and simplified the save state manager, it is no longer a part of the core
    - S-DD1 and SPC7110 can now access up to 256MB via their MMCs
    - re-added background and OAM layer toggling under the tools dialog
    - added config file options to adjust emulation speed levels (config.system.speed*)
    - added snesreader, snesfilter and supergameboy support to the OS X port
    - added a really neat pixel shader that can perform point scaling to non-even multiples, eg it looks great even with aspect correction [Fes]
    - upgraded to Qt 4.6.0 official
Debugger changelog:
    - added memory export and import to the memory editor
    - added bus usage analyzer: logs opcodes, memory reads, memory writes and M/X states to usage.bin file
    - added disassembler that can trace both forward and backward from the current execution address
    - extended read/write breakpoints to the S-SMP
    - re-added trace masking option
Errata: there is one known bug in Qt 4.6.0 that affects the Windows port: menus attached to buttons show up as invisible on Windows Vista and above. I only use this on the file load dialog options button, and only to toggle the information pane on and off. Given that this is less severe than the bugs in the beta versions, I've upgraded anyway. I'll submit a bug report to the Qt team for this shortly. Also, my sincerest thanks to Bradley Hughes from the Qt development team for quickly fixing this show-stopper bug that greatly affected performance in bsnes v056.
2009-12-09 13:34:03 +00:00
byuu
54c7b4692d Update to bsnes v057 release.
I'm really sorry about this, but a major issue snuck into v056. It was caused by a bug in the newly released Qt 4.6.0 RC1. Whenever one moved the mouse cursor over the main window in the Windows port, the frame rate was immediately cut in half, which effectively ruined Mouse, Super Scope and Justifier support. As for how this could happen, well ... I'm ... really at a loss for words about this.
This release does not change the source code at all except to increment the version number, and it is built against Qt 4.6.0 beta 1 instead of 4.6.0 release candidate 1 as v055 was.
I will file an official bug complaint and post a link to it here during next week. Again, my apologies for any inconvenience. I incorrectly assumed it would be safe to update to RC1, and didn't spot the bug in time.
2009-11-23 13:24:03 +00:00
byuu
66067f0015 Update to bsnes v056 release.
This release adds a lot of new user interface features, and polishes Super Game Boy support.
Note that many pixel shaders need to be coded specifically for bsnes, eg ones designed for Pete's OpenGL2 plugin will not work. I will maintain a pixelshaders archive on the bsnes download page with a collection of working shaders. Right now, there are three: HDR TV, Scale2x and HQ2x; written by guest(r) and Pete, and ported by myself.
Changelog:
    - lowered Game Boy audio volume so that it matches SNES audio volume
    - fixed Super Game Boy multi-player support
    - fixed Super Game Boy swapped player bug
    - compressed Game Boy cartridges can now be loaded
    - added save state support for Super Game Boy games
    - blocked illegal Super Game Boy packets, fixes Zelda DX, Akumajou Dracula, etc palette issues
    - main window once again shrinks on size changes
    - joypads can now control the file loading window (support is very rudimentary)
    - cleaned up video and audio sliders, increased audio input frequency range for 59hz monitors
    - rewrote all of the input capture system from scratch
    - added dozens of additional GUI hotkey bindings to resize the main window, control synchronization, control speed, etc
    - it is now possible to map keyboard modifiers (shift, control, alt, super) to any input or hotkey; eg alt+enter = fullscreen
    - merged all input capture windows into the main settings panel
    - added turbo button support; hold down turbo buttons to send a 30hz input pulse
    - added asciiPad controller emulation; contains off/turbo/auto fire toggles and slow-motion mode
    - asciiPad support allows for quick switching between keyboard and gamepad input
    - merged scanline filter into the user interface (under Video Settings) to allow it to work on all filters; including the NTSC filter
    - killed off an evil QString <> string intermediary class called utf8; string class can convert to and from QString directly now
    - added fast BS-X, Sufami Turbo and Game Boy cartridge loading: use the filter list under "Load Cartridge" to bypass the BIOS selection screen
    - added pixel shader support to the OpenGL driver on Windows and Linux; note that it only really works well on Linux at the moment
    - added proper Vsync support to the OpenGL driver on Windows and Linux using GL extensions; again this really only works well on Linux
    - added unique path memory for shaders, folders, cartridges, BS-X, Sufami Turbo and Game Boy images
    - upgraded to Qt 4.6.0 release candidate 1; fixes an issue with the first checkbox in lists not updating when clicked
2009-11-22 14:48:58 +00:00
byuu
4c66de6f27 Update to bsnes v055 release.
Happy Halloween, this release adds full Super Game Boy support ... but is it a trick, or a treat? ;) ::cough::, lameness aside ...
The Game Boy emulation core is courtesy of gambatte, and excellent, accuracy-focused, open source, and lightning fast Game Boy Color emulator. Now I know what you're thinking, using a Game Boy Color emulator with the Super Game Boy? The truth is, gambatte was just such an amazingly perfect fit that nothing else compared. I fully believe that even as a CGB emulator, gambatte will do a better job than any pure DMG emulator could.
The emulation of the ICD2 chip (aka the Super Game Boy) was fully reverse engineered by myself. Eventually I'll get an updated document put up explaining how it works.
The next question might be, "why emulate the Super Game Boy when existing Game Boy emulators do?"; well, they can only simulate part of the SGB. Features such as custom SNES sound effects, hand-drawn borders, multi-tap support and custom SNES code execution can only be accomplished by a true SNES emulator. Space Invaders is perhaps the most impressive demonstration, as it contains an entire SNES game embedded inside the Game Boy cartridge.
bsnes' SGB emulation supports virtually every command, full sound mixing from both the SNES and Game Boy sides, both BIOS revisions, etc. The only thing that is not fully functional yet is the multi-player support, but it should be in due time. Save state support is also planned for a later date.
Changelog:
    - added Super Game Boy emulation (thanks to gambatte for the Game Boy core)
    - extended hybrid scanline/cycle PPU renderer to support Mode7 register caching; fixes scanline flickering on NHL '94 title screen
    - all windows (other than the main window) can be closed with the escape key now
    - file dialog path selection now accepts typed paths; can be used to access hidden directories and network shares
    - file dialog's game information panel can now be disabled
    - fixed a crashing issue when the file dialog was given an invalid path
    - fixed screenshot capture save location
    - added screenshot capture option to tools menu
    - state manager now auto-closes when loading a state; it can be reopened quickly with F3
    - fixed GZip archive loading
    - fixed NTSC off-by-one filter bug on hires screens
    - extended Scale2x, LQ2x and HQ2x to properly filter hires screens
    - added Pixellate2x filter
2009-11-01 14:30:51 +00:00
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
byuu
8135dfdac9 Update to bsnes v053 release.
This release greatly polishes the user interface, adds a new cheat code search utility, adds the snesfilter library, and adds Qt-based GUI support to both snesfilter and snesreader. snesfilter gains 2xSaI, Super 2xSaI and Super Eagle support, plus full configuration for both the NTSC and scanline filters; and snesreader gains support support for multi-file ROM archives (eg GoodMerge sets.)
Statically linking Qt to bsnes, snesfilter and snesreader would be too prohibitive size-wise (~10MB or so.) I have to link dynamically so that all three can share the same Qt runtime, which gets all of bsnes and its modules to ~1MB (including the debugger build); and Qt itself to about ~2.5MB.
However, there is some bad news. There's a serious bug in MinGW 4.4+, where it is not generating profile-guided input files (*.gcno files.) There is also a serious bug in Qt 4.5.2/Windows when using dynamic linking: the library is hanging indefinitely, forcing me to manually terminate the process upon exit. This prevents the creation of profile-guided output files (*.gcda files.) It would be tough enough to work around one, but facing both of these issues at once is too much.
I'm afraid I have no choice but to disable profile-guided optimizations until these issues can be addressed. I did not know about these bugs until trying to build the official v053 release, so it's too late to revert to an all-in-one binary now. And I'm simply not willing to stop releasing new builds because of bugs in third-party software. As soon as I can work around this, I'll post a new optimized binary. In the mean time, despite the fact that this release is actually more optimized, please understand that the Windows binary will run approximately ~10% slower than previous releases. I recommend keeping v052 for now if you need the performance. Linux and OS X users are unaffected.
Changelog:
    - save RAM is initialized to 0xff again to work around Ken Griffey Jr Baseball issue
    - libco adds assembly-optimized targets for Win64 and PPC-ELF [the latter courtesy of Kernigh]
    - libco/x86 and libco/amd64 use pre-assembled blocks now, obviates need for custom compilation flags
    - added a new cheat code search utility to the tools menu
    - separated filters from main bsnes binary to libsnesfilter / snesfilter.dll
    - added 2xSaI, Super 2xSaI and Super Eagle filters [kode54]
    - added full configuration settings for NTSC and scanline filters (12+ new options)
    - further optimized HQ2x filter [blargg]
    - added Vsync support to the Mac OS X OpenGL driver
    - added folder creation button to custom file load dialog
    - fixed a few oddities with loading of "game folders" (see older news for an explanation on what this is)
    - updated to blargg's file_extractor v1.0.0
    - added full support for multi-file archives (eg GoodMerge sets)
    - split multi-cart loading again (BS-X, Sufami Turbo, etc) as required for multi-file support
    - cleaned up handling of file placement detection for save files (.srm, .cht, etc)
    - file load dialog now remembers your previous folder path across runs even without a custom games folder assigned
    - windows now save their exact positioning and size across runs, they no longer forcibly center
    - menus now have radio button and check box icons where appropriate
    - debugger's hex editor now has a working scrollbar widget
    - added resize splitter to settings and tools windows
    - worked around Qt style sheet bug where subclassed widgets were not properly applying style properties
2009-10-18 17:33:04 +00:00
233 changed files with 9073 additions and 7390 deletions

View File

@@ -37,8 +37,8 @@ else ifeq ($(platform),osx)
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win)
link += -mwindows
# link += -mconsole
link += -mwindows -mthreads
# link += -mconsole -mthreads
link += -s -luuid -lkernel32 -luser32 -lgdi32 -lshell32
# statically link Qt for Windows build
link += -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
@@ -76,11 +76,12 @@ link += $(call ifhas,input.rawinput,$(ruby),-ldinput8 -ldxguid)
### objects ###
###############
objects := libco ruby libfilter
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 ###
@@ -111,8 +112,6 @@ rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
obj/ruby.o: lib/ruby/ruby.cpp $(call rwildcard,lib/ruby/*)
$(call compile,$(rubydef) $(rubyflags))
obj/libco.o: lib/libco/libco.c lib/libco/*
$(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@
obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/*
#################
### utilities ###
@@ -168,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.052";
static const char bsnesVersion[] = "0.058";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSaveStateVersion = 3;
static const unsigned bsnesSerializerVersion = 4;
//S-DSP can be encapsulated into a state machine using #define magic
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
@@ -23,7 +23,6 @@ static const unsigned bsnesSaveStateVersion = 3;
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/new.hpp>
#include <nall/platform.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/property.hpp>

View File

@@ -1,17 +1,19 @@
#include <../base.hpp>
#include <nall/crc32.hpp>
#include <nall/sha256.hpp>
#define CARTRIDGE_CPP
namespace SNES {
#include "header.cpp"
#include "gameboyheader.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bsxflash, bsxram, bsxpram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
MappedRAM gbrom, gbram;
MappedRAM gbrom, gbram, gbrtc;
};
Cartridge cartridge;
@@ -24,25 +26,31 @@ void Cartridge::load(Mode cartridge_mode) {
set(mode, cartridge_mode);
if(cartinfo.ram_size > 0) {
memory::cartram.map(new(zeromemory) uint8_t[cartinfo.ram_size], cartinfo.ram_size);
memory::cartram.map(allocate<uint8_t>(cartinfo.ram_size, 0xff), cartinfo.ram_size);
}
if(cartinfo.srtc || cartinfo.spc7110rtc) {
memory::cartrtc.map(new(zeromemory) uint8_t[20], 20);
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
}
if(mode() == ModeBsx) {
memory::bsxram.map (new(zeromemory) uint8_t[ 32 * 1024], 32 * 1024);
memory::bsxpram.map(new(zeromemory) uint8_t[512 * 1024], 512 * 1024);
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(memory::stArom.data()) memory::stAram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
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(new(zeromemory) uint8_t[64 * 1024], 64 * 1024);
if(memory::gbrom.data()) {
unsigned ram_size = gameboy_ram_size();
unsigned rtc_size = gameboy_rtc_size();
if(ram_size) memory::gbram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
if(rtc_size) memory::gbrtc.map(allocate<uint8_t>(rtc_size, 0x00), rtc_size);
}
}
memory::cartrom.write_protect(true);
@@ -57,6 +65,7 @@ void Cartridge::load(Mode cartridge_mode) {
memory::stBram.write_protect(false);
memory::gbrom.write_protect(true);
memory::gbram.write_protect(false);
memory::gbrtc.write_protect(false);
unsigned checksum = ~0;
for(unsigned n = 0; n < memory::cartrom.size(); n++) checksum = crc32_adjust(checksum, memory::cartrom[n]);
@@ -70,6 +79,21 @@ void Cartridge::load(Mode cartridge_mode) {
for(unsigned n = 0; n < memory::gbrom.size(); n++) checksum = crc32_adjust(checksum, memory::gbrom[n]);
set(crc32, ~checksum);
#if 0
fprintf(stdout, "crc32 = %.8x\n", crc32());
sha256_ctx sha;
uint8_t shahash[32];
sha256_init(&sha);
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
sha256_final(&sha);
sha256_hash(&sha, shahash);
fprintf(stdout, "sha256 = ");
for(unsigned i = 0; i < 32; i++) fprintf(stdout, "%.2x", shahash[i]);
fprintf(stdout, "\n");
#endif
bus.load_cart();
system.serialize_init();
set(loaded, true);
@@ -88,6 +112,7 @@ void Cartridge::unload() {
memory::stBram.reset();
memory::gbrom.reset();
memory::gbram.reset();
memory::gbrtc.reset();
if(loaded() == false) return;
bus.unload_cart();
@@ -100,6 +125,8 @@ Cartridge::Type Cartridge::detect_image_type(uint8_t *data, unsigned size) const
return info.type;
}
bool Cartridge::has_21fx() const { return s21fx.exists(); }
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
@@ -128,6 +155,10 @@ void Cartridge::serialize(serializer &s) {
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
s.array(memory::gbram.data(), memory::gbram.size());
}
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
s.array(memory::gbrtc.data(), memory::gbrtc.size());
}
}
Cartridge::Cartridge() {
@@ -197,5 +228,4 @@ Cartridge::cartinfo_t::cartinfo_t() {
reset();
}
};
}

View File

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

View File

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

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

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 685 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

104
src/lib/libco/amd64.c Normal file
View File

@@ -0,0 +1,104 @@
/*
libco.amd64 (2009-10-12)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (*co_swap)(cothread_t, cothread_t) = 0;
#ifdef _WIN32
//ABI: Win64
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x22, 0x48, 0x8B, 0x21, 0x58, 0x48, 0x89, 0x6A, 0x08, 0x48, 0x89, 0x72, 0x10, 0x48,
0x89, 0x7A, 0x18, 0x48, 0x89, 0x5A, 0x20, 0x4C, 0x89, 0x62, 0x28, 0x4C, 0x89, 0x6A, 0x30, 0x4C,
0x89, 0x72, 0x38, 0x4C, 0x89, 0x7A, 0x40, 0x48, 0x81, 0xC2, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE2, 0xF0, 0x0F, 0x29, 0x32, 0x0F, 0x29, 0x7A, 0x10, 0x44, 0x0F, 0x29, 0x42, 0x20, 0x44, 0x0F,
0x29, 0x4A, 0x30, 0x44, 0x0F, 0x29, 0x52, 0x40, 0x44, 0x0F, 0x29, 0x5A, 0x50, 0x44, 0x0F, 0x29,
0x62, 0x60, 0x44, 0x0F, 0x29, 0x6A, 0x70, 0x44, 0x0F, 0x29, 0xB2, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xBA, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x69, 0x08, 0x48, 0x8B, 0x71, 0x10, 0x48,
0x8B, 0x79, 0x18, 0x48, 0x8B, 0x59, 0x20, 0x4C, 0x8B, 0x61, 0x28, 0x4C, 0x8B, 0x69, 0x30, 0x4C,
0x8B, 0x71, 0x38, 0x4C, 0x8B, 0x79, 0x40, 0x48, 0x81, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE1, 0xF0, 0x0F, 0x29, 0x31, 0x0F, 0x29, 0x79, 0x10, 0x44, 0x0F, 0x29, 0x41, 0x20, 0x44, 0x0F,
0x29, 0x49, 0x30, 0x44, 0x0F, 0x29, 0x51, 0x40, 0x44, 0x0F, 0x29, 0x59, 0x50, 0x44, 0x0F, 0x29,
0x61, 0x60, 0x44, 0x0F, 0x29, 0x69, 0x70, 0x44, 0x0F, 0x29, 0xB1, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xB9, 0x90, 0x00, 0x00, 0x00, 0xFF, 0xE0,
};
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
//ABI: SystemV
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x26, 0x48, 0x8B, 0x27, 0x58, 0x48, 0x89, 0x6E, 0x08, 0x48, 0x89, 0x5E, 0x10, 0x4C,
0x89, 0x66, 0x18, 0x4C, 0x89, 0x6E, 0x20, 0x4C, 0x89, 0x76, 0x28, 0x4C, 0x89, 0x7E, 0x30, 0x48,
0x8B, 0x6F, 0x08, 0x48, 0x8B, 0x5F, 0x10, 0x4C, 0x8B, 0x67, 0x18, 0x4C, 0x8B, 0x6F, 0x20, 0x4C,
0x8B, 0x77, 0x28, 0x4C, 0x8B, 0x7F, 0x30, 0xFF, 0xE0,
};
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long long addr = (unsigned long long)co_swap_function;
unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
if(!co_swap) {
co_init();
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 512; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)malloc(size)) {
long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
*--p = (long long)crash; /* crash if entrypoint returns */
*--p = (long long)entrypoint; /* start of function */
*(long long*)handle = (long long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t handle) {
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#ifdef __cplusplus
}
#endif

View File

@@ -6,15 +6,17 @@
#if defined(__GNUC__) && defined(__i386__)
#include "x86.c"
#elif defined(__GNUC__) && defined(__amd64__) && !defined(__MINGW64__)
#include "x86-64.c"
#elif defined(__MINGW64__)
#include "fiber.c"
#elif defined(__GNUC__) && defined(__amd64__)
#include "amd64.c"
#elif defined(__GNUC__) && defined(__powerpc__) && defined(__ELF__)
#include "ppc-elf.c"
#elif defined(__GNUC__)
#include "sjlj.c"
#elif defined(_MSC_VER) && defined(_M_IX86)
#include "x86.c"
#elif defined(_MSC_VER) && defined(_M_AMD64)
#include "amd64.c"
#elif defined(_MSC_VER)
#include "fiber.c"
#else
#error "libco: unsupported processor, compiler or operating system"

View File

@@ -1,6 +1,6 @@
/*
libco
version: 0.13 rc2 (2008-01-28)
version: 0.15 (2009-10-12)
license: public domain
*/

325
src/lib/libco/ppc-elf.c Normal file
View File

@@ -0,0 +1,325 @@
/*
* libco.ppc-elf
* author: Kernigh
* license: public domain
*
* PowerPC 32-bit ELF implementation of libco (for compile with GCC),
* ported from PowerPC Mac OS X implementation (ppc.s) by Vas Crabb.
* This ELF version works for OpenBSD, and might also work for FreeBSD,
* NetBSD and Linux.
*
* Note 1: This implementation does not handle the AltiVec/VMX
* registers, because the ELF ABI does not mention them,
* and my OpenBSD system is not using them.
*
* Note 2: If you want position-independent code, then you must
* define __PIC__. gcc -fpic or -fPIC defines __PIC__, but
* gcc -fpie or -fPIE might not. If you want to use -fpie
* or -fPIE, then you might need a manual definition:
* gcc -fpie -D__PIC__=1
* gcc -fPIE -D__PIC__=2
*
* The ELF ABI is "System V Application Binary Interface, PowerPC
* Processor Supplement", which you can get from
* <http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf>
* (PDF file, hosted by Linux Foundation).
*
* ELF and Mac OS X use similar conventions to allocate the registers,
* and to pass arguments and return values through registers. The main
* differences are that ELF has a slightly different stack format, that
* symbols are different (and without an extra underscore at the start),
* and that the assembly syntax is different.
*
* A function may destroy the values of volatile registers, but must
* preserve the values of nonvolatile registers. So the co_switch()
* function only saves the nonvolatile registers.
*
* [nonvolatile registers in ELF]
* %r1, %r14..%r31
* %f14..%f31
* %cr2..%cr4 in cr
*
* [volatile registers in ELF]
* %r0, %r3..%r10
* %f0..%f13
* %cr0, %cr1, %cr5..%cr7 in cr
* ctr, lr, xer
*
* lr (link register) is volatile, but it contains the return address,
* so co_switch must save lr.
*
* %r13 is the small data pointer. This is constant across threads, so
* co_switch() does not touch %r13.
*
* %r2 is a reserved register, so co_switch() does not touch %r2. Some
* systems might borrow an idea from the PowerPC Embedded ABI, and might
* use %r2 as a small read-only data pointer, which is constant across
* threads.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef void * cothread_t;
/*
* co_active_context is either in a global offset table (if we are
* compiling -fPIC or -fPIE) or has an absolute position.
*/
static void *co_main_stack_pointer;
static cothread_t co_active_context = &co_main_stack_pointer;
extern cothread_t co_active() {
return co_active_context;
}
/*
* Embedded assembly.
*
* We are not using the percent-sign substitution feature,
* so we must write "%r1", not "%%r1".
*
* We always write 'bl malloc@plt', not 'bl malloc'. The '@plt'
* is necessary in position-indepent code and seems to have no
* significant effect in fixed-position code.
*
* We never use the 'lmw' or 'stmw' instructions. The ELF ABI
* mentions that these instructions "are usually slower than
* a sequence of other instructions that have the same effect."
* We instead use sequences of 'lwz' or 'stz' instructions.
*/
__asm__("\n"
"### embedded assembly \n"
".section \".text\" \n"
" .balign 4 \n"
" \n"
/*
* void co_switch(co_thread to %r3)
*
* Allocate our stack frame of 240 bytes:
* Old New Value
* 4(%r1) 244(%r1) return address, used by us
* 0(%r1) 240(%r1) frame pointer
* 232(%r1) %f31
* 224(%r1) %f30
* ...
* 96(%r1) %f14
* 92(%r1) %r31
* 88(%r1) %r30
* ...
* 24(%r1) %r14
* 20(%r1) condition register
* 8(%r1) padding of 12 bytes
* 4(%r1) return address, never used
* 0(%r1) frame pointer
*
* Save our registers in our stack frame.
* Save our stack pointer in 0(%r4).
* Switch to the stack of the other thread.
* Restore registers and return.
*/
" .globl co_switch \n"
" .type co_switch, @function \n"
"co_switch: \n"
" mflr %r0 # %r0 = return address \n"
" mfcr %r9 # %r9 = condition register \n"
" stwu %r1, -240(%r1) # allocate stack frame \n"
" \n"
" stw %r0, 244(%r1) # save return address \n"
" stfd %f31, 232(%r1) # save floating-point regs \n"
" stfd %f30, 224(%r1) \n"
" stfd %f29, 216(%r1) \n"
" stfd %f28, 208(%r1) \n"
" stfd %f27, 200(%r1) \n"
" stfd %f26, 192(%r1) \n"
" stfd %f25, 184(%r1) \n"
" stfd %f24, 176(%r1) \n"
" stfd %f23, 168(%r1) \n"
" stfd %f22, 160(%r1) \n"
" stfd %f21, 152(%r1) \n"
" stfd %f20, 144(%r1) \n"
" stfd %f19, 136(%r1) \n"
" stfd %f18, 128(%r1) \n"
" stfd %f17, 120(%r1) \n"
" stfd %f16, 112(%r1) \n"
" stfd %f16, 104(%r1) \n"
" stfd %f14, 96(%r1) \n"
" stw %r31, 92(%r1) # save general-purpose regs \n"
" stw %r30, 88(%r1) \n"
" stw %r29, 84(%r1) \n"
" stw %r28, 80(%r1) \n"
" stw %r27, 76(%r1) \n"
" stw %r26, 72(%r1) \n"
" stw %r25, 68(%r1) \n"
" stw %r24, 64(%r1) \n"
" stw %r23, 60(%r1) \n"
" stw %r22, 56(%r1) \n"
" stw %r21, 52(%r1) \n"
" stw %r20, 48(%r1) \n"
" stw %r19, 44(%r1) \n"
" stw %r18, 40(%r1) \n"
" stw %r17, 36(%r1) \n"
" stw %r16, 32(%r1) \n"
" stw %r15, 28(%r1) \n"
" stw %r14, 24(%r1) \n"
" stw %r9, 20(%r1) # save condition reg \n"
" \n"
" # save current context, set new context \n"
" # %r4 = co_active_context \n"
" # co_active_context = %r3 \n"
#if __PIC__ == 2
" # position-independent code, large model (-fPIC) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" addis %r7, %r8, co_active_context@got@ha \n"
" lwz %r6, co_active_context@got@l(%r7) \n"
" lwz %r4, 0(%r6) \n"
" stw %r3, 0(%r6) \n"
#elif __PIC__ == 1
" # position-independent code, small model (-fpic) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" lwz %r7, co_active_context@got(%r8) \n"
" lwz %r4, 0(%r7) \n"
" stw %r3, 0(%r7) \n"
#else
" # fixed-position code \n"
" lis %r8, co_active_context@ha \n"
" lwz %r4, co_active_context@l(%r8) \n"
" stw %r3, co_active_context@l(%r8) \n"
#endif
" \n"
" # save current stack pointer \n"
" stw %r1, 0(%r4) \n"
" # get new stack pointer \n"
" lwz %r1, 0(%r3) \n"
" \n"
" lwz %r0, 244(%r1) # get return address \n"
" lfd %f31, 232(%r1) # restore floating-point regs \n"
" lfd %f30, 224(%r1) \n"
" lfd %f29, 216(%r1) \n"
" lfd %f28, 208(%r1) \n"
" lfd %f27, 200(%r1) \n"
" lfd %f26, 192(%r1) \n"
" lfd %f25, 184(%r1) \n"
" lfd %f24, 176(%r1) \n"
" lfd %f23, 168(%r1) \n"
" lfd %f22, 160(%r1) \n"
" lfd %f21, 152(%r1) \n"
" lfd %f20, 144(%r1) \n"
" lfd %f19, 136(%r1) \n"
" lfd %f18, 128(%r1) \n"
" lfd %f17, 120(%r1) \n"
" lfd %f16, 112(%r1) \n"
" lfd %f16, 104(%r1) \n"
" lfd %f14, 96(%r1) \n"
" lwz %r31, 92(%r1) # restore general-purpose regs \n"
" lwz %r30, 88(%r1) \n"
" lwz %r29, 84(%r1) \n"
" lwz %r28, 80(%r1) \n"
" lwz %r27, 76(%r1) \n"
" lwz %r26, 72(%r1) \n"
" lwz %r25, 68(%r1) \n"
" lwz %r24, 64(%r1) \n"
" lwz %r23, 60(%r1) \n"
" lwz %r22, 56(%r1) \n"
" lwz %r21, 52(%r1) \n"
" lwz %r20, 48(%r1) \n"
" lwz %r19, 44(%r1) \n"
" lwz %r18, 40(%r1) \n"
" lwz %r17, 36(%r1) \n"
" lwz %r16, 32(%r1) \n"
" lwz %r15, 28(%r1) \n"
" lwz %r14, 24(%r1) \n"
" lwz %r9, 20(%r1) # get condition reg \n"
" \n"
" addi %r1, %r1, 240 # free stack frame \n"
" mtlr %r0 # restore return address \n"
" mtcr %r9 # restore condition register \n"
" blr # return \n"
" .size co_switch, . - co_switch \n"
" \n"
/*
* cothread_t %r3 co_create(unsigned int stack_size %r3,
* void (*coentry %r4)())
*
* Allocate a new stack, such that when you co_switch to that
* stack, then co_switch returns to coentry.
*/
" .globl co_create \n"
" .type co_create, @function \n"
"co_create: \n"
" mflr %r0 # %r0 = return address \n"
" stwu %r1, -16(%r1) # allocate my stack frame \n"
" stw %r0, 20(%r1) # save return address \n"
" stw %r31, 12(%r1) # save %r31 \n"
" stw %r30, 8(%r1) # save %r30 \n"
" \n"
" mr %r30, %r3 # %r30 = stack_size \n"
" mr %r31, %r4 # %r31 = coentry \n"
" \n"
" # Call malloc(stack_size %r3) to allocate stack; \n"
" # malloc() probably uses good alignment. \n"
" # \n"
" bl malloc@plt # returns %r3 = low end \n"
" cmpwi %r3, 0 # if returned NULL, \n"
" beq- 1f # then abort \n"
" \n"
" # we return %r3 = low end of stack \n"
" add %r4, %r3, %r30 # %r4 = high end of stack \n"
" \n"
" # uncomment if malloc() uses wrong alignment \n"
" #rlwinm %r4,%r4,0,0,27 # force 16-byte alignment \n"
" \n"
/*
* Allocate two stack frames:
* 16 bytes for stack frame with return address
* 240 bytes for co_switch stack frame
*
* Old New Value
* -8(%r4) 248(%r5) padding of 8 bytes
* -12(%r4) 244(%r5) return address = coentry
* -16(%r4) 240(%r5) frame pointer = NULL
* 232(%r5) %f31 = 0
* ...
* 20(%r5) condition register = 0
* 0(%r5) frame pointer
*/
" li %r9, (240-20)/4+1 \n"
" addi %r5, %r4, -16 # allocate first stack frame \n"
" li %r0, 0 \n"
" stwu %r5, -240(%r5) # allocate second stack frame \n"
" li %r8, 20 \n"
" mtctr %r9 # loop %r9 times \n"
"2: # loop to store zero to 20(%r5) through 240(%r5) \n"
" stwx %r0, %r5, %r8 \n"
" addi %r8, %r8, 4 # index += 4 \n"
" bdnz+ 2b # ctr -= 1, branch if nonzero \n"
" \n"
" stw %r31, 244(%r5) # return address = coentry \n"
" stw %r5, 0(%r3) # save stack pointer \n"
" \n"
" lwz %r0, 20(%r1) # get return address \n"
" lwz %r31, 12(%r1) # restore %r31 \n"
" lwz %r30, 8(%r1) # restore %r30 \n"
" mtlr %r0 # restore return address \n"
" addi %r1, %r1, 16 # free stack frame \n"
" blr # return \n"
" \n"
"1: b abort@plt # branch 1f to abort \n"
" .size co_create, . - co_create \n"
" \n"
/*
* void co_delete(cothread_t) => void free(void *)
*/
" .globl co_delete \n"
" .type co_delete, @function \n"
"co_delete: \n"
" b free@plt \n"
" \n"
);
#ifdef __cplusplus
}
#endif

View File

@@ -1,81 +0,0 @@
/*
libco.x86-64 (2008-01-28)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 8);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
*(long*)handle = (long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movq %%rsp,(%1) \n\t" /* save old stack pointer */
"movq (%0),%%rsp \n\t" /* load new stack pointer */
"addq $8,%%rsp \n\t" /* "pop" return address off stack */
"movq %%rbp, 8(%1) \n\t" /* backup non-volatile registers */
"movq %%rbx,16(%1) \n\t"
"movq %%r12,24(%1) \n\t"
"movq %%r13,32(%1) \n\t"
"movq %%r14,40(%1) \n\t"
"movq %%r15,48(%1) \n\t"
"movq 8(%0),%%rbp \n\t" /* restore non-volatile registers */
"movq 16(%0),%%rbx \n\t"
"movq 24(%0),%%r12 \n\t"
"movq 32(%0),%%r13 \n\t"
"movq 40(%0),%%r14 \n\t"
"movq 48(%0),%%r15 \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
libco.x86 (2008-01-28)
libco.x86 (2009-10-12)
author: byuu
license: public domain
*/
@@ -13,26 +13,63 @@
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
#if defined(_MSC_VER)
#define fastcall __fastcall
#elif defined(__GNUC__)
#define fastcall __attribute__((fastcall))
#else
#error "libco: please define fastcall macro"
#endif
static thread_local long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
//ABI: fastcall
static unsigned char co_swap_function[] = {
0x89, 0x22, 0x8B, 0x21, 0x58, 0x89, 0x6A, 0x04, 0x89, 0x72, 0x08, 0x89, 0x7A, 0x0C, 0x89, 0x5A,
0x10, 0x8B, 0x69, 0x04, 0x8B, 0x71, 0x08, 0x8B, 0x79, 0x0C, 0x8B, 0x59, 0x10, 0xFF, 0xE0,
};
#ifdef _WIN32
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long addr = (unsigned long)co_swap_function;
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 4);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
if(!co_swap) {
co_init();
co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 256; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
if(handle = (cothread_t)malloc(size)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
@@ -46,65 +83,11 @@ void co_delete(cothread_t handle) {
free(handle);
}
#if defined(__GNUC__)
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movl %%esp,(%1) \n\t" /* save old stack pointer */
"movl (%0),%%esp \n\t" /* load new stack pointer */
"addl $4,%%esp \n\t" /* "pop" return address off stack */
"movl %%ebp, 4(%1) \n\t" /* backup non-volatile registers */
"movl %%esi, 8(%1) \n\t"
"movl %%edi,12(%1) \n\t"
"movl %%ebx,16(%1) \n\t"
"movl 4(%0),%%ebp \n\t" /* restore non-volatile registers */
"movl 8(%0),%%esi \n\t"
"movl 12(%0),%%edi \n\t"
"movl 16(%0),%%ebx \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#elif defined(_MSC_VER)
__declspec(naked) __declspec(noinline)
static void __fastcall co_swap(register cothread_t to, register cothread_t from) {
/* ecx = to, edx = from */
__asm {
mov [edx],esp
mov esp,[ecx]
pop eax
mov [edx+ 4],ebp
mov [edx+ 8],esi
mov [edx+12],edi
mov [edx+16],ebx
mov ebp,[ecx+ 4]
mov esi,[ecx+ 8]
mov edi,[ecx+12]
mov ebx,[ecx+16]
jmp eax
}
}
void co_switch(cothread_t handle) {
register cothread_t co_prev_ = co_active_;
co_swap(co_active_ = handle, co_prev_);
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -1,138 +0,0 @@
Colortable colortable;
void Colortable::set_format(Format format_) { format = format_; }
void Colortable::set_contrast(signed contrast_) { contrast = contrast_; }
void Colortable::set_brightness(signed brightness_) { brightness = brightness_; }
void Colortable::set_gamma(signed gamma_) { gamma = gamma_; }
void Colortable::enable_gamma_ramp(bool value) { gamma_ramp = value; }
void Colortable::enable_sepia(bool value) { sepia = value; }
void Colortable::enable_grayscale(bool value) { grayscale = value; }
void Colortable::enable_invert(bool value) { invert = value; }
void Colortable::update() {
double kr = 0.2126, kb = 0.0722, kg = (1.0 - kr - kb); //luminance weights
for(unsigned i = 0; i < 32768; i++) {
unsigned color //bgr555->rgb888 conversion
= ((i & 0x001f) << 19) | ((i & 0x001c) << 14)
| ((i & 0x03e0) << 6) | ((i & 0x0380) << 1)
| ((i & 0x7c00) >> 7) | ((i & 0x7000) >> 12);
signed l;
signed r = (color >> 16) & 0xff;
signed g = (color >> 8) & 0xff;
signed b = (color ) & 0xff;
if(gamma_ramp == true) {
r = gamma_ramp_table[r >> 3];
g = gamma_ramp_table[g >> 3];
b = gamma_ramp_table[b >> 3];
}
if(contrast != 0) {
r = contrast_adjust(r);
g = contrast_adjust(g);
b = contrast_adjust(b);
}
if(brightness != 0) {
r = brightness_adjust(r);
g = brightness_adjust(g);
b = brightness_adjust(b);
}
if(gamma != 100) {
r = gamma_adjust(r);
g = gamma_adjust(g);
b = gamma_adjust(b);
}
if(sepia == true) {
l = (signed)((double)r * kr + (double)g * kg + (double)b * kb);
l = max(0, min(255, l));
r = (signed)((double)l * (1.0 + 0.300));
g = (signed)((double)l * (1.0 - 0.055));
b = (signed)((double)l * (1.0 - 0.225));
r = max(0, min(255, r));
g = max(0, min(255, g));
b = max(0, min(255, b));
}
if(grayscale == true) {
l = (signed)((double)r * kr + (double)g * kg + (double)b * kb);
l = max(0, min(255, l));
r = g = b = l;
}
if(invert == true) {
r ^= 0xff;
g ^= 0xff;
b ^= 0xff;
}
switch(format) {
case RGB555: {
r >>= 3;
g >>= 3;
b >>= 3;
table[i] = (r << 10) | (g << 5) | (b);
} break;
case RGB565: {
r >>= 3;
g >>= 2;
b >>= 3;
table[i] = (r << 11) | (g << 5) | (b);
} break;
case RGB888: {
table[i] = (r << 16) | (g << 8) | (b);
} break;
default: {
table[i] = ~0;
} break;
}
}
}
Colortable::Colortable() {
table = new uint32_t[32768];
contrast = 0;
brightness = 0;
gamma = 100;
gamma_ramp = false;
sepia = false;
grayscale = false;
invert = false;
}
Colortable::~Colortable() {
delete[] table;
}
const uint8_t Colortable::gamma_ramp_table[32] = {
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff,
};
uint8_t Colortable::contrast_adjust(uint8_t input) {
signed result = input - contrast + (2 * contrast * input + 127) / 255;
return max(0, min(255, result));
}
uint8_t Colortable::brightness_adjust(uint8_t input) {
signed result = input + brightness;
return max(0, min(255, result));
}
uint8_t Colortable::gamma_adjust(uint8_t input) {
signed result = (signed)(pow(((double)input / 255.0), (double)gamma / 100.0) * 255.0 + 0.5);
return max(0, min(255, result));
}

View File

@@ -1,44 +0,0 @@
class Colortable {
public:
enum Format {
RGB555,
RGB565,
RGB888,
};
const inline uint32_t operator[](uint16_t index) const { return table[index]; }
void set_format(Format);
void set_contrast(signed);
void set_brightness(signed);
void set_gamma(signed);
void enable_gamma_ramp(bool);
void enable_sepia(bool);
void enable_grayscale(bool);
void enable_invert(bool);
void update();
Colortable();
~Colortable();
private:
uint32_t *table;
Format format;
signed contrast;
signed brightness;
signed gamma;
bool gamma_ramp;
bool sepia;
bool grayscale;
bool invert;
static const uint8_t gamma_ramp_table[32];
uint8_t contrast_adjust(uint8_t input);
uint8_t brightness_adjust(uint8_t input);
uint8_t gamma_adjust(uint8_t input);
};
extern Colortable colortable;

View File

@@ -1,32 +0,0 @@
DirectFilter filter_direct;
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
}
void DirectFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
pitch >>= 1;
outpitch >>= 2;
for(unsigned y = 0; y < height; y++) {
if(width == 512 && line[y] == 256) {
for(unsigned x = 0; x < 256; x++) {
uint16_t p = *input++;
*output++ = colortable[p];
*output++ = colortable[p];
}
input += 256;
} else {
for(unsigned x = 0; x < width; x++) {
uint16_t p = *input++;
*output++ = colortable[p];
}
}
input += pitch - width;
output += outpitch - width;
}
}

View File

@@ -1,7 +0,0 @@
class DirectFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern DirectFilter filter_direct;

View File

@@ -1,32 +0,0 @@
FilterInterface filter;
void FilterInterface::set(FilterInterface::FilterType type) {
active_filter = type;
}
void FilterInterface::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
switch(active_filter) { default:
case Direct: return filter_direct.size(outwidth, outheight, width, height);
case Scanline: return filter_scanline.size(outwidth, outheight, width, height);
case Scale2x: return filter_scale2x.size(outwidth, outheight, width, height);
case LQ2x: return filter_lq2x.size(outwidth, outheight, width, height);
case HQ2x: return filter_hq2x.size(outwidth, outheight, width, height);
case NTSC: return filter_ntsc.size(outwidth, outheight, width, height);
}
}
void FilterInterface::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
switch(active_filter) { default:
case Direct: return filter_direct.render(output, outpitch, input, pitch, line, width, height);
case Scanline: return filter_scanline.render(output, outpitch, input, pitch, line, width, height);
case Scale2x: return filter_scale2x.render(output, outpitch, input, pitch, line, width, height);
case LQ2x: return filter_lq2x.render(output, outpitch, input, pitch, line, width, height);
case HQ2x: return filter_hq2x.render(output, outpitch, input, pitch, line, width, height);
case NTSC: return filter_ntsc.render(output, outpitch, input, pitch, line, width, height);
}
}
FilterInterface::FilterInterface() : active_filter(FilterInterface::Direct) {}

View File

@@ -1,37 +0,0 @@
class Filter {
public:
virtual void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) = 0;
virtual void render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) = 0;
};
class FilterInterface : public Filter {
public:
enum FilterType {
Direct,
Scanline,
Scale2x,
LQ2x,
HQ2x,
NTSC,
};
void set(FilterType type);
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
);
FilterInterface();
private:
FilterType active_filter;
};
extern FilterInterface filter;

View File

@@ -1,204 +0,0 @@
//HQ2x filter
//authors: byuu and blargg
//license: public domain
//
//note: this is a clean reimplementation of the original HQ2x filter, which was
//written by Maxim Stepin (MaxSt). it is not 100% identical, but very similar.
HQ2xFilter filter_hq2x;
const uint8_t HQ2xFilter::hqTable[256] = {
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
};
bool HQ2xFilter::same(uint16_t x, uint16_t y) {
return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask);
}
bool HQ2xFilter::diff(uint32_t x, uint16_t y) {
return ((x - yuvTable[y]) & diff_mask);
}
void HQ2xFilter::grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; }
uint16_t HQ2xFilter::pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); }
uint16_t HQ2xFilter::blend1(uint32_t A, uint32_t B) {
grow(A); grow(B);
A = (A * 3 + B) >> 2;
return pack(A);
}
uint16_t HQ2xFilter::blend2(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + B + C) >> 2);
}
uint16_t HQ2xFilter::blend3(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 5 + B * 2 + C) >> 3);
}
uint16_t HQ2xFilter::blend4(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 6 + B + C) >> 3);
}
uint16_t HQ2xFilter::blend5(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + (B + C) * 3) >> 3);
}
uint16_t HQ2xFilter::blend6(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 14 + B + C) >> 4);
}
alwaysinline uint16_t HQ2xFilter::blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) {
switch(rule) { default:
case 0: return E;
case 1: return blend1(E, A);
case 2: return blend1(E, D);
case 3: return blend1(E, B);
case 4: return blend2(E, D, B);
case 5: return blend2(E, A, B);
case 6: return blend2(E, A, D);
case 7: return blend3(E, B, D);
case 8: return blend3(E, D, B);
case 9: return blend4(E, D, B);
case 10: return blend5(E, D, B);
case 11: return blend6(E, D, B);
case 12: return same(B, D) ? blend2(E, D, B) : E;
case 13: return same(B, D) ? blend5(E, D, B) : E;
case 14: return same(B, D) ? blend6(E, D, B) : E;
case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
}
}
void HQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void HQ2xFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
int prevline = (y == 0) ? 0 : pitch;
int nextline = (y == height - 1) ? 0 : pitch;
input++;
*out0++ = 0; *out0++ = 0;
*out1++ = 0; *out1++ = 0;
for(unsigned x = 1; x < 256 - 1; x++) {
uint16_t A = *(input - prevline - 1);
uint16_t B = *(input - prevline + 0);
uint16_t C = *(input - prevline + 1);
uint16_t D = *(input - 1);
uint16_t E = *(input + 0);
uint16_t F = *(input + 1);
uint16_t G = *(input + nextline - 1);
uint16_t H = *(input + nextline + 0);
uint16_t I = *(input + nextline + 1);
uint32_t e = yuvTable[E] + diff_offset;
uint8_t pattern;
pattern = diff(e, A) << 0;
pattern |= diff(e, B) << 1;
pattern |= diff(e, C) << 2;
pattern |= diff(e, D) << 3;
pattern |= diff(e, F) << 4;
pattern |= diff(e, G) << 5;
pattern |= diff(e, H) << 6;
pattern |= diff(e, I) << 7;
*(out0 + 0) = colortable[blend(hqTable[pattern], E, A, B, D, F, H)]; pattern = rotate[pattern];
*(out0 + 1) = colortable[blend(hqTable[pattern], E, C, F, B, H, D)]; pattern = rotate[pattern];
*(out1 + 1) = colortable[blend(hqTable[pattern], E, I, H, F, D, B)]; pattern = rotate[pattern];
*(out1 + 0) = colortable[blend(hqTable[pattern], E, G, D, H, B, F)];
input++;
out0 += 2;
out1 += 2;
}
input++;
*out0++ = 0; *out0++ = 0;
*out1++ = 0; *out1++ = 0;
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}
HQ2xFilter::HQ2xFilter() {
yuvTable = new uint32_t[32768];
for(unsigned i = 0; i < 32768; i++) {
uint8_t R = (i >> 0) & 31;
uint8_t G = (i >> 5) & 31;
uint8_t B = (i >> 10) & 31;
//bgr555->bgr888
double r = (R << 3) | (R >> 2);
double g = (G << 3) | (G >> 2);
double b = (B << 3) | (B >> 2);
//bgr888->yuv888
double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v);
}
diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407;
diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0;
for(unsigned n = 0; n < 256; n++) {
rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
| ((n & 0x01) << 5) | ((n & 0x08) << 3)
| ((n & 0x10) >> 3) | ((n & 0x80) >> 5);
}
}
HQ2xFilter::~HQ2xFilter() {
delete[] yuvTable;
}

View File

@@ -1,31 +0,0 @@
class HQ2xFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
HQ2xFilter();
~HQ2xFilter();
private:
static const uint8_t hqTable[256];
uint32_t *yuvTable;
uint32_t diff_offset;
uint32_t diff_mask;
uint8_t rotate[256];
bool same(uint16_t, uint16_t);
bool diff(uint32_t, uint16_t);
void grow(uint32_t&);
uint16_t pack(uint32_t);
uint16_t blend1(uint32_t, uint32_t);
uint16_t blend2(uint32_t, uint32_t, uint32_t);
uint16_t blend3(uint32_t, uint32_t, uint32_t);
uint16_t blend4(uint32_t, uint32_t, uint32_t);
uint16_t blend5(uint32_t, uint32_t, uint32_t);
uint16_t blend6(uint32_t, uint32_t, uint32_t);
uint16_t blend (unsigned, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t);
};
extern HQ2xFilter filter_hq2x;

View File

@@ -1,15 +0,0 @@
#include "libfilter.hpp"
using nall::min;
using nall::max;
namespace libfilter {
#include "colortable.cpp"
#include "filter.cpp"
#include "direct.cpp"
#include "scanline.cpp"
#include "scale2x.cpp"
#include "lq2x.cpp"
#include "hq2x.cpp"
#include "ntsc.cpp"
}

View File

@@ -1,24 +0,0 @@
#ifndef LIBFILTER_H
#define LIBFILTER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <nall/algorithm.hpp>
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
namespace libfilter {
#include "colortable.hpp"
#include "filter.hpp"
#include "direct.hpp"
#include "scanline.hpp"
#include "scale2x.hpp"
#include "lq2x.hpp"
#include "hq2x.hpp"
#include "ntsc.hpp"
};
#endif

View File

@@ -1,57 +0,0 @@
LQ2xFilter filter_lq2x;
void LQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void LQ2xFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
int prevline = (y == 0) ? 0 : pitch;
int nextline = (y == height - 1) ? 0 : pitch;
for(unsigned x = 0; x < 256; x++) {
uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C];
if(A != E && B != D) {
*out0++ = (A == B ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
*out0++ = (A == D ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
*out1++ = (E == B ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
*out1++ = (E == D ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
} else {
*out0++ = c;
*out0++ = c;
*out1++ = c;
*out1++ = c;
}
}
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}

View File

@@ -1,7 +0,0 @@
class LQ2xFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern LQ2xFilter filter_lq2x;

View File

@@ -1,79 +0,0 @@
#include "snes_ntsc/snes_ntsc.c"
NTSCFilter filter_ntsc;
void NTSCFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = SNES_NTSC_OUT_WIDTH(256);
outheight = height;
}
void NTSCFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(!ntsc) return;
width = SNES_NTSC_OUT_WIDTH(256);
burst ^= burst_toggle;
pitch >>= 1;
outpitch >>= 2;
unsigned line_burst = burst;
for(unsigned y = 0; y < height; y++) {
uint16_t *in = input + y * pitch;
uint32_t *out = output + y * outpitch;
//render as many lines in one snes_ntsc_blit as possible:
//do this by determining for how many lines the width stays the same
unsigned rheight = 1;
unsigned rwidth = line[y];
while(y + rheight < height && rwidth == line[y + rheight]) rheight++;
if(rwidth == 256) {
snes_ntsc_blit (ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
}
line_burst = (line_burst + rheight) % 3;
y += rheight;
}
}
void NTSCFilter::adjust(
float hue, float saturation, float contrast,
float brightness, float sharpness, bool merge_fields
) {
static snes_ntsc_setup_t defaults;
snes_ntsc_setup_t setup = defaults;
setup.hue = hue;
setup.saturation = saturation;
setup.contrast = contrast;
setup.brightness = brightness;
setup.sharpness = sharpness;
setup.resolution = sharpness;
setup.merge_fields = merge_fields;
setup.bsnes_colortbl = 0;
if(!ntsc) {
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
if(!ntsc) {
fprintf(stderr, "error: snes_ntsc: out of memory\n");
return;
}
}
burst = 0;
burst_toggle = (merge_fields ? 0 : 1); //don't toggle burst when fields are merged
snes_ntsc_init(ntsc, &setup);
}
NTSCFilter::NTSCFilter() {
ntsc = 0;
adjust(0, 0, 0, 0, 0, false);
}
NTSCFilter::~NTSCFilter() {
if(ntsc) free(ntsc);
}

View File

@@ -1,17 +0,0 @@
#include "snes_ntsc/snes_ntsc.h"
class NTSCFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields);
NTSCFilter();
~NTSCFilter();
private:
struct snes_ntsc_t *ntsc;
int burst, burst_toggle;
};
extern NTSCFilter filter_ntsc;

View File

@@ -1,57 +0,0 @@
Scale2xFilter filter_scale2x;
void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void Scale2xFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
int prevline = (y == 0) ? 0 : pitch;
int nextline = (y == height - 1) ? 0 : pitch;
for(unsigned x = 0; x < 256; x++) {
uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C];
if(A != E && B != D) {
*out0++ = (A == B ? colortable[A] : c);
*out0++ = (A == D ? colortable[A] : c);
*out1++ = (E == B ? colortable[E] : c);
*out1++ = (E == D ? colortable[E] : c);
} else {
*out0++ = c;
*out0++ = c;
*out1++ = c;
*out1++ = c;
}
}
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}

View File

@@ -1,7 +0,0 @@
class Scale2xFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern Scale2xFilter filter_scale2x;

View File

@@ -1,42 +0,0 @@
ScanlineFilter filter_scanline;
void ScanlineFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height > 240 ? height : height * 2;
}
void ScanlineFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
for(unsigned y = 0; y < height; y++) {
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
if(width == 512 && line[y] == 256) {
for(unsigned x = 0; x < 256; x++) {
uint16_t p = *input++;
*out0++ = colortable[p];
*out0++ = colortable[p];
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
}
input += 256;
} else {
for(unsigned x = 0; x < width; x++) {
uint16_t p = *input++;
*out0++ = colortable[p];
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
}
}
input += pitch - width;
output += outpitch * 2;
}
}

View File

@@ -1,7 +0,0 @@
class ScanlineFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern ScanlineFilter filter_scanline;

View File

@@ -1,251 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "snes_ntsc.h"
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
#define alignment_count 3
#define burst_count 3
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
#define std_decoder_hue 0
#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */
#define gamma_size 32
#include "snes_ntsc_impl.h"
/* 3 input pixels -> 8 composite samples */
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
};
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
{
int n;
for ( n = burst_size; n; --n )
{
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
/* merge colors without losing precision */
io [burst_size * 0] =
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 1] =
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 2] =
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
++io;
}
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
snes_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
{
int merge_fields;
int entry;
init_t impl;
if ( !setup )
setup = &snes_ntsc_composite;
init( &impl, setup );
merge_fields = setup->merge_fields;
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
merge_fields = 1;
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
{
/* Reduce number of significant bits of source color. Clearing the
low bits of R and B were least notictable. Modifying green was too
noticeable. */
int ir = entry >> 8 & 0x1E;
int ig = entry >> 4 & 0x1F;
int ib = entry << 1 & 0x1E;
#if SNES_NTSC_BSNES_COLORTBL
if ( setup->bsnes_colortbl )
{
int bgr15 = (ib << 10) | (ig << 5) | ir;
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
ir = rgb16 >> 11 & 0x1E;
ig = rgb16 >> 6 & 0x1F;
ib = rgb16 & 0x1E;
}
#endif
{
float rr = impl.to_float [ir];
float gg = impl.to_float [ig];
float bb = impl.to_float [ib];
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
snes_ntsc_rgb_t* out = ntsc->table [entry];
gen_kernel( &impl, y, i, q, out );
if ( merge_fields )
merge_kernel_fields( out );
correct_errors( rgb, out );
}
}
}
#ifndef SNES_NTSC_NO_BLITTERS
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 3;
line_out += 7;
}
/* finish final pixels */
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
SNES_NTSC_ADJ_IN( line_in [0] ),
SNES_NTSC_ADJ_IN( line_in [1] ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
line_in += 2;
for ( n = chunk_count; n; --n )
{
/* twice as many input pixels per chunk */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 6;
line_out += 7;
}
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif

View File

@@ -1,228 +0,0 @@
/* SNES NTSC video filter */
/* snes_ntsc 0.2.2 */
#ifndef SNES_NTSC_H
#define SNES_NTSC_H
#include "snes_ntsc_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */
typedef struct snes_ntsc_setup_t
{
/* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
} snes_ntsc_setup_t;
/* Video format presets */
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
/* Initializes and adjusts parameters. Can be called multiple times on the same
snes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct snes_ntsc_t snes_ntsc_t;
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. */
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
/* Number of output pixels written by low-res blitter for given input width. Width
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define SNES_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk)
/* Number of low-res input pixels that will fit within given output width. Might be
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define SNES_NTSC_IN_WIDTH( out_width ) \
(((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters */
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { snes_ntsc_black = 0 }; /* palette index for black */
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable )
/* Begins input pixel */
#define SNES_NTSC_COLOR_IN( index, color ) \
SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable )
/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \
SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 )
/* Hires equivalents */
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\
unsigned const snes_ntsc_pixel3_ = (pixel3);\
snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\
unsigned const snes_ntsc_pixel4_ = (pixel4);\
snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\
unsigned const snes_ntsc_pixel5_ = (pixel5);\
snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\
snes_ntsc_rgb_t const* kernel0 = kernel1;\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel1;\
snes_ntsc_rgb_t const* kernelx2 = kernel1;\
snes_ntsc_rgb_t const* kernelx3 = kernel1;\
snes_ntsc_rgb_t const* kernelx4 = kernel1;\
snes_ntsc_rgb_t const* kernelx5 = kernel1
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
SNES_NTSC_CLAMP_( raw_, 0 );\
SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\
}
/* private */
enum { snes_ntsc_entry_size = 128 };
enum { snes_ntsc_palette_size = 0x2000 };
typedef unsigned long snes_ntsc_rgb_t;
struct snes_ntsc_t {
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
};
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
#define SNES_NTSC_RGB16( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
#define SNES_NTSC_BGR15( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
/* common 3->7 ntsc macros */
#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
unsigned const snes_ntsc_pixel0_ = (pixel0);\
snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel0;\
snes_ntsc_rgb_t const* kernelx2 = kernel0
#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
SNES_NTSC_CLAMP_( raw_, shift );\
SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2)
#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101)
#define SNES_NTSC_CLAMP_( io, shift ) {\
snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\
snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* x is always zero except in snes_ntsc library */
/* original routine */
/*
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 24 || bits == 32 )\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
if ( bits == 15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 14 )\
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\
if ( bits == 0 )\
rgb_out = raw_ << x;\
}
*/
/* custom bsnes routine -- hooks into bsnes colortable */
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 ) {\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 24 || bits == 32 ) {\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 15 ) {\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else {\
rgb_out = raw_ << x;\
}\
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,26 +0,0 @@
/* Configure library by modifying this file */
#ifndef SNES_NTSC_CONFIG_H
#define SNES_NTSC_CONFIG_H
/* Format of source pixels */
/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
/* The following affect the built-in blitter only; a custom blitter can
handle things however it wants. */
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
#define SNES_NTSC_OUT_DEPTH 32
/* Type of input pixel values */
#define SNES_NTSC_IN_T unsigned short
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define SNES_NTSC_ADJ_IN( in ) in
/* For each pixel, this is the basic operation:
output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */
#endif

View File

@@ -1,439 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* Common implementation of NTSC filters */
#include <assert.h>
#include <math.h>
/* Copyright (C) 2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define DISABLE_CORRECTION 0
#undef PI
#define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20
#endif
#ifndef gamma_size
#define gamma_size 1
#endif
#ifndef rgb_bits
#define rgb_bits 8
#endif
#ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f)
#endif
#ifndef fringing_max
#define fringing_max (fringing_mid * 2)
#endif
#ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1
#endif
#define ext_decoder_hue (std_decoder_hue + 15)
#define rgb_unit (1 << rgb_bits)
#define rgb_offset (rgb_unit * 2 + 0.5f)
enum { burst_size = snes_ntsc_entry_size / burst_count };
enum { kernel_half = 16 };
enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t
{
float to_rgb [burst_count * 6];
float to_float [gamma_size];
float contrast;
float brightness;
float artifacts;
float fringing;
float kernel [rescale_out * kernel_size * 2];
} init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\
t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\
i = t;\
}
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
{
#if rescale_out > 1
float kernels [kernel_size * 2];
#else
float* const kernels = impl->kernel;
#endif
/* generate luma (y) filter using sinc kernel */
{
/* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh );
float sum;
int i;
/* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = i - kernel_half;
float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{
float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
}
}
/* apply blackman window and find sum */
sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
}
/* normalize kernel */
sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
/* generate chroma (iq) filter using gaussian kernel */
{
float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed;
int i;
if ( cutoff < 0 )
{
/* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= -30.0f / 0.65f;
}
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ )
{
float sum = 0;
int x;
for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x];
sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 )
{
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
}
/*
printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] );
printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] );
*/
/* generate linear rescale kernels */
#if rescale_out > 1
{
float weight = 1.0f;
float* out = impl->kernel;
int n = rescale_out;
do
{
float remain = 0;
int i;
weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ )
{
float cur = kernels [i];
float m = cur * weight;
*out++ = m + remain;
remain = cur - m;
}
}
while ( --n );
}
#endif
}
static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
static void init( init_t* impl, snes_ntsc_setup_t const* setup )
{
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast
if ( !setup->palette )
impl->contrast *= default_palette_contrast;
#endif
impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup );
/* generate gamma table */
if ( gamma_size > 1 )
{
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i;
for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
}
/* setup decoder matricies */
{
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix;
if ( !decoder )
{
decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
}
{
float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb;
int n;
n = burst_count;
do
{
float const* in = decoder;
int n = 3;
do
{
float i = *in++;
float q = *in++;
*out++ = i * c - q * s;
*out++ = i * s + q * c;
}
while ( --n );
if ( burst_count <= 1 )
break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
}
while ( --n );
}
}
}
/* kernel generation */
#define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
)
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
enum { rgb_kernel_size = burst_size / alignment_count };
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
typedef struct pixel_info_t
{
int offset;
float negate;
float kernel [4];
} pixel_info_t;
#if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2))
#else
#define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2))
#endif
extern pixel_info_t const snes_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
{
/* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count;
y -= rgb_offset;
do
{
/* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = snes_ntsc_pixels;
int alignment_remain = alignment_count;
do
{
/* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset];
int n;
++pixel;
for ( n = rgb_kernel_size; n; --n )
{
float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 )
k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1;
else
k -= kernel_size * 2 * (rescale_out - 1) + 2;
{
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
}
}
}
while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 )
break;
to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
}
while ( --burst_remain );
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
#if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
#else
#define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c ) {\
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\
out [a] += fourth;\
out [b] += fourth;\
out [c] += fourth;\
out [i] += error - (fourth * 3);\
}
#endif
#define RGB_PALETTE_OUT( rgb, out_ )\
{\
unsigned char* out = (out_);\
snes_ntsc_rgb_t clamped = (rgb);\
SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\
}
/* blitter related */
#ifndef restrict
#if defined (__GNUC__)
#define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict __restrict
#else
/* no support for restricted pointers */
#define restrict
#endif
#endif
#include <limits.h>
#if SNES_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF
typedef unsigned short snes_ntsc_out_t;
#else
#error "Need 16-bit int type"
#endif
#else
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int snes_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long snes_ntsc_out_t;
#else
#error "Need 32-bit int type"
#endif
#endif

View File

@@ -47,8 +47,8 @@ else ifeq ($(platform),win)
qtlib := -L$(qtpath)/lib
qtlib += -L$(qtpath)/plugins/imageformats
qtlib += -lmingw32 -lqtmain -lQtGui -lcomdlg32 -loleaut32 -limm32 -lwinmm
qtlib += -lwinspool -lmsimg32 -lQtCore -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
qtlib += -lmingw32 -lqtmain -lQtGui4 -lcomdlg32 -loleaut32 -limm32 -lwinmm
qtlib += -lwinspool -lmsimg32 -lQtCore4 -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
# optional image-file support:
# qtlib += -lqjpeg -lqmng

View File

@@ -2,15 +2,13 @@
#define NALL_BASE64_HPP
#include <string.h>
#include <nall/new.hpp>
#include <nall/stdint.hpp>
namespace nall {
class base64 {
public:
static bool encode(char *&output, const uint8_t* input, unsigned inlength) {
output = new(zeromemory) char[inlength * 8 / 6 + 6];
output = new char[inlength * 8 / 6 + 6]();
unsigned i = 0, o = 0;
while(i < inlength) {
@@ -41,7 +39,7 @@ namespace nall {
static bool decode(uint8_t *&output, unsigned &outlength, const char *input) {
unsigned inlength = strlen(input), infix = 0;
output = new(zeromemory) uint8_t[inlength];
output = new uint8_t[inlength]();
unsigned i = 0, o = 0;
while(i < inlength) {

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>
@@ -17,6 +17,7 @@
namespace nall {
struct library : noncopyable {
bool opened() const { return handle; }
bool open(const char*);
void* sym(const char*);
void close();
@@ -51,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

@@ -15,6 +15,14 @@
#include <nall/utility.hpp>
namespace nall {
inline FILE* fopen_utf8(const char *utf8_filename, const char *mode) {
#if !defined(_WIN32)
return fopen(utf8_filename, mode);
#else
return _wfopen(utf16_t(utf8_filename), utf16_t(mode));
#endif
}
class file : noncopyable {
public:
enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread };

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,7 +1,6 @@
#ifndef NALL_MODULO_HPP
#define NALL_MODULO_HPP
#include <nall/new.hpp>
#include <nall/serializer.hpp>
namespace nall {
@@ -26,7 +25,7 @@ namespace nall {
}
modulo_array() {
buffer = new(zeromemory) T[size * 3];
buffer = new T[size * 3]();
}
~modulo_array() {

View File

@@ -1,25 +0,0 @@
#ifndef NALL_NEW_HPP
#define NALL_NEW_HPP
#include <string.h>
#include <new>
#include <nall/stdint.hpp>
namespace nall {
struct zeromemory_t {};
static zeromemory_t zeromemory;
}
inline void* operator new[](size_t size, const nall::zeromemory_t&) throw(std::bad_alloc) {
void *p = new uint8_t[size];
memset(p, 0, size);
return p;
}
inline void* operator new[](size_t size, const std::nothrow_t&, const nall::zeromemory_t&) throw() {
void *p = new(std::nothrow) uint8_t[size];
if(p) memset(p, 0, size);
return p;
}
#endif

View File

@@ -1,7 +1,6 @@
#ifndef NALL_SERIALIZER_HPP
#define NALL_SERIALIZER_HPP
#include <nall/new.hpp>
#include <nall/stdint.hpp>
#include <nall/traits.hpp>
#include <nall/utility.hpp>
@@ -21,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;
}
@@ -38,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;
@@ -49,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;
}
}
@@ -71,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;
@@ -85,20 +90,20 @@ namespace nall {
}
serializer() {
mode = Size;
imode = Size;
idata = 0;
isize = 0;
}
serializer(unsigned capacity) {
mode = Save;
idata = new(zeromemory) uint8_t[capacity];
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;
@@ -110,7 +115,7 @@ namespace nall {
}
private:
enum mode_t { Load, Save, Size } mode;
mode_t imode;
uint8_t *idata;
unsigned isize;
unsigned icapacity;

143
src/lib/nall/sha256.hpp Normal file
View File

@@ -0,0 +1,143 @@
#ifndef NALL_SHA256_HPP
#define NALL_SHA256_HPP
//author: vladitx
namespace nall {
#define PTR(t, a) ((t*)(a))
#define SWAP32(x) ((uint32_t)( \
(((uint32_t)(x) & 0x000000ff) << 24) | \
(((uint32_t)(x) & 0x0000ff00) << 8) | \
(((uint32_t)(x) & 0x00ff0000) >> 8) | \
(((uint32_t)(x) & 0xff000000) >> 24) \
))
#define ST32(a, d) *PTR(uint32_t, a) = (d)
#define ST32BE(a, d) ST32(a, SWAP32(d))
#define LD32(a) *PTR(uint32_t, a)
#define LD32BE(a) SWAP32(LD32(a))
#define LSL32(x, n) ((uint32_t)(x) << (n))
#define LSR32(x, n) ((uint32_t)(x) >> (n))
#define ROR32(x, n) (LSR32(x, n) | LSL32(x, 32 - (n)))
//first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19
static const uint32_t T_H[8] = {
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
};
//first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311
static const uint32_t T_K[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
};
struct sha256_ctx {
uint8_t in[64];
unsigned inlen;
uint32_t w[64];
uint32_t h[8];
uint64_t len;
};
void sha256_init(sha256_ctx *p) {
memset(p, 0, sizeof(sha256_ctx));
memcpy(p->h, T_H, sizeof(T_H));
}
static void sha256_block(sha256_ctx *p) {
unsigned i;
uint32_t s0, s1;
uint32_t a, b, c, d, e, f, g, h;
uint32_t t1, t2, maj, ch;
for(i = 0; i < 16; i++) p->w[i] = LD32BE(p->in + i * 4);
for(i = 16; i < 64; i++) {
s0 = ROR32(p->w[i - 15], 7) ^ ROR32(p->w[i - 15], 18) ^ LSR32(p->w[i - 15], 3);
s1 = ROR32(p->w[i - 2], 17) ^ ROR32(p->w[i - 2], 19) ^ LSR32(p->w[i - 2], 10);
p->w[i] = p->w[i - 16] + s0 + p->w[i - 7] + s1;
}
a = p->h[0]; b = p->h[1]; c = p->h[2]; d = p->h[3];
e = p->h[4]; f = p->h[5]; g = p->h[6]; h = p->h[7];
for(i = 0; i < 64; i++) {
s0 = ROR32(a, 2) ^ ROR32(a, 13) ^ ROR32(a, 22);
maj = (a & b) ^ (a & c) ^ (b & c);
t2 = s0 + maj;
s1 = ROR32(e, 6) ^ ROR32(e, 11) ^ ROR32(e, 25);
ch = (e & f) ^ (~e & g);
t1 = h + s1 + ch + T_K[i] + p->w[i];
h = g; g = f; f = e; e = d + t1;
d = c; c = b; b = a; a = t1 + t2;
}
p->h[0] += a; p->h[1] += b; p->h[2] += c; p->h[3] += d;
p->h[4] += e; p->h[5] += f; p->h[6] += g; p->h[7] += h;
//next block
p->inlen = 0;
}
void sha256_chunk(sha256_ctx *p, const uint8_t *s, unsigned len) {
unsigned l;
p->len += len;
while(len) {
l = 64 - p->inlen;
l = (len < l) ? len : l;
memcpy(p->in + p->inlen, s, l);
s += l;
p->inlen += l;
len -= l;
if(p->inlen == 64) sha256_block(p);
}
}
void sha256_final(sha256_ctx *p) {
uint64_t len;
p->in[p->inlen++] = 0x80;
if(p->inlen > 56) {
memset(p->in + p->inlen, 0, 64 - p->inlen);
sha256_block(p);
}
memset(p->in + p->inlen, 0, 56 - p->inlen);
len = p->len << 3;
ST32BE(p->in + 56, len >> 32);
ST32BE(p->in + 60, len);
sha256_block(p);
}
void sha256_hash(sha256_ctx *p, uint8_t *s) {
uint32_t *t = (uint32_t*)s;
for(unsigned i = 0; i < 8; i++) ST32BE(t++, p->h[i]);
}
#undef PTR
#undef SWAP32
#undef ST32
#undef ST32BE
#undef LD32
#undef LD32BE
#undef LSL32
#undef LSR32
#undef ROR32
}
#endif

View File

@@ -6,6 +6,7 @@
#include <nall/string/cast.hpp>
#include <nall/string/compare.hpp>
#include <nall/string/convert.hpp>
#include <nall/string/filename.hpp>
#include <nall/string/match.hpp>
#include <nall/string/math.hpp>
#include <nall/string/strl.hpp>

View File

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

View File

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

View File

@@ -0,0 +1,48 @@
#ifndef NALL_FILENAME_HPP
#define NALL_FILENAME_HPP
namespace nall {
// "foo/bar.c" -> "foo/", "bar.c" -> "./"
inline string dir(char const *name) {
string result = name;
for(signed i = strlen(result); i >= 0; i--) {
if(result[i] == '/' || result[i] == '\\') {
result[i + 1] = 0;
break;
}
if(i == 0) result = "./";
}
return result;
}
// "foo/bar.c" -> "bar.c"
inline string notdir(char const *name) {
for(signed i = strlen(name); i >= 0; i--) {
if(name[i] == '/' || name[i] == '\\') {
name += i + 1;
break;
}
}
string result = name;
return result;
}
// "foo/bar.c" -> "foo/bar"
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;
}
}
return result;
}
}
#endif

View File

@@ -3,7 +3,14 @@
char* ltrim(char *str, const char *key) {
if(!key || !*key) return str;
while(strbegin(str, key)) strcpy(str, str + strlen(key));
while(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key);
while(true) {
*dest = *src++;
if(!*dest) break;
dest++;
}
}
return str;
}
@@ -19,7 +26,14 @@ char* trim(char *str, const char *key) {
char* ltrim_once(char *str, const char *key) {
if(!key || !*key) return str;
if(strbegin(str, key)) strcpy(str, str + strlen(key));
if(strbegin(str, key)) {
char *dest = str, *src = str + strlen(key);
while(true) {
*dest = *src++;
if(!*dest) break;
dest++;
}
}
return str;
}

View File

@@ -6,7 +6,6 @@
#include <nall/algorithm.hpp>
#include <nall/crc32.hpp>
#include <nall/file.hpp>
#include <nall/new.hpp>
#include <nall/stdint.hpp>
namespace nall {
@@ -98,7 +97,7 @@ namespace nall {
//mirror
if(x_size != px_size && x_size != py_size) return input_invalid;
y_size = (x_size == px_size) ? py_size : px_size;
y_data = new(zeromemory) uint8_t[y_size];
y_data = new uint8_t[y_size]();
for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i];
for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00;

View File

@@ -1,8 +1,6 @@
#ifndef NALL_UTF8_HPP
#define NALL_UTF8_HPP
#include <nall/new.hpp>
//UTF-8 <> UTF-16 conversion
//used only for Win32; Linux, etc use UTF-8 internally
@@ -30,7 +28,7 @@ namespace nall {
utf16_t(const char *s = "") {
if(!s) s = "";
unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
buffer = new(zeromemory) wchar_t[length + 1];
buffer = new wchar_t[length + 1]();
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
}
@@ -56,7 +54,7 @@ namespace nall {
utf8_t(const wchar_t *s = L"") {
if(!s) s = L"";
unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, 0, 0, (const char*)0, (BOOL*)0);
buffer = new(zeromemory) char[length + 1];
buffer = new char[length + 1]();
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, (const char*)0, (BOOL*)0);
}

View File

@@ -24,6 +24,13 @@ namespace nall {
noncopyable(const noncopyable&);
const noncopyable& operator=(const noncopyable&);
};
template<typename T>
inline T* allocate(size_t size, const T &value) {
T *array = new T[size];
for(size_t i = 0; i < size; i++) array[i] = value;
return array;
}
}
#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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,6 @@
#include <nall/bit.hpp>
#include <nall/detect.hpp>
#include <nall/input.hpp>
#include <nall/new.hpp>
#include <nall/sort.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,7 @@
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#endif
namespace ruby {
class pVideoQtOpenGL {
@@ -13,6 +17,7 @@ public:
uint32_t *buffer;
unsigned rasterWidth, rasterHeight;
bool synchronize;
unsigned filter;
void resize(unsigned width, unsigned height) {
@@ -35,6 +40,15 @@ public:
}
}
void updateSynchronization() {
#ifdef __APPLE__
makeCurrent();
CGLContextObj context = CGLGetCurrentContext();
GLint value = synchronize; //0 = draw immediately (no vsync), 1 = draw once per frame (vsync)
CGLSetParameter(context, kCGLCPSwapInterval, &value);
#endif
}
void paintGL() {
unsigned outputWidth = width();
unsigned outputHeight = height();
@@ -85,18 +99,26 @@ public:
} *widget;
bool cap(const string& name) {
if(name == Video::Synchronize) return true;
if(name == Video::Filter) return true;
if(name == "QWidget") return true;
return false;
}
any get(const string& name) {
if(name == Video::Synchronize) return widget->synchronize;
if(name == Video::Filter) return widget->filter;
if(name == "QWidget") return parent;
return false;
}
bool set(const string& name, const any& value) {
if(name == Video::Synchronize) {
widget->synchronize = any_cast<bool>(value);
widget->updateSynchronization();
return true;
}
if(name == Video::Filter) {
widget->filter = any_cast<unsigned>(value);
return true;

View File

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

View File

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

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