Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
6ec765f2c4 | ||
|
54c7b4692d | ||
|
66067f0015 | ||
|
4c66de6f27 | ||
|
6a17b5ed4f | ||
|
8135dfdac9 |
44
src/Makefile
@@ -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 ###
|
||||
|
@@ -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>
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -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;
|
||||
|
22
src/cartridge/gameboyheader.cpp
Normal 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
@@ -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
@@ -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;
|
31
src/chip/21fx/serialization.cpp
Normal 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
|
@@ -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"
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
};
|
@@ -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;
|
@@ -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;
|
||||
|
133
src/chip/supergameboy/supergameboy.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
41
src/chip/supergameboy/supergameboy.hpp
Normal 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;
|
@@ -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++;
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
};
|
||||
|
@@ -32,7 +32,7 @@ configuration data.
|
||||
|
||||
<h3>Supported Filetypes</h3><br>
|
||||
|
||||
<b>SFC, SMC:</b> SNES cartridge — ROM image.<br>
|
||||
<b>SFC:</b> SNES cartridge — ROM image.<br>
|
||||
<b>BS:</b> Satellaview BS-X flash cartridge — EEPROM image.<br>
|
||||
<b>ST:</b> Sufami Turbo cartridge — ROM image.<br>
|
||||
<b>SRM, PSR:</b> non-volatile memory, often used to save game data — (P)SRAM image.<br>
|
||||
|
Before Width: | Height: | Size: 574 B |
BIN
src/data/icons-16x16/applications-multimedia.png
Normal file
After Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 685 B |
Before Width: | Height: | Size: 632 B |
Before Width: | Height: | Size: 477 B |
BIN
src/data/icons-16x16/folder-new.png
Normal file
After Width: | Height: | Size: 635 B |
Before Width: | Height: | Size: 720 B |
BIN
src/data/icons-16x16/item-check-off.png
Normal file
After Width: | Height: | Size: 209 B |
BIN
src/data/icons-16x16/item-check-on.png
Normal file
After Width: | Height: | Size: 266 B |
BIN
src/data/icons-16x16/item-radio-off.png
Normal file
After Width: | Height: | Size: 565 B |
BIN
src/data/icons-16x16/item-radio-on.png
Normal file
After Width: | Height: | Size: 647 B |
BIN
src/data/icons-16x16/media-playback-start.png
Normal file
After Width: | Height: | Size: 660 B |
BIN
src/data/icons-16x16/media-playback-stop.png
Normal file
After Width: | Height: | Size: 429 B |
BIN
src/data/icons-16x16/media-record.png
Normal file
After Width: | Height: | Size: 653 B |
Before Width: | Height: | Size: 378 B |
Before Width: | Height: | Size: 534 B |
Before Width: | Height: | Size: 650 B |
BIN
src/data/icons-22x22/image-x-generic.png
Normal file
After Width: | Height: | Size: 900 B |
BIN
src/data/icons-22x22/system-search.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
104
src/lib/libco/amd64.c
Normal 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
|
@@ -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"
|
||||
|
@@ -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
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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));
|
||||
}
|
@@ -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;
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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) {}
|
@@ -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;
|
@@ -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;
|
||||
}
|
@@ -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;
|
@@ -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"
|
||||
}
|
@@ -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
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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);
|
||||
}
|
@@ -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;
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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;
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
@@ -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
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
|
@@ -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 };
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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() {
|
||||
|
@@ -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
|
@@ -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
@@ -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
|
@@ -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>
|
||||
|
@@ -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> {
|
||||
|
@@ -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
|
||||
|
48
src/lib/nall/string/filename.hpp
Normal 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
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
};
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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();
|
||||
|
@@ -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>
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
|
@@ -5,5 +5,3 @@ mkdir nall
|
||||
mkdir ruby
|
||||
xcopy /E ..\..\..\nall nall
|
||||
xcopy /E ..\..\..\ruby ruby
|
||||
del ruby\test*
|
||||
del ruby\cc.*
|
||||
|