From 7b54c0078640584b82d93ad445537a9b069dfeb0 Mon Sep 17 00:00:00 2001 From: "coadde [Márcio Alexandre Silva Delgado]" Date: Wed, 7 Oct 2015 03:14:31 -0300 Subject: pcr/reicast-git: update pkg --- pcr/reicast-git/PKGBUILD | 113 +- pcr/reicast-git/fix-dyna-constprop.patch | 63 + pcr/reicast-git/futuristic-memops.patch | 31 + pcr/reicast-git/generalize-mappings.patch | 1979 ++++++++++++++++++++++++ pcr/reicast-git/loop-tracing.patch | 109 ++ pcr/reicast-git/loungekatt_rm-nonfree-fp.patch | 1451 +++++++++++++++++ pcr/reicast-git/multiplayer-unstable.patch | 450 ++++++ pcr/reicast-git/multiplayer.patch | 1211 +++++++++++++++ pcr/reicast-git/refactor-rend-stuff.patch | 1244 +++++++++++++++ pcr/reicast-git/sdl-opengl.patch | 251 +++ pcr/reicast-git/sh-block-graphs.patch | 296 ++++ pcr/reicast-git/ta-hash-logs.patch | 120 ++ 12 files changed, 7311 insertions(+), 7 deletions(-) create mode 100644 pcr/reicast-git/fix-dyna-constprop.patch create mode 100644 pcr/reicast-git/futuristic-memops.patch create mode 100644 pcr/reicast-git/generalize-mappings.patch create mode 100644 pcr/reicast-git/loop-tracing.patch create mode 100644 pcr/reicast-git/loungekatt_rm-nonfree-fp.patch create mode 100644 pcr/reicast-git/multiplayer-unstable.patch create mode 100644 pcr/reicast-git/multiplayer.patch create mode 100644 pcr/reicast-git/refactor-rend-stuff.patch create mode 100644 pcr/reicast-git/sdl-opengl.patch create mode 100644 pcr/reicast-git/sh-block-graphs.patch create mode 100644 pcr/reicast-git/ta-hash-logs.patch (limited to 'pcr') diff --git a/pcr/reicast-git/PKGBUILD b/pcr/reicast-git/PKGBUILD index 6f4f6e9e2..5ed2c9fb9 100644 --- a/pcr/reicast-git/PKGBUILD +++ b/pcr/reicast-git/PKGBUILD @@ -6,10 +6,10 @@ # read: error-mem.txt pkgname=reicast-git -pkgver=r1651.56f8ffa -pkgrel=2 +pkgver=r1665.915d6b2 +pkgrel=1 pkgdesc="A multiplatform Sega Dreamcast emulator" -arch=('i686' 'x86_64') +arch=('i686' 'x86_64' 'armv7h') url="http://reicast.com/" license=('GPL2') provides=('reicast') @@ -17,9 +17,31 @@ conflicts=('reicast') makedepends=('git') depends=('libgl' 'alsa-plugins' 'libpulse' 'python-evdev' ) source=(reicast::"git+https://github.com/reicast/reicast-emulator.git" - 'enable_multiplayer_support.patch') + 'enable_multiplayer_support.patch' + 'fix-dyna-constprop.patch' + 'futuristic-memops.patch' + 'generalize-mappings.patch' + 'loop-tracing.patch' + 'loungekatt_rm-nonfree-fp.patch' + 'multiplayer.patch' + 'multiplayer-unstable.patch' + 'refactor-rend-stuff.patch' + 'sdl-opengl.patch' + 'sh-block-graphs.patch' + 'ta-hash-logs.patch') sha256sums=('SKIP' - '12bfc58e12b3ee79b0c82159cdc70c76a4b6804f5c6986853156602bb0e6beb0') + '12bfc58e12b3ee79b0c82159cdc70c76a4b6804f5c6986853156602bb0e6beb0' + 'c14287cf2b2289b9de28cedeee06fcb89ca40da50e34607780dce55d7d8e5fd6' + 'ce3fe9f10555c473cafbf4e85724ebe7a8535a1fa3bfae3c9bc0fe518024f71e' + '4c0227db07dc9fa4713694bc438345261e401e0b10c89b25a3c1d20ac9acd9b9' + 'af47982ca67babb18a96014643c2394b45316f474c3b07b4e38079f780606fce' + '4a6025daded179e88174057affadbcfd539d919c35c36945aa3273fab0b0cb49' + '09097f59200daaa919fee6f50473f4295a7de6702f40ad5e2648d12c9478a080' + '7c0e2a158d7d37ddbf99a40d11a0a889e55c1e85f9c17a2602e5a2bc809ff4ac' + 'aead8326ac6815b555be03030ffbdc8f6ced625c980e77eca89e570591c5eb34' + 'cf386ebaeafce046a1fc971a5b140bb6a1245840ad2c2a341541327ed6f5606c' + '94694d1b615facb39b5ee92ed90c6cefc77fab23fb97f2fcc82e0aa6e1cb14c5' + 'ead1e44b82c5a58beca6550a7620fc426b7729f0b7e2ebe27583397fac2a574d') pkgver() { cd reicast @@ -30,16 +52,93 @@ prepare () { cd reicast # Remove nonfree fp.h header - rm -v core/deps/libpng/fp.h + # rm -v core/deps/libpng/fp.h # Add Multiplayer support patch -Np1 -i "$srcdir"/enable_multiplayer_support.patch + # Add extra patches + patch -Np1 -i "$srcdir"/fix-dyna-constprop.patch + patch -Np1 -i "$srcdir"/futuristic-memops.patch + patch -Np1 -i "$srcdir"/generalize-mappings.patch +# patch -Np1 -i "$srcdir"/loop-tracing.patch # failed build on i686 + patch -Np1 -i "$srcdir"/loungekatt_rm-nonfree-fp.patch + patch -Np1 -i "$srcdir"/refactor-rend-stuff.patch + patch -Np1 -i "$srcdir"/sdl-opengl.patch + patch -Np1 -i "$srcdir"/sh-block-graphs.patch + patch -Np1 -i "$srcdir"/ta-hash-logs.patch + + # Add Multiplayer support (unstable) + # core/linux-dist/main.cpp + # evdev_controllers[port] = { -1, NULL }; + # evdev_device_id[port] = -1; + # maple_controller[port].enabled = true; +# patch -Np1 -i "$srcdir"/multiplayer-unstable.patch +# sed -i 's|kcode[[]port[]]|maple_controller[port].buttons|g +# s|lt[[]port[]]|maple_controller[port].trigger_left|g +# s|rt[[]port[]]|maple_controller[port].trigger_right|g +# s|joyx[[]port[]]|maple_controller[port].stick_x|g +# s|joyy[[]port[]]|maple_controller[port].stick_y|g +# s|DC_DPAD_LEFT|DC_BTN_DPAD1_LEFT|g +# s|DC_DPAD_RIGHT|DC_BTN_DPAD1_RIGHT|g +# s|DC_DPAD_UP|DC_BTN_DPAD1_UP|g +# s|DC_DPAD_DOWN|DC_BTN_DPAD1_DOWN|g +# s|DC_DPAD2_LEFT|DC_BTN_DPAD2_LEFT|g +# s|DC_DPAD2_RIGHT|DC_BTN_DPAD2_RIGHT|g +# s|DC_DPAD2_UP|DC_BTN_DPAD2_UP|g +# s|DC_DPAD2_DOWN|DC_BTN_DPAD2_DOWN|g +# s|const u32 sdl_map_|const DreamcastControllerCodes sdl_map_| +# s|const u32[*] sdl_map_|const DreamcastControllerCodes* sdl_map_| +# \|extern u16|d +# \|extern u32|d +# \|extern u8 |d +# \|extern s8 |d +# \|#define DC_|d +# \|u16 kcode|d +# \|u8 rt|d +# \|u8 lt|d +# \|u32 vks|d +# \|s8 joy|d +# \|int port = 0; port| s|4|MAPLE_NUM_PORTS| +# \|enum DreamcastController|,+32 d +# s|#include ["]types[.]h["]|#include "types.h"\n#include "hw/maple/maple_controller.h"| +# ' core/sdl/sdl.cpp \ +# core/linux-dist/main.cpp \ +# core/linux-dist/main.h \ +# shell/apple/emulator-ios/emulator/EmulatorView.mm +# sed -i 's|kcode[[]port[]]|maple_controller[port].buttons|g +# s|lt[[]port[]]|maple_controller[port].trigger_left|g +# s|rt[[]port[]]|maple_controller[port].trigger_right|g +# s|joyx[[]port[]]|maple_controller[port].stick_x|g +# s|joyy[[]port[]]|maple_controller[port].stick_y|g +# s|DC_DPAD_LEFT|DC_BTN_DPAD1_LEFT|g +# s|DC_DPAD_RIGHT|DC_BTN_DPAD1_RIGHT|g +# s|DC_DPAD_UP|DC_BTN_DPAD1_UP|g +# s|DC_DPAD_DOWN|DC_BTN_DPAD1_DOWN|g +# s|DC_DPAD2_LEFT|DC_BTN_DPAD2_LEFT|g +# s|DC_DPAD2_RIGHT|DC_BTN_DPAD2_RIGHT|g +# s|DC_DPAD2_UP|DC_BTN_DPAD2_UP|g +# s|DC_DPAD2_DOWN|DC_BTN_DPAD2_DOWN|g +# \|extern u16|d +# \|extern u8 |d +# \|extern s8 |d +# \|#define key_CONT_|d +# s|#include ["]glshaders[.]h["]|#include "glshaders.h"\n#include "hw/maple/maple_controller.h"| +# ' core/rend/gles/gles.cpp +# sed -i 's|x11_keymap[[]53[]] = DC_BTN_X;|x11_keymap[53] = DC_BTN_X;\nx11_keymap[52] = DC_BTN_Y;| +# ' core/linux-dist/x11.cpp +# sed -i 's|DC_BTN_DPAD_|DC_BTN_DPAD1_| +# ' core/hw/maple/maple_controller.h \ +# core/windows/winmain.cpp \ +# core/rend/gles/gles.cpp \ +# shell/apple/emulator-osx/emulator-osx/osx-main.mm + # Add experimental shadow support: http://github.com/reicast-emulator/issues/94 sed -i 's|//DrawModVols|DrawModVols|' core/rend/gles/gldraw.cpp # Fix Xbox Input Axis - sed -i 's|DC_AXIS_LT, 0, 0, DC_AXIS_RT|0, 0, DC_AXIS_RT, DC_AXIS_LT|' core/linux-dist/joystick.cpp + # sed -i 's|DC_AXIS_LT, 0, 0, DC_AXIS_RT|0, 0, DC_AXIS_RT, DC_AXIS_LT|' core/linux-dist/joystick.cpp + sed -i 's|DC_AXIS_LT, 0, 0, DC_AXIS_RT|0, 0, DC_AXIS_RT, DC_AXIS_LT|' core/sdl/sdl.cpp # with generalize-mappings.patch # Enable Pulseaudio sed -i 's|#USE_PULSEAUDIO|USE_PULSEAUDIO|' shell/linux/Makefile diff --git a/pcr/reicast-git/fix-dyna-constprop.patch b/pcr/reicast-git/fix-dyna-constprop.patch new file mode 100644 index 000000000..c7c89b5e2 --- /dev/null +++ b/pcr/reicast-git/fix-dyna-constprop.patch @@ -0,0 +1,63 @@ +diff -Nur a/core/hw/sh4/dyna/shil.cpp b/core/hw/sh4/dyna/shil.cpp +--- a/core/hw/sh4/dyna/shil.cpp 2015-10-06 21:43:53.031336322 -0300 ++++ b/core/hw/sh4/dyna/shil.cpp 2015-10-06 21:45:06.558863627 -0300 +@@ -521,20 +521,39 @@ + rv[op->rd._reg]=op->rs1._imm; + } + +- //NOT WORKING +- //WE NEED PROPER PAGELOCKS +- if (op->op==shop_readm && op->rs1.is_imm() && op->rd.is_r32i() && op->rd._reg<16 && op->flags==0x4 && op->rs3.is_null()) +- { +- u32 baddr=blk->addr&0x0FFFFFFF; ++ if (0) { ++ //a more minimalistic but still broken approach for this. ++ //this is clearly a hack ++ if (op->op == shop_readm && op->rs1.is_imm() && IsOnRam(op->rs1.imm_value())) ++ { ++ u32 round = op->rs1.imm_value() & ~PAGE_MASK; ++ bool optmize_away = round == (blk->addr & ~PAGE_MASK) && (blk->addr & 0x007FFFFF) > 0x200000; ++ ++ if (optmize_away && op->flags == 4) { ++ u32 data = _vmem_ReadMem32(op->rs1.imm_value()); ++ op->op = shop_mov32; ++ op->rs1.type = FMT_IMM; ++ op->rs1._imm = data; ++ } ++ } ++ } + +- if (/*baddr==0xC158400 &&*/ blk->addr/PAGE_SIZE == op->rs1._imm/PAGE_SIZE) ++ if (0) { ++ //NOT WORKING ++ //WE NEED PROPER PAGELOCKS ++ if (op->op == shop_readm && op->rs1.is_imm() && op->rd.is_r32i() && op->rd._reg<16 && op->flags == 0x4 && op->rs3.is_null()) + { +- isi[op->rd._reg]=true; +- rv[op->rd._reg]= ReadMem32(op->rs1._imm); +- printf("IMM MOVE: %08X -> %08X\n",op->rs1._imm,rv[op->rd._reg]); ++ u32 baddr = blk->addr & 0x0FFFFFFF; + +- op->op=shop_mov32; +- op->rs1._imm=rv[op->rd._reg]; ++ if (/*baddr==0xC158400 &&*/ blk->addr / PAGE_SIZE == op->rs1._imm / PAGE_SIZE) ++ { ++ isi[op->rd._reg] = true; ++ rv[op->rd._reg] = ReadMem32(op->rs1._imm); ++ printf("IMM MOVE: %08X -> %08X\n", op->rs1._imm, rv[op->rd._reg]); ++ ++ op->op = shop_mov32; ++ op->rs1._imm = rv[op->rd._reg]; ++ } + } + } + } +@@ -925,7 +944,7 @@ + */ + if (settings.dynarec.unstable_opt) + sq_pref(blk); +- //constprop(blk); // crashes on ip ++ constprop(blk); // maybe it works w/o the readm parts? + #if HOST_CPU==CPU_X86 + // rdgrp(blk); + // wtgrp(blk); diff --git a/pcr/reicast-git/futuristic-memops.patch b/pcr/reicast-git/futuristic-memops.patch new file mode 100644 index 000000000..517670402 --- /dev/null +++ b/pcr/reicast-git/futuristic-memops.patch @@ -0,0 +1,31 @@ +diff -Nur a/core/hw/sh4/dyna/shil_canonical.h b/core/hw/sh4/dyna/shil_canonical.h +--- a/core/hw/sh4/dyna/shil_canonical.h 2015-10-06 21:43:53.031336322 -0300 ++++ b/core/hw/sh4/dyna/shil_canonical.h 2015-10-06 21:48:30.009328396 -0300 +@@ -206,6 +206,27 @@ + shil_recimp() + shil_opc_end() + ++//mem io v2 ++ ++//vref = vrans(ptr, nil) ++//vref = vrans(base, offset) ++shil_opc(vtrans) ++shil_recimp() ++shil_opc_end() ++ ++//dst = readpvr(vref) ++//dst = readpvr(vref, nil, offs) w/ offs < 1024 ++shil_opc(readvptr) ++shil_recimp() ++shil_opc_end() ++ ++//writevptr(vref, src) ++//writevptr(vref, src, offs) w/ offs < 1024 ++shil_opc(writevptr) ++shil_recimp() ++shil_opc_end() ++ ++ + //Canonical impl. opcodes ! + shil_opc(sync_sr) + shil_canonical diff --git a/pcr/reicast-git/generalize-mappings.patch b/pcr/reicast-git/generalize-mappings.patch new file mode 100644 index 000000000..a47681f39 --- /dev/null +++ b/pcr/reicast-git/generalize-mappings.patch @@ -0,0 +1,1979 @@ +diff -Nur a/core/linux-dist/bimap.h b/core/linux-dist/bimap.h +--- a/core/linux-dist/bimap.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/bimap.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,67 @@ ++/* SimpleBimap ++ * ++ * A basic implementation of a bidirectional map that not only allows ++ * you to get a mapped value from a key, but also the other way around. ++ * Deleting elements and other fancy (and not-so-fancy) stuff is not ++ * supported. ++ * ++ * Usage example: ++ * SimpleBimap bimap; ++ * bimap.insert("foo", "bar"); ++ * printf("foo -> %s\n", bimap.get_by_key("foo")->c_str()); ++ * printf("bar <- %s\n", bimap.get_by_value("bar")->c_str()); ++ * if(bimap.get_by_key("somekey") == NULL) ++ * puts("somekey not found"); ++ * ++ * The above example's output: ++ * foo -> bar ++ * bar <- foo ++ * somekey not found ++ */ ++#include ++#include ++#include ++ ++template ++class SimpleBimap ++{ ++ private: ++ typedef typename std::map MapA; ++ typedef typename std::map MapB; ++ MapA map_a; ++ MapB map_b; ++ public: ++ void insert(const T1& a, const T2& b) ++ { ++ // create first pair ++ typename MapA::iterator iter_a = map_a.insert(std::pair(b, NULL)).first; ++ T2* ptr_b = const_cast(&(iter_a->first)); ++ ++ // insert second pair (a, pointer_to_b) ++ typename MapB::iterator iter_b = map_b.insert(std::pair(a, ptr_b)).first; ++ ++ // update pointer in map_a to point to a ++ T1* ptr_a = const_cast(&(iter_b->first)); ++ iter_a->second = ptr_a; ++ } ++ ++ const T2* get_by_key(const T1 &a) ++ { ++ typename MapB::iterator it = this->map_b.find(a); ++ if(it != this->map_b.end()) ++ { ++ return (it->second); ++ } ++ return NULL; ++ } ++ ++ const T1* get_by_value(const T2 &b) ++ { ++ typename MapA::iterator it = this->map_a.find(b); ++ if(it != this->map_a.end()) ++ { ++ return (it->second); ++ } ++ return NULL; ++ } ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/evdev.cpp b/core/linux-dist/evdev.cpp +--- a/core/linux-dist/evdev.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/evdev.cpp 1969-12-31 21:00:00.000000000 -0300 +@@ -1,450 +0,0 @@ +-#include +-#include +-#include +-#include "linux-dist/evdev.h" +-#include "linux-dist/main.h" +-#include "cfg/ini.h" +-#include +-#include +-#include +- +-#if defined(USE_EVDEV) +- bool libevdev_tried = false; +- bool libevdev_available = false; +- typedef int (*libevdev_func1_t)(int, const char*); +- typedef const char* (*libevdev_func2_t)(int, int); +- libevdev_func1_t libevdev_event_code_from_name; +- libevdev_func2_t libevdev_event_code_get_name; +- +- void load_libevdev() +- { +- if (libevdev_tried) +- { +- return; +- } +- +- libevdev_tried = true; +- void* lib_handle = dlopen("libevdev.so", RTLD_NOW); +- +- bool failed = false; +- +- if (!lib_handle) +- { +- fprintf(stderr, "%s\n", dlerror()); +- failed = true; +- } +- else +- { +- libevdev_event_code_from_name = reinterpret_cast(dlsym(lib_handle, "libevdev_event_code_from_name")); +- +- const char* error1 = dlerror(); +- if (error1 != NULL) +- { +- fprintf(stderr, "%s\n", error1); +- failed = true; +- } +- +- libevdev_event_code_get_name = reinterpret_cast(dlsym(lib_handle, "libevdev_event_code_get_name")); +- +- const char* error2 = dlerror(); +- if (error2 != NULL) +- { +- fprintf(stderr, "%s\n", error2); +- failed = true; +- } +- } +- +- if(failed) +- { +- puts("WARNING: libevdev is not available. You'll not be able to use button names instead of numeric codes in your controller mappings!\n"); +- return; +- } +- +- libevdev_available = true; +- } +- +- s8 EvdevAxisData::convert(s32 value) +- { +- return (((value - min) * 255) / range); +- } +- +- void EvdevAxisData::init(int fd, int code, bool inverted) +- { +- struct input_absinfo abs; +- if(code < 0 || ioctl(fd, EVIOCGABS(code), &abs)) +- { +- if(code >= 0) +- { +- perror("evdev ioctl"); +- } +- this->range = 255; +- this->min = 0; +- return; +- } +- s32 min = abs.minimum; +- s32 max = abs.maximum; +- printf("evdev: range of axis %d is from %d to %d\n", code, min, max); +- if(inverted) +- { +- this->range = (min - max); +- this->min = max; +- } +- else +- { +- this->range = (max - min); +- this->min = min; +- } +- } +- +- void EvdevController::init() +- { +- this->data_x.init(this->fd, this->mapping->Axis_Analog_X, this->mapping->Axis_Analog_X_Inverted); +- this->data_y.init(this->fd, this->mapping->Axis_Analog_Y, this->mapping->Axis_Analog_Y_Inverted); +- this->data_trigger_left.init(this->fd, this->mapping->Axis_Trigger_Left, this->mapping->Axis_Trigger_Left_Inverted); +- this->data_trigger_right.init(this->fd, this->mapping->Axis_Trigger_Right, this->mapping->Axis_Trigger_Right_Inverted); +- } +- +- std::map loaded_mappings; +- +- int load_keycode(ConfigFile* cfg, string section, string dc_key) +- { +- int code = -1; +- +- string keycode = cfg->get(section, dc_key, "-1"); +- if (strstr(keycode.c_str(), "KEY_") != NULL || +- strstr(keycode.c_str(), "BTN_") != NULL || +- strstr(keycode.c_str(), "ABS_") != NULL) +- { +- if(libevdev_available) +- { +- int type = ((strstr(keycode.c_str(), "ABS_") != NULL) ? EV_ABS : EV_KEY); +- code = libevdev_event_code_from_name(type, keycode.c_str()); +- } +- if(code < 0) +- { +- printf("evdev: failed to find keycode for '%s'\n", keycode.c_str()); +- } +- else +- { +- printf("%s = %s (%d)\n", dc_key.c_str(), keycode.c_str(), code); +- } +- return code; +- } +- +- code = cfg->get_int(section, dc_key, -1); +- if(code >= 0) +- { +- char* name = NULL; +- if(libevdev_available) +- { +- int type = ((strstr(dc_key.c_str(), "axis_") != NULL) ? EV_ABS : EV_KEY); +- name = (char*)libevdev_event_code_get_name(type, code); +- } +- if (name != NULL) +- { +- printf("%s = %s (%d)\n", dc_key.c_str(), name, code); +- } +- else +- { +- printf("%s = %d\n", dc_key.c_str(), code); +- } +- } +- return code; +- } +- +- EvdevControllerMapping load_mapping(FILE* fd) +- { +- ConfigFile mf; +- mf.parse(fd); +- +- EvdevControllerMapping mapping = { +- mf.get("emulator", "mapping_name", "").c_str(), +- load_keycode(&mf, "dreamcast", "btn_a"), +- load_keycode(&mf, "dreamcast", "btn_b"), +- load_keycode(&mf, "dreamcast", "btn_c"), +- load_keycode(&mf, "dreamcast", "btn_d"), +- load_keycode(&mf, "dreamcast", "btn_x"), +- load_keycode(&mf, "dreamcast", "btn_y"), +- load_keycode(&mf, "dreamcast", "btn_z"), +- load_keycode(&mf, "dreamcast", "btn_start"), +- load_keycode(&mf, "emulator", "btn_escape"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_left"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_right"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_up"), +- load_keycode(&mf, "dreamcast", "btn_dpad1_down"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_left"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_right"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_up"), +- load_keycode(&mf, "dreamcast", "btn_dpad2_down"), +- load_keycode(&mf, "compat", "btn_trigger_left"), +- load_keycode(&mf, "compat", "btn_trigger_right"), +- load_keycode(&mf, "compat", "axis_dpad1_x"), +- load_keycode(&mf, "compat", "axis_dpad1_y"), +- load_keycode(&mf, "compat", "axis_dpad2_x"), +- load_keycode(&mf, "compat", "axis_dpad2_y"), +- load_keycode(&mf, "dreamcast", "axis_x"), +- load_keycode(&mf, "dreamcast", "axis_y"), +- load_keycode(&mf, "dreamcast", "axis_trigger_left"), +- load_keycode(&mf, "dreamcast", "axis_trigger_right"), +- mf.get_bool("compat", "axis_x_inverted", false), +- mf.get_bool("compat", "axis_y_inverted", false), +- mf.get_bool("compat", "axis_trigger_left_inverted", false), +- mf.get_bool("compat", "axis_trigger_right_inverted", false) +- }; +- return mapping; +- } +- +- int input_evdev_init(EvdevController* controller, const char* device, const char* custom_mapping_fname = NULL) +- { +- load_libevdev(); +- +- char name[256] = "Unknown"; +- +- printf("evdev: Trying to open device at '%s'\n", device); +- +- int fd = open(device, O_RDONLY); +- +- if (fd >= 0) +- { +- fcntl(fd, F_SETFL, O_NONBLOCK); +- if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) +- { +- perror("evdev: ioctl"); +- return -2; +- } +- else +- { +- printf("evdev: Found '%s' at '%s'\n", name, device); +- +- controller->fd = fd; +- +- const char* mapping_fname; +- +- if(custom_mapping_fname != NULL) +- { +- mapping_fname = custom_mapping_fname; +- } +- else +- { +- #if defined(TARGET_PANDORA) +- mapping_fname = "controller_pandora.cfg"; +- #elif defined(TARGET_GCW0) +- mapping_fname = "controller_gcwz.cfg"; +- #else +- if (strcmp(name, "Microsoft X-Box 360 pad") == 0 || +- strcmp(name, "Xbox 360 Wireless Receiver") == 0 || +- strcmp(name, "Xbox 360 Wireless Receiver (XBOX)") == 0) +- { +- mapping_fname = "controller_xpad.cfg"; +- } +- else if (strstr(name, "Xbox Gamepad (userspace driver)") != NULL) +- { +- mapping_fname = "controller_xboxdrv.cfg"; +- } +- else if (strstr(name, "keyboard") != NULL || +- strstr(name, "Keyboard") != NULL) +- { +- mapping_fname = "keyboard.cfg"; +- } +- else +- { +- mapping_fname = "controller_generic.cfg"; +- } +- #endif +- } +- if(loaded_mappings.count(string(mapping_fname)) == 0) +- { +- FILE* mapping_fd = NULL; +- if(mapping_fname[0] == '/') +- { +- // Absolute mapping +- mapping_fd = fopen(mapping_fname, "r"); +- } +- else +- { +- // Mapping from ~/.reicast/mappings/ +- size_t size_needed = snprintf(NULL, 0, EVDEV_MAPPING_PATH, mapping_fname) + 1; +- char* mapping_path = (char*)malloc(size_needed); +- sprintf(mapping_path, EVDEV_MAPPING_PATH, mapping_fname); +- mapping_fd = fopen(get_readonly_data_path(mapping_path).c_str(), "r"); +- free(mapping_path); +- } +- +- if(mapping_fd != NULL) +- { +- printf("evdev: reading mapping file: '%s'\n", mapping_fname); +- loaded_mappings.insert(std::make_pair(string(mapping_fname), load_mapping(mapping_fd))); +- fclose(mapping_fd); +- +- } +- else +- { +- printf("evdev: unable to open mapping file '%s'\n", mapping_fname); +- perror("evdev"); +- return -3; +- } +- } +- controller->mapping = &loaded_mappings[string(mapping_fname)]; +- printf("evdev: Using '%s' mapping\n", controller->mapping->name); +- controller->init(); +- +- return 0; +- } +- } +- else +- { +- perror("evdev: open"); +- return -1; +- } +- } +- +- bool input_evdev_handle(EvdevController* controller, u32 port) +- { +- #define SET_FLAG(field, mask, expr) field =((expr) ? (field & ~mask) : (field | mask)) +- if (controller->fd < 0 || controller->mapping == NULL) +- { +- return false; +- } +- +- input_event ie; +- +- while(read(controller->fd, &ie, sizeof(ie)) == sizeof(ie)) +- { +- switch(ie.type) +- { +- case EV_KEY: +- if (ie.code == controller->mapping->Btn_A) { +- SET_FLAG(kcode[port], DC_BTN_A, ie.value); +- } else if (ie.code == controller->mapping->Btn_B) { +- SET_FLAG(kcode[port], DC_BTN_B, ie.value); +- } else if (ie.code == controller->mapping->Btn_C) { +- SET_FLAG(kcode[port], DC_BTN_C, ie.value); +- } else if (ie.code == controller->mapping->Btn_D) { +- SET_FLAG(kcode[port], DC_BTN_D, ie.value); +- } else if (ie.code == controller->mapping->Btn_X) { +- SET_FLAG(kcode[port], DC_BTN_X, ie.value); +- } else if (ie.code == controller->mapping->Btn_Y) { +- SET_FLAG(kcode[port], DC_BTN_Y, ie.value); +- } else if (ie.code == controller->mapping->Btn_Z) { +- SET_FLAG(kcode[port], DC_BTN_Z, ie.value); +- } else if (ie.code == controller->mapping->Btn_Start) { +- SET_FLAG(kcode[port], DC_BTN_START, ie.value); +- } else if (ie.code == controller->mapping->Btn_Escape) { +- die("death by escape key"); +- } else if (ie.code == controller->mapping->Btn_DPad_Left) { +- SET_FLAG(kcode[port], DC_DPAD_LEFT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad_Right) { +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad_Up) { +- SET_FLAG(kcode[port], DC_DPAD_UP, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad_Down) { +- SET_FLAG(kcode[port], DC_DPAD_DOWN, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Left) { +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Right) { +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Up) { +- SET_FLAG(kcode[port], DC_DPAD2_UP, ie.value); +- } else if (ie.code == controller->mapping->Btn_DPad2_Down) { +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, ie.value); +- } else if (ie.code == controller->mapping->Btn_Trigger_Left) { +- lt[port] = (ie.value ? 255 : 0); +- } else if (ie.code == controller->mapping->Btn_Trigger_Right) { +- rt[port] = (ie.value ? 255 : 0); +- } +- break; +- case EV_ABS: +- if (ie.code == controller->mapping->Axis_DPad_X) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 1); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_DPad_Y) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD_UP, 1); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_DPad2_X) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 1); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_DPad2_X) +- { +- switch(ie.value) +- { +- case -1: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 1); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 0); +- break; +- case 0: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 0); +- break; +- case 1: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 1); +- break; +- } +- } +- else if (ie.code == controller->mapping->Axis_Analog_X) +- { +- joyx[port] = (controller->data_x.convert(ie.value) + 128); +- } +- else if (ie.code == controller->mapping->Axis_Analog_Y) +- { +- joyy[port] = (controller->data_y.convert(ie.value) + 128); +- } +- else if (ie.code == controller->mapping->Axis_Trigger_Left) +- { +- lt[port] = controller->data_trigger_left.convert(ie.value); +- } +- else if (ie.code == controller->mapping->Axis_Trigger_Right) +- { +- rt[port] = controller->data_trigger_right.convert(ie.value); +- } +- break; +- } +- } +- } +-#endif +- +diff -Nur a/core/linux-dist/evdev.h b/core/linux-dist/evdev.h +--- a/core/linux-dist/evdev.h 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/evdev.h 1969-12-31 21:00:00.000000000 -0300 +@@ -1,74 +0,0 @@ +-#pragma once +-#include +-#include "types.h" +- +-struct EvdevControllerMapping +-{ +- const char* name; +- const int Btn_A; +- const int Btn_B; +- const int Btn_C; +- const int Btn_D; +- const int Btn_X; +- const int Btn_Y; +- const int Btn_Z; +- const int Btn_Start; +- const int Btn_Escape; +- const int Btn_DPad_Left; +- const int Btn_DPad_Right; +- const int Btn_DPad_Up; +- const int Btn_DPad_Down; +- const int Btn_DPad2_Left; +- const int Btn_DPad2_Right; +- const int Btn_DPad2_Up; +- const int Btn_DPad2_Down; +- const int Btn_Trigger_Left; +- const int Btn_Trigger_Right; +- const int Axis_DPad_X; +- const int Axis_DPad_Y; +- const int Axis_DPad2_X; +- const int Axis_DPad2_Y; +- const int Axis_Analog_X; +- const int Axis_Analog_Y; +- const int Axis_Trigger_Left; +- const int Axis_Trigger_Right; +- const bool Axis_Analog_X_Inverted; +- const bool Axis_Analog_Y_Inverted; +- const bool Axis_Trigger_Left_Inverted; +- const bool Axis_Trigger_Right_Inverted; +-}; +- +-struct EvdevAxisData +-{ +- s32 range; // smaller size than 32 bit might cause integer overflows +- s32 min; +- void init(int fd, int code, bool inverted); +- s8 convert(int value); +-}; +- +-struct EvdevController +-{ +- int fd; +- EvdevControllerMapping* mapping; +- EvdevAxisData data_x; +- EvdevAxisData data_y; +- EvdevAxisData data_trigger_left; +- EvdevAxisData data_trigger_right; +- void init(); +-}; +- +-#define EVDEV_DEVICE_CONFIG_KEY "evdev_device_id_%d" +-#define EVDEV_MAPPING_CONFIG_KEY "evdev_mapping_%d" +-#define EVDEV_DEVICE_STRING "/dev/input/event%d" +-#define EVDEV_MAPPING_PATH "/mappings/%s" +- +-#ifdef TARGET_PANDORA +- #define EVDEV_DEFAULT_DEVICE_ID_1 4 +-#else +- #define EVDEV_DEFAULT_DEVICE_ID_1 0 +-#endif +- +-#define EVDEV_DEFAULT_DEVICE_ID(port) (port == 1 ? EVDEV_DEFAULT_DEVICE_ID_1 : -1) +- +-extern int input_evdev_init(EvdevController* controller, const char* device, const char* mapping_fname); +-extern bool input_evdev_handle(EvdevController* controller, u32 port); +diff -Nur a/core/linux-dist/handler.cpp b/core/linux-dist/handler.cpp +--- a/core/linux-dist/handler.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,263 @@ ++#include "handler.h" ++ ++#define SET_FLAG(field, mask, expr) field =((expr) ? (field & ~mask) : (field | mask)) ++static InputAxisID axis_ids[] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_TRIGGER_LEFT, DC_AXIS_TRIGGER_RIGHT, EMU_AXIS_DPAD1_X, EMU_AXIS_DPAD1_Y, EMU_AXIS_DPAD2_X, EMU_AXIS_DPAD2_Y }; ++ ++InputAxisConverter::InputAxisConverter(bool inverted, InputAxisLimits limits) ++{ ++ this->m_deadzone = limits.deadzone; ++ if(inverted) ++ { ++ this->m_range = (limits.minimum - limits.maximum); ++ this->m_minimum = limits.maximum; ++ } ++ else ++ { ++ this->m_range = (limits.maximum - limits.minimum); ++ this->m_minimum = limits.minimum; ++ } ++} ++ ++s8 InputAxisConverter::convert(s32 value) ++{ ++ // If value is in deadzone, return 0 ++ if (this->m_deadzone && ((value >= 0 && value <= this->m_deadzone) || (value < 0 && value >= -this->m_deadzone))) ++ { ++ return 0; ++ } ++ if (this->m_range) ++ { ++ return (((value - this->m_minimum) * 255) / this->m_range); ++ } ++ return value; ++} ++ ++InputMappingStore InputHandler::s_mappingstore; ++ ++ ++InputHandler::InputHandler() ++{ ++ this->m_initialized = false; ++} ++ ++InputHandler::~InputHandler() ++{ ++ //TODO; ++} ++ ++bool InputHandler::initialize(u32 port, std::string device, std::string custom_mapping_filename) ++{ ++ if(this->m_initialized) ++ { ++ printf("%s: Handler is already initialized!\n", this->get_api_name().c_str()); ++ return true; ++ } ++ ++ this->m_port = port; ++ ++ bool success = this->setup_device(device); ++ ++ if(!success) ++ { ++ printf("%s: Initialization of device '%s' failed!\n", this->get_api_name().c_str(), device.c_str()); ++ return false; ++ } ++ ++ if(custom_mapping_filename.empty()) ++ { ++ this->m_mapping = NULL; ++ } ++ else ++ { ++ this->m_mapping = InputHandler::s_mappingstore.get(custom_mapping_filename, this->get_api_name()); ++ } ++ ++ if(this->m_mapping == NULL) ++ { ++ if(!custom_mapping_filename.empty()) ++ { ++ printf("%s: Loading custom mapping '%s' failed!\n", this->get_api_name().c_str(), custom_mapping_filename.c_str()); ++ } ++ std::string default_mapping_filename = this->get_default_mapping_filename(); ++ if(default_mapping_filename.empty()) ++ { ++ printf("%s: No default mapping available!\n", this->get_api_name().c_str()); ++ } ++ else ++ { ++ printf("%s: Using default mapping '%s'.\n", this->get_api_name().c_str(), default_mapping_filename.c_str()); ++ this->m_mapping = InputHandler::s_mappingstore.get(default_mapping_filename, this->get_api_name()); ++ } ++ } ++ ++ ++ if(this->m_mapping == NULL) ++ { ++ printf("%s: Couldn't load a mapping!\n", this->get_api_name().c_str()); ++ return false; ++ } ++ ++ for(int i = 0; i < 8; i++) ++ { ++ InputAxisID id = axis_ids[i]; ++ const InputAxisCode* code = this->m_mapping->get_axis_code(id); ++ if(code != NULL) ++ { ++ InputAxisLimits limits; ++ this->get_axis_limits(*code, limits); ++ if(limits.minimum != limits.maximum) ++ { ++ bool inverted = this->m_mapping->get_axis_inverted(*code); ++ this->enable_axis_converter(id, inverted, limits); ++ } ++ } ++ } ++ this->m_initialized = true; ++ return true; ++} ++ ++bool InputHandler::is_initialized() ++{ ++ return this->m_initialized; ++} ++ ++std::string InputHandler::get_default_mapping_filename() ++{ ++ return "default.cfg"; ++} ++ ++void InputHandler::get_axis_limits(const InputAxisCode code, InputAxisLimits& limits) ++{ ++ // Default stub, can be overridden in subclasses ++ limits.minimum = 0; ++ limits.maximum = 0; ++ limits.deadzone = 0; ++} ++ ++void InputHandler::handle_button(InputButtonCode code, int value) ++{ ++ if(this->m_mapping == NULL) ++ { ++ return; ++ } ++ const InputButtonID* button_id = this->m_mapping->get_button_id(code); ++ if(button_id == NULL) ++ { ++ printf("Ignoring %d (%d)\n", code, button_id); ++ return; ++ } ++ switch(*button_id) ++ { ++ case EMU_BTN_ESCAPE: ++ if(value) ++ { ++ die("death by escape key"); ++ } ++ break; ++ case EMU_BTN_TRIGGER_LEFT: ++ lt[this->m_port] = (value ? 255 : 0); ++ break; ++ case EMU_BTN_TRIGGER_RIGHT: ++ rt[this->m_port] = (value ? 255 : 0); ++ break; ++ default: ++ SET_FLAG(kcode[this->m_port], *button_id, value); ++ }; ++} ++ ++void InputHandler::handle_axis(InputAxisCode code, int value) ++{ ++ if(this->m_mapping == NULL) ++ { ++ return; ++ } ++ const InputAxisID* axis_id = this->m_mapping->get_axis_id(code); ++ if(axis_id == NULL) ++ { ++ printf("Ignoring %d\n", code); ++ return; ++ } ++ switch(*axis_id) ++ { ++ case EMU_AXIS_DPAD1_X: ++ case EMU_AXIS_DPAD1_Y: ++ case EMU_AXIS_DPAD2_X: ++ case EMU_AXIS_DPAD2_Y: ++ { ++ InputButtonID axis_button_id[2]; ++ switch(*axis_id) ++ { ++ case EMU_AXIS_DPAD1_X: ++ axis_button_id[0] = DC_BTN_DPAD1_LEFT; ++ axis_button_id[1] = DC_BTN_DPAD1_RIGHT; ++ break; ++ case EMU_AXIS_DPAD1_Y: ++ axis_button_id[0] = DC_BTN_DPAD1_UP; ++ axis_button_id[1] = DC_BTN_DPAD1_DOWN; ++ break; ++ case EMU_AXIS_DPAD2_X: ++ axis_button_id[0] = DC_BTN_DPAD2_LEFT; ++ axis_button_id[1] = DC_BTN_DPAD2_RIGHT; ++ break; ++ case EMU_AXIS_DPAD2_Y: ++ axis_button_id[0] = DC_BTN_DPAD2_UP; ++ axis_button_id[1] = DC_BTN_DPAD2_DOWN; ++ } ++ bool axis_button_value[2]; ++ axis_button_value[0] = (value < 0); ++ axis_button_value[1] = (value > 0); ++ SET_FLAG(kcode[this->m_port], axis_button_id[0], axis_button_value[0]); ++ SET_FLAG(kcode[this->m_port], axis_button_id[1], axis_button_value[1]); ++ break; ++ } ++ case DC_AXIS_X: ++ case DC_AXIS_Y: ++ case DC_AXIS_TRIGGER_LEFT: ++ case DC_AXIS_TRIGGER_RIGHT: ++ { ++ InputAxisConverter* converter = this->get_axis_converter(*axis_id); ++ s8 converted_value = ((converter == NULL) ? value : converter->convert(value)); ++ switch(*axis_id) ++ { ++ case DC_AXIS_X: ++ joyx[this->m_port] = (converted_value + 128); ++ break; ++ case DC_AXIS_Y: ++ joyy[this->m_port] = (converted_value + 128); ++ break; ++ case DC_AXIS_TRIGGER_LEFT: ++ lt[this->m_port] = converted_value; ++ break; ++ case DC_AXIS_TRIGGER_RIGHT: ++ rt[this->m_port] = converted_value; ++ break; ++ } ++ } ++ } ++} ++ ++void InputHandler::enable_axis_converter(InputAxisID axis, bool inverted, InputAxisLimits limits) ++{ ++ this->disable_axis_converter(axis); // Delete old axis converter ++ this->m_axis_converters[axis] = new InputAxisConverter(inverted, limits); ++} ++ ++void InputHandler::disable_axis_converter(InputAxisID axis) ++{ ++ InputAxisConverterStore::iterator iter = this->m_axis_converters.find(axis); ++ if(iter != this->m_axis_converters.end()) ++ { ++ delete iter->second; ++ this->m_axis_converters.erase(iter); ++ } ++} ++ ++InputAxisConverter* InputHandler::get_axis_converter(InputAxisID axis) ++{ ++ InputAxisConverterStore::iterator iter = this->m_axis_converters.find(axis); ++ if(iter == this->m_axis_converters.end()) ++ { ++ return NULL; ++ } ++ return iter->second; ++} +\ No newline at end of file +diff -Nur a/core/linux-dist/handler_evdev.cpp b/core/linux-dist/handler_evdev.cpp +--- a/core/linux-dist/handler_evdev.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_evdev.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,132 @@ ++#if defined(USE_EVDEV) ++#include "handler_evdev.h" ++#include ++#include ++#include ++#include ++#include ++ ++#define EVDEV_DEVICE_STRING "/dev/input/event%s" ++ ++void EvdevInputHandler::get_axis_limits(const InputAxisCode code, InputAxisLimits& limits) ++{ ++ struct input_absinfo abs; ++ if(!this->m_evdev_fd < 0 || code < 0 || ioctl(this->m_evdev_fd, EVIOCGABS(code), &abs)) ++ { ++ if(this->m_evdev_fd >= 0 && code >= 0) ++ { ++ perror("evdev ioctl"); ++ } ++ limits.minimum = 0; ++ limits.maximum = 0; ++ limits.deadzone = 0; ++ return; ++ } ++ limits.minimum = abs.minimum; ++ limits.maximum = abs.maximum; ++ limits.deadzone = abs.flat; ++} ++ ++std::string EvdevInputHandler::get_api_name() ++{ ++ return "evdev"; ++} ++ ++bool EvdevInputHandler::setup_device(std::string device) ++{ ++ size_t size_needed = snprintf(NULL, 0, EVDEV_DEVICE_STRING, device.c_str()) + 1; ++ char* evdev_fname = (char*)malloc(size_needed); ++ sprintf(evdev_fname, EVDEV_DEVICE_STRING, device.c_str()); ++ ++ printf("evdev: Trying to open device '%s'\n", evdev_fname); ++ ++ this->m_evdev_fd = open(evdev_fname, O_RDONLY); ++ ++ char device_name[256] = "Unknown"; ++ ++ if (this->m_evdev_fd < 0) ++ { ++ printf("evdev: Opening device '%s' failed - %s", evdev_fname, strerror(errno)); ++ free(evdev_fname); ++ return false; ++ } ++ ++ fcntl(this->m_evdev_fd, F_SETFL, O_NONBLOCK); ++ ++ // Get device name ++ if(ioctl(this->m_evdev_fd, EVIOCGNAME(sizeof(device_name)), device_name) < 0) ++ { ++ printf("evdev: Getting name of '%s' (ioctl) failed - %s", evdev_fname, strerror(errno)); ++ free(evdev_fname); ++ return false; ++ } ++ ++ printf("evdev: Found '%s' at '%s'\n", device_name, evdev_fname); ++ this->m_evdev_devname = std::string(device_name); ++ ++ free(evdev_fname); ++ ++ return true; ++} ++ ++std::string EvdevInputHandler::get_default_mapping_filename() ++{ ++ if (this->m_evdev_devname.empty()) ++ { ++ return ""; ++ } ++ ++ std::string mapping_filename; ++ #if defined(TARGET_PANDORA) ++ mapping_filename = "controller_pandora.cfg"; ++ #elif defined(TARGET_GCW0) ++ mapping_filename = "controller_gcwz.cfg"; ++ #else ++ if (strstr(this->m_evdev_devname.c_str(), "Microsoft X-Box 360 pad") == NULL || strstr(this->m_evdev_devname.c_str(), "Xbox 360 Wireless Receiver") == NULL) ++ { ++ mapping_filename = "controller_xpad.cfg"; ++ } ++ else if (strstr(this->m_evdev_devname.c_str(), "Xbox Gamepad (userspace driver)") != NULL) ++ { ++ mapping_filename = "controller_xboxdrv.cfg"; ++ } ++ else if (strstr(this->m_evdev_devname.c_str(), "keyboard") != NULL || strstr(this->m_evdev_devname.c_str(), "Keyboard") != NULL) ++ { ++ mapping_filename = "keyboard.cfg"; ++ } ++ else ++ { ++ mapping_filename = "controller_generic.cfg"; ++ } ++ #endif ++ ++ return mapping_filename; ++} ++ ++void EvdevInputHandler::handle() ++{ ++ if (!this->is_initialized()) ++ { ++ return; ++ } ++ ++ input_event ie; ++ while(read(this->m_evdev_fd, &ie, sizeof(ie)) == sizeof(ie)) ++ { ++ //printf("evdev: type = %d - code = %d - value = %d\n", ie.type, ie.code, ie.value); ++ switch(ie.type) ++ { ++ case EV_KEY: ++ { ++ this->handle_button(ie.code, ie.value); ++ break; ++ } ++ case EV_ABS: ++ { ++ this->handle_axis(ie.code, ie.value); ++ break; ++ } ++ } ++ } ++} ++#endif +diff -Nur a/core/linux-dist/handler_evdev.h b/core/linux-dist/handler_evdev.h +--- a/core/linux-dist/handler_evdev.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_evdev.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,15 @@ ++#pragma once ++#include "handler.h" ++ ++class EvdevInputHandler : public InputHandler ++{ ++ private: ++ int m_evdev_fd; ++ std::string m_evdev_devname; ++ void get_axis_limits(const InputAxisCode code, InputAxisLimits& limits); ++ public: ++ void handle(); ++ std::string get_api_name(); ++ std::string get_default_mapping_filename(); ++ bool setup_device(std::string device); ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/handler.h b/core/linux-dist/handler.h +--- a/core/linux-dist/handler.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,49 @@ ++#pragma once ++#include "types.h" ++#include "mapping.h" ++#include "mappingstore.h" ++ ++struct InputAxisLimits ++{ ++ s32 minimum; ++ s32 maximum; ++ s32 deadzone; ++}; ++ ++class InputAxisConverter ++{ ++ private: ++ s32 m_minimum; ++ s32 m_range; ++ s32 m_deadzone; ++ public: ++ InputAxisConverter(bool inverted, InputAxisLimits limits); ++ s8 convert(s32 value); ++}; ++ ++class InputHandler ++{ ++ typedef std::map InputAxisConverterStore; ++ private: ++ InputAxisConverterStore m_axis_converters; ++ void enable_axis_converter(InputAxisID axis, bool inverted, InputAxisLimits limits); ++ void disable_axis_converter(InputAxisID axis); ++ InputAxisConverter* get_axis_converter(InputAxisID axis); ++ bool m_initialized; ++ protected: ++ static InputMappingStore s_mappingstore; ++ u32 m_port; ++ InputMapping* m_mapping; ++ bool is_initialized(); ++ void handle_button(InputButtonCode code, int value); ++ void handle_axis(InputAxisCode code, int value); ++ virtual void get_axis_limits(const InputAxisCode code, InputAxisLimits& limits); ++ public: ++ InputHandler(); ++ ~InputHandler(); ++ bool initialize(u32 port, std::string device, std::string custom_mapping); ++ virtual std::string get_default_mapping_filename(); ++ virtual void handle() = 0; ++ virtual std::string get_api_name() = 0; ++ virtual bool setup_device(std::string device) = 0; ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/handler_linuxjs.cpp b/core/linux-dist/handler_linuxjs.cpp +--- a/core/linux-dist/handler_linuxjs.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_linuxjs.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,127 @@ ++#if defined(USE_JOYSTICK) ++#include "handler_linuxjs.h" ++#include ++#include ++#include ++#include ++#include ++ ++#define LINUXJS_DEVICE_STRING "/dev/input/js%s" ++ ++void LinuxJoystickInputHandler::get_axis_limits(const InputAxisCode code, InputAxisLimits& limits) ++{ ++ // The Linux Joystick API's axes always normalized to this minimum/maximum ++ limits.minimum = -32767; ++ limits.maximum = 32767; ++ limits.deadzone = 0; ++} ++ ++std::string LinuxJoystickInputHandler::get_api_name() ++{ ++ return "linuxjs"; ++} ++ ++bool LinuxJoystickInputHandler::setup_device(std::string device) ++{ ++ size_t size_needed = snprintf(NULL, 0, LINUXJS_DEVICE_STRING, device.c_str()) + 1; ++ char* linuxjs_fname = (char*)malloc(size_needed); ++ sprintf(linuxjs_fname, LINUXJS_DEVICE_STRING, device.c_str()); ++ ++ printf("linuxjs: Trying to open device '%s'\n", linuxjs_fname); ++ ++ this->m_linuxjs_fd = open(linuxjs_fname, O_RDONLY); ++ ++ if (this->m_linuxjs_fd < 0) ++ { ++ printf("linuxjs: Opening device '%s' failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ fcntl(this->m_linuxjs_fd, F_SETFL, O_NONBLOCK); ++ ++ char device_name[256] = "Unknown"; ++ int button_count = 0; ++ int axis_count = 0; ++ ++ // Get device name ++ if(ioctl(this->m_linuxjs_fd, JSIOCGNAME(sizeof(device_name)), device_name) < 0) ++ { ++ printf("linuxjs: Getting name of '%s' (ioctl) failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ // Get number of buttons ++ if(ioctl(this->m_linuxjs_fd, JSIOCGBUTTONS, &button_count) < 0) ++ { ++ printf("linuxjs: Getting button count of '%s' (ioctl) failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ // Get number of axes ++ if(ioctl(this->m_linuxjs_fd, JSIOCGAXES, &axis_count) < 0) ++ { ++ printf("linuxjs: Getting axis count of '%s' (ioctl) failed - %s", linuxjs_fname, strerror(errno)); ++ free(linuxjs_fname); ++ return false; ++ } ++ ++ printf("linuxjs: Found '%s' with %d axes and %d buttons at '%s'\n", device_name, axis_count, button_count, linuxjs_fname); ++ this->m_linuxjs_devname = std::string(device_name); ++ ++ free(linuxjs_fname); ++ ++ return true; ++} ++ ++std::string LinuxJoystickInputHandler::get_default_mapping_filename() ++{ ++ if (this->m_linuxjs_devname.empty()) ++ { ++ return ""; ++ } ++ ++ std::string mapping_filename; ++ if (strstr(this->m_linuxjs_devname.c_str(), "Microsoft X-Box 360 pad") != NULL || ++ strstr(this->m_linuxjs_devname.c_str(), "Xbox Gamepad (userspace driver)") != NULL || ++ strstr(this->m_linuxjs_devname.c_str(), "Xbox 360 Wireless Receiver") != NULL) ++ { ++ mapping_filename = "controller_xbox360.cfg"; ++ } ++ else ++ { ++ mapping_filename = "controller_generic.cfg"; ++ } ++ ++ return mapping_filename; ++} ++ ++void LinuxJoystickInputHandler::handle() ++{ ++ if (!this->is_initialized()) ++ { ++ return; ++ } ++ ++ struct js_event je; ++ while(read(this->m_linuxjs_fd, &je, sizeof(je)) == sizeof(je)) ++ { ++ printf("linuxjs: type = %d - code = %d - value = %d\n", je.type, je.number, je.value); ++ switch(je.type) ++ { ++ case JS_EVENT_BUTTON: ++ { ++ this->handle_button(je.number, je.value); ++ break; ++ } ++ case JS_EVENT_AXIS: ++ { ++ this->handle_axis(je.number, je.value); ++ break; ++ } ++ } ++ } ++} ++#endif +\ No newline at end of file +diff -Nur a/core/linux-dist/handler_linuxjs.h b/core/linux-dist/handler_linuxjs.h +--- a/core/linux-dist/handler_linuxjs.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/handler_linuxjs.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,15 @@ ++#pragma once ++#include "handler.h" ++ ++class LinuxJoystickInputHandler : public InputHandler ++{ ++ private: ++ int m_linuxjs_fd; ++ std::string m_linuxjs_devname; ++ void get_axis_limits(const InputAxisCode code, InputAxisLimits& limits); ++ public: ++ void handle(); ++ std::string get_api_name(); ++ std::string get_default_mapping_filename(); ++ bool setup_device(std::string device); ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/joystick.cpp b/core/linux-dist/joystick.cpp +--- a/core/linux-dist/joystick.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/joystick.cpp 1969-12-31 21:00:00.000000000 -0300 +@@ -1,158 +0,0 @@ +-#include +-#include +-#include +-#include +-#include "linux-dist/joystick.h" +- +-#if defined(USE_JOYSTICK) +- const u32 joystick_map_btn_usb[JOYSTICK_MAP_SIZE] = { DC_BTN_Y, DC_BTN_B, DC_BTN_A, DC_BTN_X, 0, 0, 0, 0, 0, DC_BTN_START }; +- const u32 joystick_map_axis_usb[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, 0, 0, 0, 0, 0, 0, 0, 0 }; +- +- const u32 joystick_map_btn_xbox360[JOYSTICK_MAP_SIZE] = { DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, 0, 0, 0, DC_BTN_START, 0, 0 }; +- const u32 joystick_map_axis_xbox360[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, 0, 0, DC_AXIS_RT, DC_DPAD_LEFT, DC_DPAD_UP, 0, 0 }; +- +- const u32* joystick_map_btn = joystick_map_btn_usb; +- const u32* joystick_map_axis = joystick_map_axis_usb; +- +- int input_joystick_init(const char* device) +- { +- int axis_count = 0; +- int button_count = 0; +- char name[128] = "Unknown"; +- +- printf("joystick: Trying to open device at '%s'\n", device); +- +- int fd = open(device, O_RDONLY); +- +- if(fd >= 0) +- { +- fcntl(fd, F_SETFL, O_NONBLOCK); +- ioctl(fd, JSIOCGAXES, &axis_count); +- ioctl(fd, JSIOCGBUTTONS, &button_count); +- ioctl(fd, JSIOCGNAME(sizeof(name)), &name); +- +- printf("joystick: Found '%s' with %d axis and %d buttons at '%s'.\n", name, axis_count, button_count, device); +- +- if (strcmp(name, "Microsoft X-Box 360 pad") == 0 || +- strcmp(name, "Xbox Gamepad (userspace driver)") == 0 || +- strcmp(name, "Xbox 360 Wireless Receiver (XBOX)") == 0) +- { +- joystick_map_btn = joystick_map_btn_xbox360; +- joystick_map_axis = joystick_map_axis_xbox360; +- printf("joystick: Using Xbox 360 map\n"); +- } +- } +- else +- { +- perror("joystick open"); +- } +- +- return fd; +- } +- +- bool input_joystick_handle(int fd, u32 port) +- { +- // Joystick must be connected +- if(fd < 0) { +- return false; +- } +- +- struct js_event JE; +- while(read(fd, &JE, sizeof(JE)) == sizeof(JE)) +- if (JE.number < JOYSTICK_MAP_SIZE) +- { +- switch(JE.type & ~JS_EVENT_INIT) +- { +- case JS_EVENT_AXIS: +- { +- u32 mt = joystick_map_axis[JE.number] >> 16; +- u32 mo = joystick_map_axis[JE.number] & 0xFFFF; +- +- //printf("AXIS %d,%d\n",JE.number,JE.value); +- s8 v=(s8)(JE.value/256); //-127 ... + 127 range +- +- if (mt == 0) +- { +- kcode[port] |= mo; +- kcode[port] |= mo*2; +- if (v<-64) +- { +- kcode[port] &= ~mo; +- } +- else if (v>64) +- { +- kcode[port] &= ~(mo*2); +- } +- +- //printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2)); +- } +- else if (mt == 1) +- { +- if (v >= 0) +- { +- v++; //up to 255 +- } +- //printf("AXIS %d,%d Mapped to %d %d %d\n",JE.number,JE.value,mo,v,v+127); +- if (mo == 0) +- { +- lt[port] = (v + 127); +- } +- else if (mo == 1) +- { +- rt[port] = (v + 127); +- } +- } +- else if (mt == 2) +- { +- // printf("AXIS %d,%d Mapped to %d %d [%d]",JE.number,JE.value,mo,v); +- if (mo == 0) +- { +- joyx[port] = v; +- } +- else if (mo == 1) +- { +- joyy[port] = v; +- } +- } +- } +- break; +- +- case JS_EVENT_BUTTON: +- { +- u32 mt = joystick_map_btn[JE.number] >> 16; +- u32 mo = joystick_map_btn[JE.number] & 0xFFFF; +- +- // printf("BUTTON %d,%d\n",JE.number,JE.value); +- +- if (mt == 0) +- { +- // printf("Mapped to %d\n",mo); +- if (JE.value) +- { +- kcode[port] &= ~mo; +- } +- else +- { +- kcode[port] |= mo; +- } +- } +- else if (mt == 1) +- { +- // printf("Mapped to %d %d\n",mo,JE.value?255:0); +- if (mo==0) +- { +- lt[port] = JE.value ? 255 : 0; +- } +- else if (mo==1) +- { +- rt[port] = JE.value ? 255 : 0; +- } +- } +- } +- break; +- } +- } +- +- return true; +- } +-#endif +diff -Nur a/core/linux-dist/joystick.h b/core/linux-dist/joystick.h +--- a/core/linux-dist/joystick.h 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/joystick.h 1969-12-31 21:00:00.000000000 -0300 +@@ -1,10 +0,0 @@ +-#include "types.h" +-#include "linux-dist/main.h" +- +-#pragma once +-#define JOYSTICK_DEVICE_STRING "/dev/input/js%d" +-#define JOYSTICK_DEFAULT_DEVICE_ID -1 +-#define JOYSTICK_MAP_SIZE 32 +- +-extern int input_joystick_init(const char* device); +-extern bool input_joystick_handle(int fd, u32 port); +diff -Nur a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp +--- a/core/linux-dist/main.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/main.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -14,6 +14,7 @@ + #include + #include "hw/sh4/dyna/blockmanager.h" + #include ++#include "proxy.h" + + #if defined(TARGET_EMSCRIPTEN) + #include +@@ -32,11 +33,11 @@ + #endif + + #if defined(USE_EVDEV) +- #include "linux-dist/evdev.h" ++ #include "linux-dist/handler_evdev.h" + #endif + + #if defined(USE_JOYSTICK) +- #include "linux-dist/joystick.h" ++ #include "linux-dist/handler_linuxjs.h" + #endif + + #ifdef TARGET_PANDORA +@@ -84,82 +85,68 @@ + + void emit_WriteCodeCache(); + +-#if defined(USE_EVDEV) +- /* evdev input */ +- static EvdevController evdev_controllers[4] = { +- { -1, NULL }, +- { -1, NULL }, +- { -1, NULL }, +- { -1, NULL } +- }; +-#endif +- +-#if defined(USE_JOYSTICK) +- /* legacy joystick input */ +- static int joystick_fd = -1; // Joystick file descriptor +-#endif ++static InputHandlerProxy input_handlers; + + void SetupInput() + { + #if defined(USE_EVDEV) +- int evdev_device_id[4] = { -1, -1, -1, -1 }; +- size_t size_needed; +- int port, i; ++ #define EVDEV_DEVICE_CONFIG_KEY "evdev_device_id_%d" ++ #define EVDEV_MAPPING_CONFIG_KEY "evdev_mapping_%d" + +- char* evdev_device; ++ #ifdef TARGET_PANDORA ++ #define EVDEV_DEFAULT_DEVICE_ID_1 "4" ++ #else ++ #define EVDEV_DEFAULT_DEVICE_ID_1 "0" ++ #endif ++ #define EVDEV_DEFAULT_DEVICE_ID(port) (port == 1 ? EVDEV_DEFAULT_DEVICE_ID_1 : "-1") + +- for (port = 0; port < 4; port++) ++ for (int port = 0; port < 4; port++) + { ++ size_t size_needed; ++ char* evdev_config_key; ++ std::string evdev_device; ++ std::string custom_mapping_filename; ++ + size_needed = snprintf(NULL, 0, EVDEV_DEVICE_CONFIG_KEY, port+1) + 1; +- char* evdev_config_key = (char*)malloc(size_needed); ++ evdev_config_key = (char*)malloc(size_needed); + sprintf(evdev_config_key, EVDEV_DEVICE_CONFIG_KEY, port+1); +- evdev_device_id[port] = cfgLoadInt("input", evdev_config_key, EVDEV_DEFAULT_DEVICE_ID(port+1)); ++ evdev_device = cfgLoadStr("input", evdev_config_key, EVDEV_DEFAULT_DEVICE_ID(port+1)); + free(evdev_config_key); + +- // Check if the same device is already in use on another port +- if (evdev_device_id[port] < 0) ++ if(evdev_device.c_str()[0] == '-') + { + printf("evdev: Controller %d disabled by config.\n", port + 1); ++ continue; + } +- else +- { +- for (i = 0; i < port; i++) +- { +- if (evdev_device_id[port] == evdev_device_id[i]) +- { +- die("You can't assign the same device to multiple ports!\n"); +- } +- } +- +- size_needed = snprintf(NULL, 0, EVDEV_DEVICE_STRING, evdev_device_id[port]) + 1; +- evdev_device = (char*)malloc(size_needed); +- sprintf(evdev_device, EVDEV_DEVICE_STRING, evdev_device_id[port]); +- +- size_needed = snprintf(NULL, 0, EVDEV_MAPPING_CONFIG_KEY, port+1) + 1; +- evdev_config_key = (char*)malloc(size_needed); +- sprintf(evdev_config_key, EVDEV_MAPPING_CONFIG_KEY, port+1); +- const char* mapping = (cfgExists("input", evdev_config_key) == 2 ? cfgLoadStr("input", evdev_config_key, "").c_str() : NULL); +- free(evdev_config_key); + +- input_evdev_init(&evdev_controllers[port], evdev_device, mapping); ++ size_needed = snprintf(NULL, 0, EVDEV_MAPPING_CONFIG_KEY, port+1) + 1; ++ evdev_config_key = (char*)malloc(size_needed); ++ sprintf(evdev_config_key, EVDEV_MAPPING_CONFIG_KEY, port+1); ++ custom_mapping_filename = (cfgExists("input", evdev_config_key) == 2 ? cfgLoadStr("input", evdev_config_key, "") : ""); ++ free(evdev_config_key); + +- free(evdev_device); +- } ++ EvdevInputHandler* handler = new EvdevInputHandler(); ++ handler->initialize(port, evdev_device, custom_mapping_filename); ++ input_handlers.add(port, handler); + } + #endif + + #if defined(USE_JOYSTICK) +- int joystick_device_id = cfgLoadInt("input", "joystick_device_id", JOYSTICK_DEFAULT_DEVICE_ID); +- if (joystick_device_id < 0) { +- puts("Legacy Joystick input disabled by config.\n"); ++ #define JOYSTICK_DEFAULT_DEVICE_ID "-1" ++ ++ std::string linuxjs_device; ++ std::string custom_mapping_filename = ""; ++ ++ linuxjs_device = cfgLoadStr("input", "joystick_device_id", JOYSTICK_DEFAULT_DEVICE_ID); ++ if (linuxjs_device.c_str()[0] == '-') ++ { ++ puts("LinuxJoystick input disabled by config.\n"); + } + else + { +- int joystick_device_length = snprintf(NULL, 0, JOYSTICK_DEVICE_STRING, joystick_device_id); +- char* joystick_device = (char*)malloc(joystick_device_length + 1); +- sprintf(joystick_device, JOYSTICK_DEVICE_STRING, joystick_device_id); +- joystick_fd = input_joystick_init(joystick_device); +- free(joystick_device); ++ LinuxJoystickInputHandler* handler = new LinuxJoystickInputHandler(); ++ handler->initialize(0, linuxjs_device, custom_mapping_filename); ++ input_handlers.add(0, handler); + } + #endif + +@@ -178,13 +165,7 @@ + return; + #endif + +- #if defined(USE_JOYSTICK) +- input_joystick_handle(joystick_fd, port); +- #endif +- +- #if defined(USE_EVDEV) +- input_evdev_handle(&evdev_controllers[port], port); +- #endif ++ input_handlers.handle(port); + + #if defined(USE_SDL) + input_sdl_handle(port); +diff -Nur a/core/linux-dist/main.h b/core/linux-dist/main.h +--- a/core/linux-dist/main.h 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/main.h 2015-10-06 21:55:43.966475140 -0300 +@@ -11,25 +11,34 @@ + + enum DreamcastController + { +- DC_BTN_C = 1, +- DC_BTN_B = 1<<1, +- DC_BTN_A = 1<<2, +- DC_BTN_START = 1<<3, +- DC_DPAD_UP = 1<<4, +- DC_DPAD_DOWN = 1<<5, +- DC_DPAD_LEFT = 1<<6, +- DC_DPAD_RIGHT = 1<<7, +- DC_BTN_Z = 1<<8, +- DC_BTN_Y = 1<<9, +- DC_BTN_X = 1<<10, +- DC_BTN_D = 1<<11, +- DC_DPAD2_UP = 1<<12, +- DC_DPAD2_DOWN = 1<<13, +- DC_DPAD2_LEFT = 1<<14, +- DC_DPAD2_RIGHT = 1<<15, ++ EMU_BTN_NONE = 0, ++ EMU_BTN_ESCAPE = 1<<16, ++ EMU_BTN_TRIGGER_LEFT = 1<<17, ++ EMU_BTN_TRIGGER_RIGHT = 1<<18, ++ DC_BTN_C = 1, ++ DC_BTN_B = 1<<1, ++ DC_BTN_A = 1<<2, ++ DC_BTN_START = 1<<3, ++ DC_BTN_DPAD1_UP = 1<<4, ++ DC_BTN_DPAD1_DOWN = 1<<5, ++ DC_BTN_DPAD1_LEFT = 1<<6, ++ DC_BTN_DPAD1_RIGHT = 1<<7, ++ DC_BTN_Z = 1<<8, ++ DC_BTN_Y = 1<<9, ++ DC_BTN_X = 1<<10, ++ DC_BTN_D = 1<<11, ++ DC_BTN_DPAD2_UP = 1<<12, ++ DC_BTN_DPAD2_DOWN = 1<<13, ++ DC_BTN_DPAD2_LEFT = 1<<14, ++ DC_BTN_DPAD2_RIGHT = 1<<15, + +- DC_AXIS_LT = 0X10000, +- DC_AXIS_RT = 0X10001, +- DC_AXIS_X = 0X20000, +- DC_AXIS_Y = 0X20001, ++ EMU_AXIS_NONE = 0X00000, ++ EMU_AXIS_DPAD1_X = 0X00001, ++ EMU_AXIS_DPAD1_Y = 0X00002, ++ EMU_AXIS_DPAD2_X = 0X00003, ++ EMU_AXIS_DPAD2_Y = 0X00004, ++ DC_AXIS_TRIGGER_LEFT = 0X10000, ++ DC_AXIS_TRIGGER_RIGHT = 0X10001, ++ DC_AXIS_X = 0X20000, ++ DC_AXIS_Y = 0X20001, + }; +diff -Nur a/core/linux-dist/mapping.cpp b/core/linux-dist/mapping.cpp +--- a/core/linux-dist/mapping.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mapping.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,159 @@ ++#include "linux-dist/mapping.h" ++#include "cfg/ini.h" ++ ++struct ButtonMap ++{ ++ InputButtonID id; ++ string section; ++ string option; ++}; ++ ++struct AxisMap ++{ ++ InputAxisID id; ++ string section; ++ string option; ++ string section_inverted; ++ string option_inverted; ++}; ++ ++static ButtonMap button_list[19] = { ++ { DC_BTN_A, "dreamcast", "btn_a" }, ++ { DC_BTN_B, "dreamcast", "btn_b" }, ++ { DC_BTN_C, "dreamcast", "btn_c" }, ++ { DC_BTN_D, "dreamcast", "btn_d" }, ++ { DC_BTN_X, "dreamcast", "btn_x" }, ++ { DC_BTN_Y, "dreamcast", "btn_y" }, ++ { DC_BTN_Z, "dreamcast", "btn_z" }, ++ { DC_BTN_START, "dreamcast", "btn_start" }, ++ { DC_BTN_DPAD1_LEFT, "dreamcast", "btn_dpad1_left" }, ++ { DC_BTN_DPAD1_RIGHT, "dreamcast", "btn_dpad1_right" }, ++ { DC_BTN_DPAD1_UP, "dreamcast", "btn_dpad1_up" }, ++ { DC_BTN_DPAD1_DOWN, "dreamcast", "btn_dpad1_down" }, ++ { DC_BTN_DPAD2_LEFT, "dreamcast", "btn_dpad2_left" }, ++ { DC_BTN_DPAD2_RIGHT, "dreamcast", "btn_dpad2_right" }, ++ { DC_BTN_DPAD2_UP, "dreamcast", "btn_dpad2_up" }, ++ { DC_BTN_DPAD2_DOWN, "dreamcast", "btn_dpad2_down" }, ++ { EMU_BTN_ESCAPE, "emulator", "btn_escape" }, ++ { EMU_BTN_TRIGGER_LEFT, "compat", "btn_trigger_left" }, ++ { EMU_BTN_TRIGGER_RIGHT, "compat", "btn_trigger_right" } ++}; ++ ++static AxisMap axis_list[8] = { ++ { DC_AXIS_X, "dreamcast", "axis_x", "compat", "axis_x_inverted" }, ++ { DC_AXIS_Y, "dreamcast", "axis_y", "compat", "axis_y_inverted" }, ++ { DC_AXIS_TRIGGER_LEFT, "dreamcast", "axis_trigger_left", "compat", "axis_trigger_left_inverted" }, ++ { DC_AXIS_TRIGGER_RIGHT, "dreamcast", "axis_trigger_right", "compat", "axis_trigger_right_inverted" }, ++ { EMU_AXIS_DPAD1_X, "compat", "axis_dpad1_x", "compat", "axis_dpad1_x_inverted" }, ++ { EMU_AXIS_DPAD1_Y, "compat", "axis_dpad1_y", "compat", "axis_dpad1_y_inverted" }, ++ { EMU_AXIS_DPAD2_X, "compat", "axis_dpad2_x", "compat", "axis_dpad2_x_inverted" }, ++ { EMU_AXIS_DPAD2_Y, "compat", "axis_dpad2_y", "compat", "axis_dpad2_y_inverted" } ++}; ++ ++const InputButtonID* InputMapping::get_button_id(InputButtonCode code) ++{ ++ return this->buttons.get_by_value(code); ++} ++ ++const InputButtonCode* InputMapping::get_button_code(InputButtonID id) ++{ ++ return this->buttons.get_by_key(id); ++} ++ ++void InputMapping::set_button(InputButtonID id, InputButtonCode code) ++{ ++ if(id != EMU_BTN_NONE) ++ { ++ this->buttons.insert(id, code); ++ } ++} ++ ++const InputAxisID* InputMapping::get_axis_id(InputAxisCode code) ++{ ++ return this->axes.get_by_value(code); ++} ++ ++const InputAxisCode* InputMapping::get_axis_code(InputAxisID id) ++{ ++ return this->axes.get_by_key(id); ++} ++ ++bool InputMapping::get_axis_inverted(InputAxisCode code) ++{ ++ std::map::iterator it = this->axes_inverted.find('b'); ++ if (it != this->axes_inverted.end()) ++ { ++ return it->second; ++ } ++ return false; ++} ++ ++void InputMapping::set_axis(InputAxisID id, InputAxisCode code, bool is_inverted) ++{ ++ if(id != EMU_AXIS_NONE) ++ { ++ this->axes.insert(id, code); ++ this->axes_inverted.insert(std::pair(code, is_inverted)); ++ } ++} ++ ++void InputMapping::load(FILE* fd) ++{ ++ ConfigFile mf; ++ mf.parse(fd); ++ ++ this->name = mf.get("emulator", "mapping_name", "").c_str(); ++ ++ int i; ++ for(i = 0; i < 19; i++) ++ { ++ InputButtonCode button_code = mf.get_int(button_list[i].section, button_list[i].option, -1); ++ if (button_code >= 0) ++ { ++ this->set_button(button_list[i].id, button_code); ++ } ++ } ++ ++ for(i = 0; i < 8; i++) ++ { ++ InputAxisCode axis_code = mf.get_int(axis_list[i].section, axis_list[i].option, -1); ++ if(axis_code >= 0) ++ { ++ this->set_axis(axis_list[i].id, axis_code, mf.get_bool(axis_list[i].section_inverted, axis_list[i].option_inverted, false)); ++ } ++ } ++} ++ ++void InputMapping::print() ++{ ++ int i; ++ ++ printf("\nMAPPING NAME: %s\n", this->name); ++ ++ puts("MAPPED BUTTONS:"); ++ for(i = 0; i < 19; i++) ++ { ++ const InputButtonCode* button_code = this->get_button_code(button_list[i].id); ++ if(button_code) ++ { ++ printf("%-18s = %d\n", button_list[i].option.c_str(), *button_code); ++ } ++ } ++ ++ puts("MAPPED AXES:"); ++ for(i = 0; i < 8; i++) ++ { ++ const InputAxisCode* axis_code = this->get_axis_code(axis_list[i].id); ++ if(axis_code) ++ { ++ printf("%-18s = %d", axis_list[i].option.c_str(), *axis_code); ++ if(this->get_axis_inverted(*axis_code)) ++ { ++ printf("%s", "(inverted)"); ++ } ++ printf("%s", "\n"); ++ } ++ } ++ puts(""); ++} ++ +diff -Nur a/core/linux-dist/mapping.h b/core/linux-dist/mapping.h +--- a/core/linux-dist/mapping.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mapping.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,32 @@ ++#pragma once ++#include ++#include "linux-dist/main.h" ++#include "linux-dist/bimap.h" ++ ++typedef DreamcastController InputButtonID; ++typedef DreamcastController InputAxisID; ++typedef int InputButtonCode; ++typedef int InputAxisCode; ++ ++class InputMapping ++{ ++ private: ++ SimpleBimap buttons; ++ SimpleBimap axes; ++ std::map axes_inverted; ++ ++ public: ++ const char* name; ++ ++ void set_button(InputButtonID id, InputButtonCode code); ++ const InputButtonID* get_button_id(InputButtonCode code); ++ const InputButtonCode* get_button_code(InputButtonID id); ++ ++ void set_axis(InputAxisID id, InputAxisCode code, bool inverted); ++ const InputAxisID* get_axis_id(InputAxisCode code); ++ const InputAxisCode* get_axis_code(InputAxisID id); ++ bool get_axis_inverted(InputAxisCode code); ++ ++ void load(FILE* file); ++ void print(); ++}; +diff -Nur a/core/linux-dist/mappingstore.cpp b/core/linux-dist/mappingstore.cpp +--- a/core/linux-dist/mappingstore.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mappingstore.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,61 @@ ++#include "mappingstore.h" ++#include ++ ++static std::string get_mapping_path(std::string filepath, std::string subdir) ++{ ++ if (filepath.empty()) ++ { ++ return ""; ++ } ++ ++ std::string new_filepath; ++ if (filepath.at(0) != '/') ++ { ++ // It's not an absolute path ++ std::string mapping_dir = "/mappings/"; ++ if(!subdir.empty()) ++ { ++ mapping_dir.append(subdir); ++ mapping_dir.append("/"); ++ } ++ filepath.insert(0, mapping_dir); ++ new_filepath = get_readonly_data_path(filepath); ++ } ++ else ++ { ++ new_filepath = filepath; ++ } ++ ++ // TODO: Some realpath magic? How portable is it? ++ ++ return new_filepath; ++} ++ ++InputMapping* InputMappingStore::get(std::string filepath, std::string subdir) ++{ ++ std::string full_filepath = get_mapping_path(filepath, subdir); ++ if(!full_filepath.empty()) ++ { ++ if(this->loaded_mappings.count(full_filepath) == 0) ++ { ++ // Mapping has not been loaded yet ++ FILE* fp = fopen(full_filepath.c_str(), "r"); ++ if(fp == NULL) ++ { ++ printf("Unable to open mapping file '%s': %s\n", full_filepath.c_str(), strerror(errno)); ++ } ++ else ++ { ++ InputMapping* mapping = new InputMapping(); ++ mapping->load(fp); ++ this->loaded_mappings.insert(std::pair(full_filepath, mapping)); ++ } ++ } ++ std::map::iterator it = loaded_mappings.find(full_filepath); ++ if(it != loaded_mappings.end()) ++ { ++ return it->second; ++ } ++ } ++ return NULL; ++} +\ No newline at end of file +diff -Nur a/core/linux-dist/mappingstore.h b/core/linux-dist/mappingstore.h +--- a/core/linux-dist/mappingstore.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/mappingstore.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,11 @@ ++#pragma once ++#include "mapping.h" ++#include ++ ++class InputMappingStore ++{ ++ private: ++ std::map loaded_mappings; ++ public: ++ InputMapping* get(std::string filepath, std::string subdir = ""); ++}; +diff -Nur a/core/linux-dist/proxy.cpp b/core/linux-dist/proxy.cpp +--- a/core/linux-dist/proxy.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/proxy.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,25 @@ ++#include "proxy.h" ++ ++InputHandlerProxy::~InputHandlerProxy() ++{ ++ //TODO ++} ++ ++void InputHandlerProxy::add(u32 port, InputHandler* handler) ++{ ++ if(handler != NULL) ++ { ++ this->handlers.insert(std::pair(port, handler)); ++ } ++} ++ ++void InputHandlerProxy::handle(u32 port) ++{ ++ std::pair range; ++ range = this->handlers.equal_range(port); ++ ++ for (InputHandlerStore::iterator it = range.first; it != range.second; ++it) ++ { ++ it->second->handle(); ++ } ++} +\ No newline at end of file +diff -Nur a/core/linux-dist/proxy.h b/core/linux-dist/proxy.h +--- a/core/linux-dist/proxy.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/linux-dist/proxy.h 2015-10-06 21:55:43.966475140 -0300 +@@ -0,0 +1,15 @@ ++#pragma once ++#include ++#include "types.h" ++#include "handler.h" ++ ++class InputHandlerProxy ++{ ++ typedef std::multimap InputHandlerStore; ++ private: ++ InputHandlerStore handlers; ++ public: ++ ~InputHandlerProxy(); ++ void add(u32 port, InputHandler* handler); ++ void handle(u32 port); ++}; +\ No newline at end of file +diff -Nur a/core/linux-dist/x11.cpp b/core/linux-dist/x11.cpp +--- a/core/linux-dist/x11.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/x11.cpp 2015-10-06 21:55:43.966475140 -0300 +@@ -112,11 +112,11 @@ + + void input_x11_init() + { +- x11_keymap[113] = DC_DPAD_LEFT; +- x11_keymap[114] = DC_DPAD_RIGHT; ++ x11_keymap[113] = DC_BTN_DPAD1_LEFT; ++ x11_keymap[114] = DC_BTN_DPAD1_RIGHT; + +- x11_keymap[111] = DC_DPAD_UP; +- x11_keymap[116] = DC_DPAD_DOWN; ++ x11_keymap[111] = DC_BTN_DPAD1_UP; ++ x11_keymap[116] = DC_BTN_DPAD1_DOWN; + + x11_keymap[53] = DC_BTN_X; + x11_keymap[54] = DC_BTN_B; diff --git a/pcr/reicast-git/loop-tracing.patch b/pcr/reicast-git/loop-tracing.patch new file mode 100644 index 000000000..2e2b5ea97 --- /dev/null +++ b/pcr/reicast-git/loop-tracing.patch @@ -0,0 +1,109 @@ +diff -Nur a/core/rec-x86/rec_x86_driver.cpp b/core/rec-x86/rec_x86_driver.cpp +--- a/core/rec-x86/rec_x86_driver.cpp 2015-10-06 21:43:53.045336422 -0300 ++++ b/core/rec-x86/rec_x86_driver.cpp 2015-10-06 21:56:33.125833142 -0300 +@@ -289,6 +289,94 @@ + } + + ++RuntimeBlockInfo* old_block; ++ ++u32 old_loop; ++u32 old_old_loop; ++#include ++ ++#include ++ ++u32 loops[RAM_SIZE]; ++u32 loops_cyc[RAM_SIZE]; ++u32 loops_hot[RAM_SIZE]; ++u32 loops_end[RAM_SIZE]; ++ ++ ++void print_loop_stats() { ++ ++ vector> vc; ++ int loopc = 0; ++ int loopo = 0; ++ ++ int ooc = 0; ++ int ooo = 0; ++ ++ for (int i = 0; i < RAM_SIZE; i += 2) { ++ if (loops_hot[i]) { ++ vc.push_back(pair(-loops_cyc[i], i)); ++ ++ loopc += loops[i]; ++ ++ loopo += loops_cyc[i]; ++ } ++ ++ ooc += loops[i]; ++ ooo += loops_cyc[i]; ++ } ++ ++ sort(vc.begin(), vc.end()); ++ ++ printf("%d loops, %d, %d, %.2f, %.2f\n", vc.size(), loopc, loopo, loopc *100.0 / 1000000, loopo * 100.0 / ooo); ++ ++ memset(loops, 0, sizeof(loops)); ++ memset(loops_cyc, 0, sizeof(loops_cyc)); ++ memset(loops_hot, 0, sizeof(loops_hot)); ++ memset(loops_end, 0, sizeof(loops_end)); ++} ++int counts = 10000; ++void DYNACALL ngen_enter(RuntimeBlockInfo* block) { ++ if (BET_GET_CLS(block->BlockType) == BET_CLS_Dynamic) ++ old_block = 0; ++ ++ if (old_block) { ++ if ((old_block->addr & RAM_MASK) >= (block->addr & RAM_MASK)) { ++ loops[RAM_MASK & block->addr]++; ++ loops_cyc[RAM_MASK & block->addr] += block->guest_cycles; ++ ++ loops_end[RAM_MASK & block->addr] = max(loops_end[RAM_MASK & block->addr], RAM_MASK & old_block->addr); ++ ++ if (!loops_hot[RAM_MASK & block->addr] && loops[RAM_MASK & block->addr] > 1000) { ++ //printf("HOT LOOP %08X\n", block->addr); ++ ++ loops_hot[RAM_MASK & block->addr] = 1; ++ } ++ ++ old_old_loop = old_loop; ++ old_loop = old_block->addr & RAM_MASK; ++ } ++ ++ else { ++ if ((block->addr & RAM_MASK) > loops_end[old_loop] && old_old_loop != -1) { ++ old_loop = old_old_loop; ++ old_old_loop = -1; ++ } ++ ++ if ((block->addr & RAM_MASK) <= loops_end[old_loop]) { ++ loops[old_loop] ++; ++ loops_cyc[old_loop] += block->guest_cycles; ++ } ++ } ++ } ++ ++ old_block = block; ++ ++ if (--counts < 0) { ++ counts = 10000000; ++ print_loop_stats(); ++ } ++} ++ + void ngen_Compile(RuntimeBlockInfo* block,bool force_checks, bool reset, bool staging,bool optimise) + { + //initialise stuff +@@ -306,6 +394,10 @@ + + block->code=(DynarecCodeEntryPtr)emit_GetCCPtr(); + ++ x86e->Emit(op_mov32, ECX, unat(block)); ++ ++ x86e->Emit(op_call, x86_ptr_imm(&ngen_enter)); ++ + x86e->Emit(op_add32,&memops_t,block->memops); + x86e->Emit(op_add32,&memops_l,block->linkedmemops); + diff --git a/pcr/reicast-git/loungekatt_rm-nonfree-fp.patch b/pcr/reicast-git/loungekatt_rm-nonfree-fp.patch new file mode 100644 index 000000000..9d0b588d9 --- /dev/null +++ b/pcr/reicast-git/loungekatt_rm-nonfree-fp.patch @@ -0,0 +1,1451 @@ +diff -Nur a/core/deps/libpng/fp.h b/core/deps/libpng/fp.h +--- a/core/deps/libpng/fp.h 2015-10-06 21:43:53.002336114 -0300 ++++ b/core/deps/libpng/fp.h 1969-12-31 21:00:00.000000000 -0300 +@@ -1,62 +0,0 @@ +-/* +-* Copyright (c) 1999 Apple Computer, Inc. All rights reserved. +-* +-* @APPLE_LICENSE_HEADER_START@ +-* +-* The contents of this file constitute Original Code as defined in and +-* are subject to the Apple Public Source License Version 1.1 (the +-* "License"). You may not use this file except in compliance with the +-* License. Please obtain a copy of the License at +-* http://www.apple.com/publicsource and read it before using this file. +-* +-* This Original Code and all software distributed under the License are +-* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER +-* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +-* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +-* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the +-* License for the specific language governing rights and limitations +-* under the License. +-* +-* @APPLE_LICENSE_HEADER_END@ +-*/ +-/* Copyright (c) 1992, NeXT Computer, Inc. All rights reserved. +-* +-* File: libc/m98k/gen/fp.h +-* Author: Derek B Clegg, NeXT Computer, Inc. +-* +-* HISTORY +-* 11-Nov-92 Derek B Clegg (dclegg@next.com) +-* Created. +-* +-* Common definitions for floating-point numbers. +-*/ +- +-/* The following definitions for for double precision IEEE format numbers. */ +- +-#define EXPONENT_BIAS 1023 +- +-#define SIGN_BITS 1 +-#define EXPONENT_BITS 11 +-#define FRACTION_BITS 52 +-#define HI_FRACTION_BITS 20 +-#define LO_FRACTION_BITS 32 +- +-struct double_format { +-unsigned sign: SIGN_BITS; +-unsigned exponent: EXPONENT_BITS; +-unsigned hi_fraction: HI_FRACTION_BITS; +-unsigned lo_fraction: LO_FRACTION_BITS; +-}; +- +-union dbl { +-struct double_format s; +-unsigned int u[2]; +-double value; +-}; +- +-#define PlusInfinity (1.0/0.0) +-#define MinusInfinity (-1.0/0.0) +- +-#define not_a_number(x) ((x) != (x)) +-#define positive_infinity(x) ((x) == PlusInfinity) +-#define negative_infinity(x) ((x) == MinusInfinity) +Binary files a/shell/apple/emulator-ios/emulator/assets/Icon@2x.png and b/shell/apple/emulator-ios/emulator/assets/Icon@2x.png differ +Binary files a/shell/apple/emulator-ios/emulator/assets/Icon-72@2x.png and b/shell/apple/emulator-ios/emulator/assets/Icon-72@2x.png differ +Binary files a/shell/apple/emulator-ios/emulator/assets/Icon-72.png and b/shell/apple/emulator-ios/emulator/assets/Icon-72.png differ +Binary files a/shell/apple/emulator-ios/emulator/assets/Icon.png and b/shell/apple/emulator-ios/emulator/assets/Icon.png differ +diff -Nur a/shell/apple/emulator-ios/emulator/DiskViewCell.h b/shell/apple/emulator-ios/emulator/DiskViewCell.h +--- a/shell/apple/emulator-ios/emulator/DiskViewCell.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/shell/apple/emulator-ios/emulator/DiskViewCell.h 2015-10-06 22:10:31.206968127 -0300 +@@ -0,0 +1,8 @@ ++#import ++ ++@interface DiskViewCell : UITableViewCell ++ ++@property (nonatomic, retain) IBOutlet UIImageView *diskImage; ++@property (nonatomic, retain) IBOutlet UILabel *nameLabel; ++ ++@end +diff -Nur a/shell/apple/emulator-ios/emulator/DiskViewCell.m b/shell/apple/emulator-ios/emulator/DiskViewCell.m +--- a/shell/apple/emulator-ios/emulator/DiskViewCell.m 1969-12-31 21:00:00.000000000 -0300 ++++ b/shell/apple/emulator-ios/emulator/DiskViewCell.m 2015-10-06 22:10:31.206968127 -0300 +@@ -0,0 +1,26 @@ ++#import "DiskViewCell.h" ++ ++@implementation DiskViewCell ++ ++- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier ++{ ++ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; ++ if (self) { ++ // Initialization code ++ } ++ return self; ++} ++ ++- (void)awakeFromNib ++{ ++ // Initialization code ++} ++ ++- (void)setSelected:(BOOL)selected animated:(BOOL)animated ++{ ++ [super setSelected:selected animated:animated]; ++ ++ // Configure the view for the selected state ++} ++ ++@end +diff -Nur a/shell/apple/emulator-ios/emulator/EmulatorViewController.h b/shell/apple/emulator-ios/emulator/EmulatorViewController.h +--- a/shell/apple/emulator-ios/emulator/EmulatorViewController.h 2015-10-06 21:43:53.121336967 -0300 ++++ b/shell/apple/emulator-ios/emulator/EmulatorViewController.h 2015-10-06 22:10:31.206968127 -0300 +@@ -10,10 +10,18 @@ + #import + #import + #import "iCadeReaderView.h" ++#import "PadViewController.h" ++#import "EmulatorView.h" + +-@interface ViewController : GLKViewController ++@interface EmulatorViewController : GLKViewController + ++@property NSString* diskImage; + @property (nonatomic) iCadeReaderView* iCadeReader; + @property (nonatomic) GCController *gController __attribute__((weak_import)); ++@property (nonatomic, strong) id connectObserver; ++@property (nonatomic, strong) id disconnectObserver; ++@property (nonatomic, strong) EmulatorView *emuView; ++ ++@property (nonatomic, strong) PadViewController *controllerView; + + @end +diff -Nur a/shell/apple/emulator-ios/emulator/EmulatorViewController.mm b/shell/apple/emulator-ios/emulator/EmulatorViewController.mm +--- a/shell/apple/emulator-ios/emulator/EmulatorViewController.mm 2015-10-06 21:43:53.121336967 -0300 ++++ b/shell/apple/emulator-ios/emulator/EmulatorViewController.mm 2015-10-06 22:10:31.206968127 -0300 +@@ -16,7 +16,7 @@ + #include "hw/maple/maple_devs.h" + #include "hw/maple/maple_if.h" + +-@interface ViewController () { ++@interface EmulatorViewController () { + } + + @property (strong, nonatomic) EAGLContext *context; +@@ -35,25 +35,34 @@ + extern "C" int reicast_main(int argc, char* argv[]); + + +-@implementation ViewController ++@implementation EmulatorViewController + + -(void)emuThread + { + install_prof_handler(1); +- + +- //This looks like the right place, rite? +- char text[2]=""; +- +- char* prms[2]; +- prms[0]=text; +- +- reicast_main(1, prms); ++ char *Args[3]; ++ const char *P; ++ ++ P = (const char *)[self.diskImage UTF8String]; ++ Args[0] = "dc"; ++ Args[1] = "-config"; ++ Args[2] = P&&P[0]? (char *)malloc(strlen(P)+32):0; ++ ++ if(Args[2]) ++ { ++ strcpy(Args[2],"config:image="); ++ strcat(Args[2],P); ++ } ++ ++ reicast_main(Args[2]? 3:1,Args); + } + + - (void)viewDidLoad + { + [super viewDidLoad]; ++ ++ self.controllerView = [[PadViewController alloc] initWithNibName:@"PadViewController" bundle:nil]; + + self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + +@@ -61,15 +70,33 @@ + NSLog(@"Failed to create ES context"); + } + +- GLKView *view = (GLKView *)self.view; +- view.context = self.context; +- view.drawableDepthFormat = GLKViewDrawableDepthFormat24; ++ self.emuView = (EmulatorView *)self.view; ++ self.emuView.context = self.context; ++ self.emuView.drawableDepthFormat = GLKViewDrawableDepthFormat24; + +- self.iCadeReader = [[iCadeReaderView alloc] init]; +- [self.view addSubview:self.iCadeReader]; +- self.iCadeReader.delegate = self; +- self.iCadeReader.active = YES; ++ [self.controllerView setControlOutput:self.emuView]; + ++ self.connectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { ++ if ([[GCController controllers] count] == 1) { ++ [self toggleHardwareController:YES]; ++ } ++ }]; ++ self.disconnectObserver = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { ++ if (![[GCController controllers] count]) { ++ [self toggleHardwareController:NO]; ++ } ++ }]; ++ ++ if ([[GCController controllers] count]) { ++ [self toggleHardwareController:YES]; ++ } ++ [self.controllerView showController:self.view]; ++ ++ self.iCadeReader = [[iCadeReaderView alloc] init]; ++ [self.view addSubview:self.iCadeReader]; ++ self.iCadeReader.delegate = self; ++ self.iCadeReader.active = YES; ++ + [self setupGL]; + + if (!gles_init()) +@@ -82,7 +109,7 @@ + } + + - (void)dealloc +-{ ++{ + [self tearDownGL]; + + if ([EAGLContext currentContext] == self.context) { +@@ -127,6 +154,126 @@ + + } + ++- (void)toggleHardwareController:(BOOL)useHardware { ++ if (useHardware) { ++// [self.controllerView hideController]; ++ self.gController = [GCController controllers][0]; ++ if (self.gController.gamepad) { ++ [self.gController.gamepad.buttonA setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_a]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_a]; ++ } ++ }]; ++ [self.gController.gamepad.buttonB setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_b]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_b]; ++ } ++ }]; ++ [self.gController.gamepad.buttonX setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_x]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_x]; ++ } ++ }]; ++ [self.gController.gamepad.buttonY setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_y]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_y]; ++ } ++ }]; ++ [self.gController.gamepad.dpad setValueChangedHandler:^(GCControllerDirectionPad *dpad, float xValue, float yValue){ ++ if (xValue >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_r]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_r]; ++ } ++ if (xValue <= -0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_l]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_l]; ++ } ++ if (yValue >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_u]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_u]; ++ } ++ if (yValue <= -0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_d]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_d]; ++ } ++ }]; ++ //Add controller pause handler here ++ } ++ if (self.gController.extendedGamepad) { ++ [self.gController.extendedGamepad.buttonA setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_a]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_a]; ++ } ++ }]; ++ [self.gController.extendedGamepad.buttonB setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_b]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_b]; ++ } ++ }]; ++ [self.gController.extendedGamepad.buttonX setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_x]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_x]; ++ } ++ }]; ++ [self.gController.extendedGamepad.buttonY setValueChangedHandler:^(GCControllerButtonInput *button, float value, BOOL pressed) { ++ if (pressed && value >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_abxy_y]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_abxy_y]; ++ } ++ }]; ++ [self.gController.extendedGamepad.dpad setValueChangedHandler:^(GCControllerDirectionPad *dpad, float xValue, float yValue){ ++ if (xValue >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_r]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_r]; ++ } ++ if (xValue <= -0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_l]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_l]; ++ } ++ if (yValue >= 0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_u]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_u]; ++ } ++ if (yValue <= -0.1) { ++ [self.emuView handleKeyDown:self.controllerView.img_dpad_d]; ++ } else { ++ [self.emuView handleKeyUp:self.controllerView.img_dpad_d]; ++ } ++ }]; ++ [self.gController.extendedGamepad.leftThumbstick.xAxis setValueChangedHandler:^(GCControllerAxisInput *axis, float value){ ++ ++ }]; ++ [self.gController.extendedGamepad.leftThumbstick.yAxis setValueChangedHandler:^(GCControllerAxisInput *axis, float value){ ++ ++ }]; ++ } ++ } else { ++ self.gController = nil; ++// [self.controllerView showController:self.view]; ++ } ++} + + - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect + { +diff -Nur a/shell/apple/emulator-ios/emulator/EmulatorView.h b/shell/apple/emulator-ios/emulator/EmulatorView.h +--- a/shell/apple/emulator-ios/emulator/EmulatorView.h 2015-10-06 21:43:53.121336967 -0300 ++++ b/shell/apple/emulator-ios/emulator/EmulatorView.h 2015-10-06 22:10:31.206968127 -0300 +@@ -10,4 +10,9 @@ + + @interface EmulatorView : GLKView + ++- (void)handleKeyDown:(UIButton*)button; ++- (void)handleKeyUp:(UIButton*)button; ++ ++@property (nonatomic, strong) UIViewController *controllerView; ++ + @end +diff -Nur a/shell/apple/emulator-ios/emulator/EmulatorView.mm b/shell/apple/emulator-ios/emulator/EmulatorView.mm +--- a/shell/apple/emulator-ios/emulator/EmulatorView.mm 2015-10-06 21:43:53.121336967 -0300 ++++ b/shell/apple/emulator-ios/emulator/EmulatorView.mm 2015-10-06 22:10:31.206968127 -0300 +@@ -7,6 +7,7 @@ + // + + #import "EmulatorView.h" ++#import "PadViewController.h" + + #include "types.h" + +@@ -15,11 +16,27 @@ + extern s8 joyx[4],joyy[4]; + extern u8 rt[4],lt[4]; + +-#define key_CONT_A (1 << 2) +-#define key_CONT_START (1 << 3) +-#define key_CONT_DPAD_LEFT (1 << 6) +- +-int dpad_or_btn = 0; ++#define DC_BTN_C (1) ++#define DC_BTN_B (1<<1) ++#define DC_BTN_A (1<<2) ++#define DC_BTN_START (1<<3) ++#define DC_DPAD_UP (1<<4) ++#define DC_DPAD_DOWN (1<<5) ++#define DC_DPAD_LEFT (1<<6) ++#define DC_DPAD_RIGHT (1<<7) ++#define DC_BTN_Z (1<<8) ++#define DC_BTN_Y (1<<9) ++#define DC_BTN_X (1<<10) ++#define DC_BTN_D (1<<11) ++#define DC_DPAD2_UP (1<<12) ++#define DC_DPAD2_DOWN (1<<13) ++#define DC_DPAD2_LEFT (1<<14) ++#define DC_DPAD2_RIGHT (1<<15) ++ ++#define DC_AXIS_LT (0X10000) ++#define DC_AXIS_RT (0X10001) ++#define DC_AXIS_X (0X20000) ++#define DC_AXIS_Y (0X20001) + + @implementation EmulatorView + +@@ -31,23 +48,85 @@ + } + */ + +--(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { +- +- if (dpad_or_btn &1) +- kcode[0] &= ~(key_CONT_START|key_CONT_A); +- else +- kcode[0] &= ~(key_CONT_DPAD_LEFT); ++- (void)setControlInput:(PadViewController *)input ++{ ++ self.controllerView = input; ++} ++ ++- (void)handleKeyDown:(UIButton*)button ++{ ++ PadViewController * controller = (PadViewController *)self.controllerView; ++ if (button == controller.img_dpad_l) { ++ kcode[0] &= ~(DC_DPAD_LEFT); ++ } ++ if (button == controller.img_dpad_r) { ++ kcode[0] &= ~(DC_DPAD_RIGHT); ++ } ++ if (button == controller.img_dpad_u) { ++ kcode[0] &= ~(DC_DPAD_UP); ++ } ++ if (button == controller.img_dpad_d) { ++ kcode[0] &= ~(DC_DPAD_DOWN); ++ } ++ if (button == controller.img_abxy_a) { ++ kcode[0] &= ~(DC_BTN_A); ++ } ++ if (button == controller.img_abxy_b) { ++ kcode[0] &= ~(DC_BTN_B); ++ } ++ if (button == controller.img_abxy_x) { ++ kcode[0] &= ~(DC_BTN_X); ++ } ++ if (button == controller.img_abxy_y) { ++ kcode[0] &= ~(DC_BTN_Y); ++ } ++ if (button == controller.img_lt) { ++ kcode[0] &= ~(DC_AXIS_LT); ++ } ++ if (button == controller.img_rt) { ++ kcode[0] &= ~(DC_AXIS_RT); ++ } ++ if (button == controller.img_start) { ++ kcode[0] &= ~(DC_BTN_START); ++ } + } + +--(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { +- +- // [event allTouches]; +- +- if (dpad_or_btn &1) +- kcode[0] |= (key_CONT_START|key_CONT_A); +- else +- kcode[0] |= (key_CONT_DPAD_LEFT); +- +- dpad_or_btn++; ++- (void)handleKeyUp:(UIButton*)button ++{ ++ PadViewController * controller = (PadViewController *)self.controllerView; ++ if (button == controller.img_dpad_l) { ++ kcode[0] |= ~(DC_DPAD_LEFT); ++ } ++ if (button == controller.img_dpad_r) { ++ kcode[0] |= ~(DC_DPAD_RIGHT); ++ } ++ if (button == controller.img_dpad_u) { ++ kcode[0] |= ~(DC_DPAD_UP); ++ } ++ if (button == controller.img_dpad_d) { ++ kcode[0] |= ~(DC_DPAD_DOWN); ++ } ++ if (button == controller.img_abxy_a) { ++ kcode[0] |= (DC_BTN_A); ++ } ++ if (button == controller.img_abxy_b) { ++ kcode[0] |= (DC_BTN_B); ++ } ++ if (button == controller.img_abxy_x) { ++ kcode[0] |= (DC_BTN_X); ++ } ++ if (button == controller.img_abxy_y) { ++ kcode[0] |= (DC_BTN_Y); ++ } ++ if (button == controller.img_lt) { ++ kcode[0] |= (DC_AXIS_LT); ++ } ++ if (button == controller.img_rt) { ++ kcode[0] |= (DC_AXIS_RT); ++ } ++ if (button == controller.img_start) { ++ kcode[0] |= (DC_BTN_START); ++ } + } ++ + @end +Binary files a/shell/apple/emulator-ios/emulator/Images/disk_unknown.png and b/shell/apple/emulator-ios/emulator/Images/disk_unknown.png differ +diff -Nur a/shell/apple/emulator-ios/emulator/MainStoryboard.storyboard b/shell/apple/emulator-ios/emulator/MainStoryboard.storyboard +--- a/shell/apple/emulator-ios/emulator/MainStoryboard.storyboard 2015-10-06 21:43:53.123336981 -0300 ++++ b/shell/apple/emulator-ios/emulator/MainStoryboard.storyboard 2015-10-06 22:10:31.207968135 -0300 +@@ -1,32 +1,100 @@ + +- ++ + +- ++ + + +- ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + +- +- ++ ++ + + +- ++ ++ ++ ++ + + ++ + + + + +- +- +- +- +- + + + + ++ ++ ++ + + + +diff -Nur a/shell/apple/emulator-ios/emulator/PadViewController.h b/shell/apple/emulator-ios/emulator/PadViewController.h +--- a/shell/apple/emulator-ios/emulator/PadViewController.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/shell/apple/emulator-ios/emulator/PadViewController.h 2015-10-06 22:10:31.207968135 -0300 +@@ -0,0 +1,34 @@ ++// ++// PadViewController.h ++// reicast-ios ++// ++// Created by Lounge Katt on 8/25/15. ++// Copyright (c) 2015 reicast. All rights reserved. ++// ++ ++#import ++#import "EmulatorView.h" ++ ++@interface PadViewController : UIViewController ++ ++@property (nonatomic, strong) IBOutlet UIButton* img_dpad_l; ++@property (nonatomic, strong) IBOutlet UIButton* img_dpad_r; ++@property (nonatomic, strong) IBOutlet UIButton* img_dpad_u; ++@property (nonatomic, strong) IBOutlet UIButton* img_dpad_d; ++@property (nonatomic, strong) IBOutlet UIButton* img_abxy_a; ++@property (nonatomic, strong) IBOutlet UIButton* img_abxy_b; ++@property (nonatomic, strong) IBOutlet UIButton* img_abxy_x; ++@property (nonatomic, strong) IBOutlet UIButton* img_abxy_y; ++@property (nonatomic, strong) IBOutlet UIButton* img_vjoy; ++@property (nonatomic, strong) IBOutlet UIButton* img_lt; ++@property (nonatomic, strong) IBOutlet UIButton* img_rt; ++@property (nonatomic, strong) IBOutlet UIButton* img_start; ++ ++@property (nonatomic, strong) EmulatorView *handler; ++ ++- (void) showController:(UIView *)parentView; ++- (void) hideController; ++- (BOOL) isControllerVisible; ++- (void) setControlOutput:(EmulatorView *)output; ++ ++@end +diff -Nur a/shell/apple/emulator-ios/emulator/PadViewController.m b/shell/apple/emulator-ios/emulator/PadViewController.m +--- a/shell/apple/emulator-ios/emulator/PadViewController.m 1969-12-31 21:00:00.000000000 -0300 ++++ b/shell/apple/emulator-ios/emulator/PadViewController.m 2015-10-06 22:10:31.207968135 -0300 +@@ -0,0 +1,78 @@ ++// ++// PadViewController.m ++// reicast-ios ++// ++// Created by Lounge Katt on 8/25/15. ++// Copyright (c) 2015 reicast. All rights reserved. ++// ++ ++#import "PadViewController.h" ++#import "EmulatorView.h" ++ ++@interface PadViewController () ++ ++@end ++ ++@implementation PadViewController ++ ++- (void)viewDidLoad { ++ [super viewDidLoad]; ++} ++ ++- (void)didReceiveMemoryWarning { ++ [super didReceiveMemoryWarning]; ++ // Dispose of any resources that can be recreated. ++} ++ ++- (void)showController:(UIView *)parentView ++{ ++ [parentView addSubview:self.view]; ++} ++ ++- (void)hideController ++{ ++ [self.view removeFromSuperview]; ++} ++ ++- (BOOL)isControllerVisible { ++ if (self.view.window != nil) { ++ return YES; ++ } ++ return NO; ++} ++ ++- (void)setControlOutput:(EmulatorView *)output ++{ ++ self.handler = output; ++} ++ ++- (IBAction)keycodeDown:(id)sender ++{ ++ [self.handler handleKeyDown:(UIButton*)sender]; ++} ++ ++- (IBAction)keycodeUp:(id)sender ++{ ++ [self.handler handleKeyUp:(UIButton*)sender]; ++} ++ ++- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil ++{ ++ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; ++ if (self) { ++ // Custom initialization ++ } ++ return self; ++} ++ ++/* ++#pragma mark - Navigation ++ ++// In a storyboard-based application, you will often want to do a little preparation before navigation ++- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { ++ // Get the new view controller using [segue destinationViewController]. ++ // Pass the selected object to the new view controller. ++} ++*/ ++ ++@end +diff -Nur a/shell/apple/emulator-ios/emulator/PadViewController.xib b/shell/apple/emulator-ios/emulator/PadViewController.xib +--- a/shell/apple/emulator-ios/emulator/PadViewController.xib 1969-12-31 21:00:00.000000000 -0300 ++++ b/shell/apple/emulator-ios/emulator/PadViewController.xib 2015-10-06 22:10:31.207968135 -0300 +@@ -0,0 +1,197 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff -Nur a/shell/apple/emulator-ios/emulator/PathsViewController.h b/shell/apple/emulator-ios/emulator/PathsViewController.h +--- a/shell/apple/emulator-ios/emulator/PathsViewController.h 2015-10-06 21:43:53.123336981 -0300 ++++ b/shell/apple/emulator-ios/emulator/PathsViewController.h 2015-10-06 22:10:31.207968135 -0300 +@@ -8,7 +8,9 @@ + + #import + +-@interface PathsViewController : UITableViewController ++@interface PathsViewController : UITableViewController + @property (weak, nonatomic) IBOutlet UIBarButtonItem *sidebarButton; + ++@property (nonatomic, strong) NSMutableArray* diskImages; ++ + @end +diff -Nur a/shell/apple/emulator-ios/emulator/PathsViewController.m b/shell/apple/emulator-ios/emulator/PathsViewController.m +--- a/shell/apple/emulator-ios/emulator/PathsViewController.m 2015-10-06 21:43:53.123336981 -0300 ++++ b/shell/apple/emulator-ios/emulator/PathsViewController.m 2015-10-06 22:10:31.207968135 -0300 +@@ -7,7 +7,9 @@ + // + + #import "PathsViewController.h" +-#import "SWRevealViewController.h" ++//#import "SWRevealViewController.h" ++#import "EmulatorViewController.h" ++#import "DiskViewCell.h" + + @interface PathsViewController () + +@@ -24,22 +26,32 @@ + return self; + } + ++- (NSURL *)documents ++{ ++ return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; ++} ++ + - (void)viewDidLoad + { + [super viewDidLoad]; + self.title = @"Paths"; + + // Set the side bar button action. When it's tapped, it'll show up the sidebar. +- _sidebarButton.target = self.revealViewController; +- _sidebarButton.action = @selector(revealToggle:); +- ++// _sidebarButton.target = self.revealViewController; ++// _sidebarButton.action = @selector(revealToggle:); ++ + // Set the gesture +- [self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer]; ++// [self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer]; + // Uncomment the following line to preserve selection between presentations. + // self.clearsSelectionOnViewWillAppear = NO; + + // Uncomment the following line to display an Edit button in the navigation bar for this view controller. + // self.navigationItem.rightBarButtonItem = self.editButtonItem; ++ ++ self.diskImages = [[NSMutableArray alloc] init]; ++ NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[self documents].path error:NULL]; ++ NSPredicate *diskPredicate = [NSPredicate predicateWithFormat:@"self ENDSWITH '.chd' || self ENDSWITH '.gdi' || self ENDSWITH '.cdi' || self ENDSWITH '.CHD' || self ENDSWITH '.GDI' || self ENDSWITH '.CDI'"]; ++ self.diskImages = [NSMutableArray arrayWithArray:[files filteredArrayUsingPredicate:diskPredicate]]; + } + + - (void)didReceiveMemoryWarning +@@ -50,6 +62,52 @@ + + #pragma mark - Table view data source + +-// TODO: paths view controller logic ++-(NSInteger)numberOfSectionsInTableView: (UITableView*)tableView ++{ ++ return 1; ++} ++ ++-(NSInteger)tableView: (UITableView *)tableView numberOfRowsInSection: (NSInteger)section ++{ ++ return [self.diskImages count]; ++} ++ ++-(NSString*)tableView: (UITableView*)tableView titleForHeaderInSection: (NSInteger)section ++{ ++ return @""; ++} ++ ++- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { ++ return 80; ++ // Assign the specific cell height to prevent issues with custom size ++} ++ ++-(UITableViewCell*)tableView: (UITableView*)tableView cellForRowAtIndexPath: (NSIndexPath*)indexPath ++{ ++ static NSString *CellIdentifier = @"Cell"; ++ ++ DiskViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; ++ NSString* imagePath = [self.diskImages objectAtIndex: indexPath.row]; ++ ++ cell.nameLabel.text = [[imagePath lastPathComponent] stringByDeletingPathExtension]; ++ ++ return cell; ++} ++ ++-(void)prepareForSegue: (UIStoryboardSegue*)segue sender: (id)sender ++{ ++ if ([segue.identifier isEqualToString:@"emulatorView"]) { ++ NSIndexPath* indexPath = self.tableView.indexPathForSelectedRow; ++ NSString* filePath = [self.diskImages objectAtIndex: indexPath.row]; ++ NSString* diskPath = [[self documents].path stringByAppendingPathComponent: filePath]; ++ EmulatorViewController* emulatorView = segue.destinationViewController; ++ emulatorView.diskImage = diskPath; ++ } ++} ++ ++-(void)tableView: (UITableView*)tableView didSelectRowAtIndexPath: (NSIndexPath*)indexPath ++{ ++ [self performSegueWithIdentifier: @"emulatorView" sender: self]; ++} + + @end +diff -Nur a/shell/apple/emulator-ios/emulator/reicast-ios-Info.plist b/shell/apple/emulator-ios/emulator/reicast-ios-Info.plist +--- a/shell/apple/emulator-ios/emulator/reicast-ios-Info.plist 2015-10-06 21:43:53.124336988 -0300 ++++ b/shell/apple/emulator-ios/emulator/reicast-ios-Info.plist 2015-10-06 22:10:31.207968135 -0300 +@@ -8,13 +8,6 @@ + Reicast + CFBundleExecutable + ${EXECUTABLE_NAME} +- CFBundleIconFiles +- +- emulator/assets/Icon-72.png +- emulator/assets/Icon-72@2x.png +- emulator/assets/Icon.png +- emulator/assets/Icon@2x.png +- + CFBundleIdentifier + com.reicast.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion +diff -Nur a/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Contents.json b/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Contents.json +--- a/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Contents.json 1969-12-31 21:00:00.000000000 -0300 ++++ b/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Contents.json 2015-10-06 22:10:31.209968149 -0300 +@@ -0,0 +1,60 @@ ++{ ++ "images" : [ ++ { ++ "idiom" : "iphone", ++ "size" : "29x29", ++ "scale" : "2x" ++ }, ++ { ++ "idiom" : "iphone", ++ "size" : "40x40", ++ "scale" : "2x" ++ }, ++ { ++ "size" : "60x60", ++ "idiom" : "iphone", ++ "filename" : "Icon-60@2x.png", ++ "scale" : "2x" ++ }, ++ { ++ "idiom" : "iphone", ++ "size" : "60x60", ++ "scale" : "3x" ++ }, ++ { ++ "idiom" : "ipad", ++ "size" : "29x29", ++ "scale" : "1x" ++ }, ++ { ++ "idiom" : "ipad", ++ "size" : "29x29", ++ "scale" : "2x" ++ }, ++ { ++ "idiom" : "ipad", ++ "size" : "40x40", ++ "scale" : "1x" ++ }, ++ { ++ "idiom" : "ipad", ++ "size" : "40x40", ++ "scale" : "2x" ++ }, ++ { ++ "idiom" : "ipad", ++ "size" : "76x76", ++ "scale" : "1x" ++ }, ++ { ++ "size" : "76x76", ++ "idiom" : "ipad", ++ "filename" : "Icon-76@2x.png", ++ "scale" : "2x" ++ } ++ ], ++ "info" : { ++ "version" : 1, ++ "author" : "xcode" ++ } ++} +\ No newline at end of file +Binary files a/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png and b/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ +Binary files a/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png and b/shell/apple/emulator-ios/reicast-ios/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png differ +diff -Nur a/shell/apple/emulator-ios/reicast-ios/Images.xcassets/LaunchImage.launchimage/Contents.json b/shell/apple/emulator-ios/reicast-ios/Images.xcassets/LaunchImage.launchimage/Contents.json +--- a/shell/apple/emulator-ios/reicast-ios/Images.xcassets/LaunchImage.launchimage/Contents.json 1969-12-31 21:00:00.000000000 -0300 ++++ b/shell/apple/emulator-ios/reicast-ios/Images.xcassets/LaunchImage.launchimage/Contents.json 2015-10-06 22:10:31.209968149 -0300 +@@ -0,0 +1,49 @@ ++{ ++ "images" : [ ++ { ++ "orientation" : "portrait", ++ "idiom" : "ipad", ++ "minimum-system-version" : "7.0", ++ "extent" : "full-screen", ++ "scale" : "2x" ++ }, ++ { ++ "orientation" : "landscape", ++ "idiom" : "ipad", ++ "minimum-system-version" : "7.0", ++ "extent" : "full-screen", ++ "scale" : "1x" ++ }, ++ { ++ "orientation" : "landscape", ++ "idiom" : "ipad", ++ "minimum-system-version" : "7.0", ++ "extent" : "full-screen", ++ "scale" : "2x" ++ }, ++ { ++ "orientation" : "portrait", ++ "idiom" : "iphone", ++ "minimum-system-version" : "7.0", ++ "scale" : "2x" ++ }, ++ { ++ "orientation" : "portrait", ++ "idiom" : "iphone", ++ "minimum-system-version" : "7.0", ++ "subtype" : "retina4", ++ "scale" : "2x" ++ }, ++ { ++ "orientation" : "portrait", ++ "idiom" : "ipad", ++ "minimum-system-version" : "7.0", ++ "extent" : "full-screen", ++ "scale" : "1x" ++ } ++ ], ++ "info" : { ++ "version" : 1, ++ "author" : "xcode" ++ } ++} +\ No newline at end of file +diff -Nur a/shell/apple/emulator-ios/reicast-ios.xcodeproj/project.pbxproj b/shell/apple/emulator-ios/reicast-ios.xcodeproj/project.pbxproj +--- a/shell/apple/emulator-ios/reicast-ios.xcodeproj/project.pbxproj 2015-10-06 21:43:53.125336995 -0300 ++++ b/shell/apple/emulator-ios/reicast-ios.xcodeproj/project.pbxproj 2015-10-06 22:10:31.209968149 -0300 +@@ -50,6 +50,9 @@ + 877652C61B6157BD00437F10 /* audiostream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 877652BF1B6157BD00437F10 /* audiostream.cpp */; }; + 877652C91B6157FC00437F10 /* ngen_arm.S in Sources */ = {isa = PBXBuildFile; fileRef = 877652C71B6157FC00437F10 /* ngen_arm.S */; }; + 877652CA1B6157FC00437F10 /* rec_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 877652C81B6157FC00437F10 /* rec_arm.cpp */; }; ++ 878B0CFC1B8BB5B400A8D1C5 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 878B0CFB1B8BB5B400A8D1C5 /* Images.xcassets */; }; ++ 878B0D001B8BFE6200A8D1C5 /* disk_unknown.png in Resources */ = {isa = PBXBuildFile; fileRef = 878B0CFF1B8BFE6200A8D1C5 /* disk_unknown.png */; }; ++ 8794D9C31B88F3D600B1B3A3 /* DiskViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8794D9C21B88F3D600B1B3A3 /* DiskViewCell.m */; }; + 87C208D71B7A4BFA00638BDD /* AboutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87C208C61B7A4BFA00638BDD /* AboutViewController.m */; }; + 87C208D81B7A4BFA00638BDD /* BrowserTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87C208C81B7A4BFA00638BDD /* BrowserTableViewController.m */; }; + 87C208D91B7A4BFA00638BDD /* CloudVMUViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87C208CA1B7A4BFA00638BDD /* CloudVMUViewController.m */; }; +@@ -87,10 +90,8 @@ + 87D92F4E1B7A1B5700D8FD9E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 87D92F4D1B7A1B5700D8FD9E /* GameController.framework */; }; + 87D92F541B7A1BB100D8FD9E /* iCadeReaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 87D92F511B7A1BB100D8FD9E /* iCadeReaderView.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + 87D92F551B7A1BB100D8FD9E /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 87D92F531B7A1BB100D8FD9E /* LICENSE */; }; +- 87DCDB251B7EE57D0054D67C /* Icon-72.png in Resources */ = {isa = PBXBuildFile; fileRef = 8703BC371A44B8DA00E7E939 /* Icon-72.png */; }; +- 87DCDB261B7EE5850054D67C /* Icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8703BC381A44B8DA00E7E939 /* Icon-72@2x.png */; }; +- 87DCDB271B7EE5850054D67C /* Icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 8703BC391A44B8DA00E7E939 /* Icon.png */; }; +- 87DCDB281B7EE5850054D67C /* Icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8703BC3A1A44B8DA00E7E939 /* Icon@2x.png */; }; ++ 87FA52E91B8CE18600CEFC32 /* PadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 87FA52E71B8CE18600CEFC32 /* PadViewController.m */; }; ++ 87FA52EA1B8CE18600CEFC32 /* PadViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 87FA52E81B8CE18600CEFC32 /* PadViewController.xib */; }; + 9C7A393318C804A80070BB5F /* reicast.entitlements in Resources */ = {isa = PBXBuildFile; fileRef = 9C7A393218C804A80070BB5F /* reicast.entitlements */; }; + 9C7A3AA218C806E00070BB5F /* cfg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C7A395118C806DE0070BB5F /* cfg.cpp */; }; + 9C7A3AA318C806E00070BB5F /* cl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9C7A395318C806DE0070BB5F /* cl.cpp */; }; +@@ -244,7 +245,6 @@ + 84967C751B8F492C005F1140 /* filter_neon.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = filter_neon.S; sourceTree = ""; }; + 84967C761B8F492C005F1140 /* filter_neon_intrinsics.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = filter_neon_intrinsics.c; sourceTree = ""; }; + 84967C771B8F492C005F1140 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; +- 84967C781B8F492C005F1140 /* fp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fp.h; sourceTree = ""; }; + 84967C791B8F492C005F1140 /* png.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = png.c; sourceTree = ""; }; + 84967C7A1B8F492C005F1140 /* png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = png.h; sourceTree = ""; }; + 84967C7B1B8F492C005F1140 /* pngconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngconf.h; sourceTree = ""; }; +@@ -282,10 +282,6 @@ + 849C0D6A1B072D14008BAAA4 /* gdrom_hle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gdrom_hle.h; path = reios/gdrom_hle.h; sourceTree = ""; }; + 849C0D6B1B072D14008BAAA4 /* reios_elf.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = reios_elf.cpp; path = reios/reios_elf.cpp; sourceTree = ""; }; + 849C0D6C1B072D14008BAAA4 /* reios_elf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reios_elf.h; path = reios/reios_elf.h; sourceTree = ""; }; +- 8703BC371A44B8DA00E7E939 /* Icon-72.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-72.png"; path = "emulator/assets/Icon-72.png"; sourceTree = ""; }; +- 8703BC381A44B8DA00E7E939 /* Icon-72@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-72@2x.png"; path = "emulator/assets/Icon-72@2x.png"; sourceTree = ""; }; +- 8703BC391A44B8DA00E7E939 /* Icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Icon.png; path = emulator/assets/Icon.png; sourceTree = ""; }; +- 8703BC3A1A44B8DA00E7E939 /* Icon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon@2x.png"; path = "emulator/assets/Icon@2x.png"; sourceTree = ""; }; + 87078A8318A47FE90034C7A0 /* reicast-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "reicast-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 87078A8618A47FE90034C7A0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 87078A8818A47FE90034C7A0 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; +@@ -316,6 +312,10 @@ + 877652C11B6157BD00437F10 /* oslib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = oslib.h; sourceTree = ""; }; + 877652C71B6157FC00437F10 /* ngen_arm.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = ngen_arm.S; sourceTree = ""; }; + 877652C81B6157FC00437F10 /* rec_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rec_arm.cpp; sourceTree = ""; }; ++ 878B0CFB1B8BB5B400A8D1C5 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = "../reicast-ios/Images.xcassets"; sourceTree = ""; }; ++ 878B0CFF1B8BFE6200A8D1C5 /* disk_unknown.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = disk_unknown.png; path = emulator/Images/disk_unknown.png; sourceTree = ""; }; ++ 8794D9C11B88F3D600B1B3A3 /* DiskViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DiskViewCell.h; path = emulator/DiskViewCell.h; sourceTree = ""; }; ++ 8794D9C21B88F3D600B1B3A3 /* DiskViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DiskViewCell.m; path = emulator/DiskViewCell.m; sourceTree = ""; }; + 87C208C51B7A4BFA00638BDD /* AboutViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AboutViewController.h; path = emulator/AboutViewController.h; sourceTree = ""; }; + 87C208C61B7A4BFA00638BDD /* AboutViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AboutViewController.m; path = emulator/AboutViewController.m; sourceTree = ""; }; + 87C208C71B7A4BFA00638BDD /* BrowserTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BrowserTableViewController.h; path = emulator/BrowserTableViewController.h; sourceTree = ""; }; +@@ -364,6 +364,9 @@ + 87D92F511B7A1BB100D8FD9E /* iCadeReaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = iCadeReaderView.m; sourceTree = ""; }; + 87D92F521B7A1BB100D8FD9E /* iCadeState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iCadeState.h; sourceTree = ""; }; + 87D92F531B7A1BB100D8FD9E /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; ++ 87FA52E61B8CE18600CEFC32 /* PadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PadViewController.h; path = emulator/PadViewController.h; sourceTree = ""; }; ++ 87FA52E71B8CE18600CEFC32 /* PadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PadViewController.m; path = emulator/PadViewController.m; sourceTree = ""; }; ++ 87FA52E81B8CE18600CEFC32 /* PadViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = PadViewController.xib; path = emulator/PadViewController.xib; sourceTree = ""; }; + 9C7A393218C804A80070BB5F /* reicast.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = reicast.entitlements; sourceTree = ""; }; + 9C7A393A18C806DE0070BB5F /* arm_coding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arm_coding.h; sourceTree = ""; }; + 9C7A393B18C806DE0070BB5F /* arm_disasm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arm_disasm.h; sourceTree = ""; }; +@@ -382,7 +385,6 @@ + 9C7A394818C806DE0070BB5F /* E_VLoadStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = E_VLoadStore.h; sourceTree = ""; }; + 9C7A394918C806DE0070BB5F /* E_VRegXfer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = E_VRegXfer.h; sourceTree = ""; }; + 9C7A394A18C806DE0070BB5F /* H_Branches.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H_Branches.h; sourceTree = ""; }; +- 9C7A394B18C806DE0070BB5F /* H_fp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H_fp.h; sourceTree = ""; }; + 9C7A394C18C806DE0070BB5F /* H_LoadStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H_LoadStore.h; sourceTree = ""; }; + 9C7A394D18C806DE0070BB5F /* H_psuedo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H_psuedo.h; sourceTree = ""; }; + 9C7A394E18C806DE0070BB5F /* H_state.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = H_state.h; sourceTree = ""; }; +@@ -722,17 +724,6 @@ + name = reios; + sourceTree = ""; + }; +- 8703BC361A44B8DA00E7E939 /* assets */ = { +- isa = PBXGroup; +- children = ( +- 8703BC371A44B8DA00E7E939 /* Icon-72.png */, +- 8703BC381A44B8DA00E7E939 /* Icon-72@2x.png */, +- 8703BC391A44B8DA00E7E939 /* Icon.png */, +- 8703BC3A1A44B8DA00E7E939 /* Icon@2x.png */, +- ); +- name = assets; +- sourceTree = ""; +- }; + 87078A7A18A47FE90034C7A0 = { + isa = PBXGroup; + children = ( +@@ -769,6 +760,7 @@ + 87078A9018A47FE90034C7A0 /* reicast */ = { + isa = PBXGroup; + children = ( ++ 878B0CFB1B8BB5B400A8D1C5 /* Images.xcassets */, + 9C7A3BC318C84EA10070BB5F /* MainStoryboard.storyboard */, + 87078A9918A47FE90034C7A0 /* AppDelegate.h */, + 87078A9A18A47FE90034C7A0 /* AppDelegate.m */, +@@ -790,7 +782,6 @@ + 87078A9118A47FE90034C7A0 /* Supporting Files */ = { + isa = PBXGroup; + children = ( +- 8703BC361A44B8DA00E7E939 /* assets */, + 87078A9218A47FE90034C7A0 /* reicast-ios-Info.plist */, + 87078A9618A47FE90034C7A0 /* main.m */, + 87078A9818A47FE90034C7A0 /* reicast-ios-Prefix.pch */, +@@ -823,6 +814,11 @@ + 9C7A393618C805F70070BB5F /* View Controller Subclasses */ = { + isa = PBXGroup; + children = ( ++ 87FA52E61B8CE18600CEFC32 /* PadViewController.h */, ++ 87FA52E71B8CE18600CEFC32 /* PadViewController.m */, ++ 87FA52E81B8CE18600CEFC32 /* PadViewController.xib */, ++ 8794D9C11B88F3D600B1B3A3 /* DiskViewCell.h */, ++ 8794D9C21B88F3D600B1B3A3 /* DiskViewCell.m */, + 87C208C51B7A4BFA00638BDD /* AboutViewController.h */, + 87C208C61B7A4BFA00638BDD /* AboutViewController.m */, + 87C208C71B7A4BFA00638BDD /* BrowserTableViewController.h */, +@@ -860,6 +856,7 @@ + 87D92F291B7A1B4800D8FD9E /* JoystickBackground.png */, + 87D92F2A1B7A1B4800D8FD9E /* JoystickBackground@2x.png */, + 87D92F2B1B7A1B4800D8FD9E /* JoystickButton.png */, ++ 878B0CFF1B8BFE6200A8D1C5 /* disk_unknown.png */, + 87D92F2C1B7A1B4800D8FD9E /* JoystickButton@2x.png */, + 87D92F2D1B7A1B4800D8FD9E /* LTrigger.png */, + 87D92F2E1B7A1B4800D8FD9E /* LTrigger@2x.png */, +@@ -924,7 +921,6 @@ + 9C7A394818C806DE0070BB5F /* E_VLoadStore.h */, + 9C7A394918C806DE0070BB5F /* E_VRegXfer.h */, + 9C7A394A18C806DE0070BB5F /* H_Branches.h */, +- 9C7A394B18C806DE0070BB5F /* H_fp.h */, + 9C7A394C18C806DE0070BB5F /* H_LoadStore.h */, + 9C7A394D18C806DE0070BB5F /* H_psuedo.h */, + 9C7A394E18C806DE0070BB5F /* H_state.h */, +@@ -1007,7 +1003,6 @@ + children = ( + 84967C731B8F492C005F1140 /* arm */, + 84967C771B8F492C005F1140 /* config.h */, +- 84967C781B8F492C005F1140 /* fp.h */, + 84967C791B8F492C005F1140 /* png.c */, + 84967C7A1B8F492C005F1140 /* png.h */, + 84967C7B1B8F492C005F1140 /* pngconf.h */, +@@ -1506,10 +1501,6 @@ + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( +- 87DCDB251B7EE57D0054D67C /* Icon-72.png in Resources */, +- 87DCDB261B7EE5850054D67C /* Icon-72@2x.png in Resources */, +- 87DCDB271B7EE5850054D67C /* Icon.png in Resources */, +- 87DCDB281B7EE5850054D67C /* Icon@2x.png in Resources */, + 87D92F461B7A1B4800D8FD9E /* menuback@2x.png in Resources */, + 87D92F491B7A1B4800D8FD9E /* RTrigger.png in Resources */, + 87D92F4B1B7A1B4800D8FD9E /* Start.png in Resources */, +@@ -1517,6 +1508,7 @@ + 87D92F391B7A1B4800D8FD9E /* 210-twitterbird.png in Resources */, + 87D92F3A1B7A1B4800D8FD9E /* 210-twitterbird@2x.png in Resources */, + 87D92F3D1B7A1B4800D8FD9E /* DPad.png in Resources */, ++ 878B0CFC1B8BB5B400A8D1C5 /* Images.xcassets in Resources */, + 87D92F3C1B7A1B4800D8FD9E /* ABXYPad@2x.png in Resources */, + 87D92F401B7A1B4800D8FD9E /* JoystickBackground@2x.png in Resources */, + 9C7A3AA418C806E00070BB5F /* core.mk in Resources */, +@@ -1535,7 +1527,9 @@ + 87D92F441B7A1B4800D8FD9E /* LTrigger@2x.png in Resources */, + 87D92F551B7A1BB100D8FD9E /* LICENSE in Resources */, + 87D92F451B7A1B4800D8FD9E /* menuback.png in Resources */, ++ 87FA52EA1B8CE18600CEFC32 /* PadViewController.xib in Resources */, + 87078AA518A47FE90034C7A0 /* Shader.vsh in Resources */, ++ 878B0D001B8BFE6200A8D1C5 /* disk_unknown.png in Resources */, + 87D92F3B1B7A1B4800D8FD9E /* ABXYPad.png in Resources */, + 87D92F481B7A1B4800D8FD9E /* menuicon@2x.png in Resources */, + 87D92F371B7A1B4800D8FD9E /* 210-octocat.png in Resources */, +@@ -1601,6 +1595,7 @@ + 9C7A3B2318C806E00070BB5F /* sh4_opcodes.cpp in Sources */, + 84967C951B8F492C005F1140 /* pngmem.c in Sources */, + 9C7A3ADA18C806E00070BB5F /* zip_name_locate.c in Sources */, ++ 8794D9C31B88F3D600B1B3A3 /* DiskViewCell.m in Sources */, + 9C7A3B1B18C806E00070BB5F /* ta_ctx.cpp in Sources */, + 9C7A3AE018C806E00070BB5F /* zip_set_archive_flag.c in Sources */, + 9C7A3B3518C806E00070BB5F /* cdi.cpp in Sources */, +@@ -1635,6 +1630,7 @@ + 9C7A3B5918C81A4F0070BB5F /* SWRevealViewController.m in Sources */, + 9C7A3B0F18C806E00070BB5F /* maple_cfg.cpp in Sources */, + 9C7A3AF318C806E00070BB5F /* crc32.c in Sources */, ++ 87FA52E91B8CE18600CEFC32 /* PadViewController.m in Sources */, + 8497BCC01A41A0E900EFB9ED /* nixprof.cpp in Sources */, + 9C7A3AE118C806E00070BB5F /* zip_set_file_comment.c in Sources */, + 84967C9A1B8F492C005F1140 /* pngrutil.c in Sources */, +@@ -1840,6 +1836,8 @@ + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = armv7; ++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ++ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; +@@ -1875,6 +1873,8 @@ + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = armv7; ++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ++ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; +diff -Nur a/shell/apple/reicast.xcworkspace/xcshareddata/xcschemes/reicast-ios.xcscheme b/shell/apple/reicast.xcworkspace/xcshareddata/xcschemes/reicast-ios.xcscheme +--- a/shell/apple/reicast.xcworkspace/xcshareddata/xcschemes/reicast-ios.xcscheme 2015-10-06 21:43:53.127337010 -0300 ++++ b/shell/apple/reicast.xcworkspace/xcshareddata/xcschemes/reicast-ios.xcscheme 2015-10-06 22:10:31.210968157 -0300 +@@ -62,7 +62,8 @@ + ignoresPersistentStateOnLaunch = "NO" + debugDocumentVersioning = "YES" + allowLocationSimulation = "YES"> +- ++ + +- ++ + bus_id); + +- pjs->kcode=kcode[dev->bus_id] | 0xF901; +- pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[dev->bus_id]); +- pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[dev->bus_id]); +- pjs->trigger[PJTI_R]=rt[dev->bus_id]; +- pjs->trigger[PJTI_L]=lt[dev->bus_id]; ++ pjs->kcode = maple_controller[dev->bus_id].buttons | 0xF901; ++ pjs->joy[PJAI_X1] = GetBtFromSgn(maple_controller[dev->bus_id].stick_x); ++ pjs->joy[PJAI_Y1] = GetBtFromSgn(maple_controller[dev->bus_id].stick_y); ++ pjs->trigger[PJTI_R] = maple_controller[dev->bus_id].trigger_right; ++ pjs->trigger[PJTI_L] = maple_controller[dev->bus_id].trigger_left; + } + void SetImage(void* img) + { +@@ -68,14 +64,19 @@ + + void mcfg_CreateDevices() + { +-#if DC_PLATFORM == DC_PLATFORM_DREAMCAST +- mcfg_Create(MDT_SegaController,0,5); +- +- mcfg_Create(MDT_SegaVMU,0,0); +- mcfg_Create(MDT_SegaVMU,0,1); +-#else +- mcfg_Create(MDT_NaomiJamma, 0, 5); +-#endif ++ for(int port = 0; port < MAPLE_NUM_PORTS; port++) ++ { ++ if(maple_controller[port].enabled) ++ { ++ #if DC_PLATFORM == DC_PLATFORM_DREAMCAST ++ mcfg_Create(MDT_SegaController, port, 5); ++ mcfg_Create(MDT_SegaVMU, port, 0); ++ mcfg_Create(MDT_SegaVMU, port, 1); ++ #else ++ mcfg_Create(MDT_NaomiJamma, port, 5); ++ #endif ++ } ++ } + } + + void mcfg_DestroyDevices() +diff -Nur a/core/hw/maple/maple_controller.cpp b/core/hw/maple/maple_controller.cpp +--- a/core/hw/maple/maple_controller.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/hw/maple/maple_controller.cpp 2015-10-06 22:08:18.378992677 -0300 +@@ -0,0 +1,8 @@ ++#include "hw/maple/maple_controller.h" ++ ++MapleController maple_controller[MAPLE_NUM_PORTS] = { ++ { 1 , 0xFFFF, 0, 0, 0, 0 }, ++ { 0 , 0xFFFF, 0, 0, 0, 0 }, ++ { 0 , 0xFFFF, 0, 0, 0, 0 }, ++ { 0 , 0xFFFF, 0, 0, 0, 0 } ++}; +diff -Nur a/core/hw/maple/maple_controller.h b/core/hw/maple/maple_controller.h +--- a/core/hw/maple/maple_controller.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/hw/maple/maple_controller.h 2015-10-06 22:08:18.378992677 -0300 +@@ -0,0 +1,42 @@ ++#pragma once ++#include "types.h" ++ ++// If you change the value of MAPLE_NUM_PORTS, please note that you need to change the initializers in maple_controller.cpp as well ++#define MAPLE_NUM_PORTS 4 ++ ++struct MapleController ++{ ++ bool enabled; ++ u16 buttons; ++ u8 trigger_left; ++ u8 trigger_right; ++ s8 stick_x; ++ s8 stick_y; ++}; ++ ++extern MapleController maple_controller[MAPLE_NUM_PORTS]; ++ ++enum DreamcastControllerCodes ++{ ++ DC_BTN_C = 1, ++ DC_BTN_B = 1<<1, ++ DC_BTN_A = 1<<2, ++ DC_BTN_START = 1<<3, ++ DC_BTN_DPAD_UP = 1<<4, ++ DC_BTN_DPAD_DOWN = 1<<5, ++ DC_BTN_DPAD_LEFT = 1<<6, ++ DC_BTN_DPAD_RIGHT = 1<<7, ++ DC_BTN_Z = 1<<8, ++ DC_BTN_Y = 1<<9, ++ DC_BTN_X = 1<<10, ++ DC_BTN_D = 1<<11, ++ DC_BTN_DPAD2_UP = 1<<12, ++ DC_BTN_DPAD2_DOWN = 1<<13, ++ DC_BTN_DPAD2_LEFT = 1<<14, ++ DC_BTN_DPAD2_RIGHT = 1<<15, ++ ++ DC_AXIS_LT = 0X10000, ++ DC_AXIS_RT = 0X10001, ++ DC_AXIS_X = 0X20000, ++ DC_AXIS_Y = 0X20001 ++}; +diff -Nur a/core/linux-dist/x11.cpp b/core/linux-dist/x11.cpp +--- a/core/linux-dist/x11.cpp 2015-10-06 22:04:14.520204440 -0300 ++++ b/core/linux-dist/x11.cpp 2015-10-06 22:08:18.381992699 -0300 +@@ -82,11 +82,11 @@ + int dc_key = x11_keymap[e.xkey.keycode]; + if (e.type == KeyPress) + { +- kcode[0] &= ~dc_key; ++ maple_controller[0].buttons &= ~dc_key; + } + else + { +- kcode[0] |= dc_key; ++ maple_controller[0].buttons |= dc_key; + } + } + //printf("KEY: %d -> %d: %d\n",e.xkey.keycode, dc_key, x11_dc_buttons ); +diff -Nur a/core/nacl/nacl.cpp b/core/nacl/nacl.cpp +--- a/core/nacl/nacl.cpp 2015-10-06 22:07:39.028703879 -0300 ++++ b/core/nacl/nacl.cpp 2015-10-06 22:08:18.381992699 -0300 +@@ -15,6 +15,7 @@ + #include "ppapi/utility/completion_callback_factory.h" + + #include "types.h" ++#include "hw/maple/maple_controller.h" + + #include + +@@ -234,12 +235,6 @@ + } + } // namespace pp + +- +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +- + int get_mic_data(u8* buffer) { return 0; } + int push_vmu_screen(u8* buffer) { return 0; } + +diff -Nur a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp +--- a/core/rend/gles/gles.cpp 2015-10-06 22:07:39.029703886 -0300 ++++ b/core/rend/gles/gles.cpp 2015-10-06 22:08:18.382992707 -0300 +@@ -1833,7 +1810,7 @@ + } + + bool do_swp=false; +- //if (kcode[0]&(1<<9)) ++ //if (maple_controller[0].buttons&(1<<9)) + { + + +diff -Nur a/core/windows/winmain.cpp b/core/windows/winmain.cpp +--- a/core/windows/winmain.cpp 2015-10-06 22:07:39.030703893 -0300 ++++ b/core/windows/winmain.cpp 2015-10-06 22:08:18.383992714 -0300 +@@ -1,5 +1,6 @@ + #include "oslib\oslib.h" + #include "oslib\audiostream.h" ++#include "hw\maple\maple_controller.h" + #include "imgread\common.h" + + #define _WIN32_WINNT 0x0500 +@@ -173,66 +174,46 @@ + return MessageBox(NULL,temp,VER_SHORTNAME,type | MB_TASKMODAL); + } + +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +-#define key_CONT_C (1 << 0) +-#define key_CONT_B (1 << 1) +-#define key_CONT_A (1 << 2) +-#define key_CONT_START (1 << 3) +-#define key_CONT_DPAD_UP (1 << 4) +-#define key_CONT_DPAD_DOWN (1 << 5) +-#define key_CONT_DPAD_LEFT (1 << 6) +-#define key_CONT_DPAD_RIGHT (1 << 7) +-#define key_CONT_Z (1 << 8) +-#define key_CONT_Y (1 << 9) +-#define key_CONT_X (1 << 10) +-#define key_CONT_D (1 << 11) +-#define key_CONT_DPAD2_UP (1 << 12) +-#define key_CONT_DPAD2_DOWN (1 << 13) +-#define key_CONT_DPAD2_LEFT (1 << 14) +-#define key_CONT_DPAD2_RIGHT (1 << 15) + void UpdateInputState(u32 port) + { +- //joyx[port]=pad.Lx; +- //joyy[port]=pad.Ly; +- lt[port]=GetAsyncKeyState('A')?255:0; +- rt[port]=GetAsyncKeyState('S')?255:0; ++ //maple_controller[port].stick_x = pad.Lx; ++ //maple_controller[port].stick_y = pad.Ly; ++ maple_controller[port].trigger_left = GetAsyncKeyState('A') ? 255 : 0; ++ maple_controller[port].trigger_right = GetAsyncKeyState('S') ? 255 : 0; + +- joyx[port]=joyy[port]=0; ++ maple_controller[port].stick_x = maple_controller[port].stick_y = 0; + + if (GetAsyncKeyState('J')) +- joyx[port]-=126; ++ maple_controller[port].stick_x -= 126; + if (GetAsyncKeyState('L')) +- joyx[port]+=126; ++ maple_controller[port].stick_x += 126; + + if (GetAsyncKeyState('I')) +- joyy[port]-=126; ++ maple_controller[port].stick_y -= 126; + if (GetAsyncKeyState('K')) +- joyy[port]+=126; ++ maple_controller[port].stick_y += 126; + +- kcode[port]=0xFFFF; ++ maple_controller[port].buttons = 0xFFFF; + if (GetAsyncKeyState('V')) +- kcode[port]&=~key_CONT_A; ++ maple_controller[port].buttons &= ~DC_BTN_A; + if (GetAsyncKeyState('C')) +- kcode[port]&=~key_CONT_B; ++ maple_controller[port].buttons &= ~DC_BTN_B; + if (GetAsyncKeyState('X')) +- kcode[port]&=~key_CONT_Y; ++ maple_controller[port].buttons &= ~DC_BTN_Y; + if (GetAsyncKeyState('Z')) +- kcode[port]&=~key_CONT_X; ++ maple_controller[port].buttons &= ~DC_BTN_X; + + if (GetAsyncKeyState(VK_SHIFT)) +- kcode[port]&=~key_CONT_START; ++ maple_controller[port].buttons &= ~DC_BTN_START; + + if (GetAsyncKeyState(VK_UP)) +- kcode[port]&=~key_CONT_DPAD_UP; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_UP; + if (GetAsyncKeyState(VK_DOWN)) +- kcode[port]&=~key_CONT_DPAD_DOWN; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_DOWN; + if (GetAsyncKeyState(VK_LEFT)) +- kcode[port]&=~key_CONT_DPAD_LEFT; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_LEFT; + if (GetAsyncKeyState(VK_RIGHT)) +- kcode[port]&=~key_CONT_DPAD_RIGHT; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_RIGHT; + + if (GetAsyncKeyState(VK_F1)) + settings.pvr.ta_skip = 100; +diff -Nur a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp +--- a/shell/android/jni/src/Android.cpp 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/android/jni/src/Android.cpp 2015-10-06 22:08:18.383992714 -0300 +@@ -16,6 +16,7 @@ + #include "rend/TexCache.h" + #include "hw/maple/maple_devs.h" + #include "hw/maple/maple_if.h" ++#include "hw/maple/maple_controller.h" + #include "oslib/audiobackend_android.h" + + #include "util.h" +@@ -175,10 +176,6 @@ + // Additonal controllers 2, 3 and 4 connected ? + static bool add_controllers[3] = { false, false, false }; + +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; + float vjoy_pos[14][8]; + + extern bool print_stats; +@@ -211,7 +208,7 @@ + } + + // Add additonal controllers +- for (int i = 0; i < 3; i++) ++ for (int i = 0; i < (MAPLE_NUM_PORTS - 1); i++) + { + if (add_controllers[i]) + mcfg_Create(MDT_SegaController,i+1,5); +@@ -443,13 +440,13 @@ + jint *jx_body = env->GetIntArrayElements(jx, 0); + jint *jy_body = env->GetIntArrayElements(jy, 0); + +- for(int i = 0; i < 4; i++) ++ for(int i = 0; i < MAPLE_NUM_PORTS; i++) + { +- kcode[i] = k_code_body[i]; +- lt[i] = l_t_body[i]; +- rt[i] = r_t_body[i]; +- joyx[i] = jx_body[i]; +- joyy[i] = jy_body[i]; ++ maple_controller[i].buttons = k_code_body[i]; ++ maple_controller[i].trigger_left = l_t_body[i]; ++ maple_controller[i].trigger_right = r_t_body[i]; ++ maple_controller[i].stick_x = jx_body[i]; ++ maple_controller[i].stick_y = jy_body[i]; + } + + env->ReleaseIntArrayElements(k_code, k_code_body, 0); +diff -Nur a/shell/apple/emulator-ios/emulator/ios_main.mm b/shell/apple/emulator-ios/emulator/ios_main.mm +--- a/shell/apple/emulator-ios/emulator/ios_main.mm 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/apple/emulator-ios/emulator/ios_main.mm 2015-10-06 22:08:18.383992714 -0300 +@@ -20,6 +20,7 @@ + #include + #include + #include "hw/sh4/dyna/blockmanager.h" ++#include "hw/maple/maple_controller.h" + #include + + +@@ -55,11 +56,6 @@ + int dc_init(int argc,wchar* argv[]); + void dc_run(); + +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +- + extern "C" int reicast_main(int argc, wchar* argv[]) + { + //if (argc==2) +diff -Nur a/shell/apple/emulator-osx/emulator-osx/osx-main.mm b/shell/apple/emulator-osx/emulator-osx/osx-main.mm +--- a/shell/apple/emulator-osx/emulator-osx/osx-main.mm 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/apple/emulator-osx/emulator-osx/osx-main.mm 2015-10-06 22:08:18.383992714 -0300 +@@ -8,6 +8,7 @@ + #import + + #include "types.h" ++#include "hw/maple/maple_controller.h" + #include + + #include +@@ -38,11 +39,6 @@ + return 0; + } + +-u16 kcode[4] = { 0xFFFF }; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +- + int get_mic_data(u8* buffer) { return 0; } + int push_vmu_screen(u8* buffer) { return 0; } + +@@ -131,35 +127,11 @@ + gles_init(); + } + +-enum DCPad { +- Btn_C = 1, +- Btn_B = 1<<1, +- Btn_A = 1<<2, +- Btn_Start = 1<<3, +- DPad_Up = 1<<4, +- DPad_Down = 1<<5, +- DPad_Left = 1<<6, +- DPad_Right = 1<<7, +- Btn_Z = 1<<8, +- Btn_Y = 1<<9, +- Btn_X = 1<<10, +- Btn_D = 1<<11, +- DPad2_Up = 1<<12, +- DPad2_Down = 1<<13, +- DPad2_Left = 1<<14, +- DPad2_Right = 1<<15, +- +- Axis_LT= 0x10000, +- Axis_RT= 0x10001, +- Axis_X= 0x20000, +- Axis_Y= 0x20001, +-}; +- + void handle_key(int dckey, int state) { + if (state) +- kcode[0] &= ~dckey; ++ maple_controller[0].buttons &= ~dckey; + else +- kcode[0] |= dckey; ++ maple_controller[0].buttons |= dckey; + } + + void handle_trig(u8* dckey, int state) { +@@ -172,18 +144,18 @@ + extern "C" void emu_key_input(char* keyt, int state) { + int key = keyt[0]; + switch(key) { +- case 'z': handle_key(Btn_X, state); break; +- case 'x': handle_key(Btn_Y, state); break; +- case 'c': handle_key(Btn_B, state); break; +- case 'v': handle_key(Btn_A, state); break; ++ case 'z': handle_key(DC_BTN_X, state); break; ++ case 'x': handle_key(DC_BTN_Y, state); break; ++ case 'c': handle_key(DC_BTN_B, state); break; ++ case 'v': handle_key(DC_BTN_A, state); break; + + case 'a': handle_trig(lt, state); break; + case 's': handle_trig(rt, state); break; + +- case 'j': handle_key(DPad_Left, state); break; +- case 'k': handle_key(DPad_Down, state); break; +- case 'l': handle_key(DPad_Right, state); break; +- case 'i': handle_key(DPad_Up, state); break; +- case 0xa: handle_key(Btn_Start, state); break; ++ case 'j': handle_key(DC_BTN_DPAD_LEFT, state); break; ++ case 'k': handle_key(DC_BTN_DPAD_DOWN, state); break; ++ case 'l': handle_key(DC_BTN_DPAD_RIGHT, state); break; ++ case 'i': handle_key(DC_BTN_DPAD_UP, state); break; ++ case 0xa: handle_key(DC_BTN_START, state); break; + } + } +\ No newline at end of file +diff -Nur a/shell/reicast.vcxproj b/shell/reicast.vcxproj +--- a/shell/reicast.vcxproj 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/reicast.vcxproj 2015-10-06 22:08:18.383992714 -0300 +@@ -92,6 +92,7 @@ + + + ++ + + + diff --git a/pcr/reicast-git/multiplayer.patch b/pcr/reicast-git/multiplayer.patch new file mode 100644 index 000000000..19ee3c869 --- /dev/null +++ b/pcr/reicast-git/multiplayer.patch @@ -0,0 +1,1211 @@ +diff -Nur a/core/hw/maple/maple_cfg.cpp b/core/hw/maple/maple_cfg.cpp +--- a/core/hw/maple/maple_cfg.cpp 2015-10-06 21:43:53.027336293 -0300 ++++ b/core/hw/maple/maple_cfg.cpp 2015-10-06 22:08:18.378992677 -0300 +@@ -3,6 +3,7 @@ + #include "maple_helper.h" + #include "maple_devs.h" + #include "maple_cfg.h" ++#include "maple_controller.h" + + #define HAS_VMU + /* +@@ -22,11 +23,6 @@ + */ + void UpdateInputState(u32 port); + +-extern u16 kcode[4]; +-extern u32 vks[4]; +-extern s8 joyx[4],joyy[4]; +-extern u8 rt[4],lt[4]; +- + u8 GetBtFromSgn(s8 val) + { + return val+128; +@@ -45,11 +41,11 @@ + { + UpdateInputState(dev->bus_id); + +- pjs->kcode=kcode[dev->bus_id] | 0xF901; +- pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[dev->bus_id]); +- pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[dev->bus_id]); +- pjs->trigger[PJTI_R]=rt[dev->bus_id]; +- pjs->trigger[PJTI_L]=lt[dev->bus_id]; ++ pjs->kcode = maple_controller[dev->bus_id].buttons | 0xF901; ++ pjs->joy[PJAI_X1] = GetBtFromSgn(maple_controller[dev->bus_id].stick_x); ++ pjs->joy[PJAI_Y1] = GetBtFromSgn(maple_controller[dev->bus_id].stick_y); ++ pjs->trigger[PJTI_R] = maple_controller[dev->bus_id].trigger_right; ++ pjs->trigger[PJTI_L] = maple_controller[dev->bus_id].trigger_left; + } + void SetImage(void* img) + { +@@ -68,14 +64,19 @@ + + void mcfg_CreateDevices() + { +-#if DC_PLATFORM == DC_PLATFORM_DREAMCAST +- mcfg_Create(MDT_SegaController,0,5); +- +- mcfg_Create(MDT_SegaVMU,0,0); +- mcfg_Create(MDT_SegaVMU,0,1); +-#else +- mcfg_Create(MDT_NaomiJamma, 0, 5); +-#endif ++ for(int port = 0; port < MAPLE_NUM_PORTS; port++) ++ { ++ if(maple_controller[port].enabled) ++ { ++ #if DC_PLATFORM == DC_PLATFORM_DREAMCAST ++ mcfg_Create(MDT_SegaController, port, 5); ++ mcfg_Create(MDT_SegaVMU, port, 0); ++ mcfg_Create(MDT_SegaVMU, port, 1); ++ #else ++ mcfg_Create(MDT_NaomiJamma, port, 5); ++ #endif ++ } ++ } + } + + void mcfg_DestroyDevices() +diff -Nur a/core/hw/maple/maple_controller.cpp b/core/hw/maple/maple_controller.cpp +--- a/core/hw/maple/maple_controller.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/hw/maple/maple_controller.cpp 2015-10-06 22:08:18.378992677 -0300 +@@ -0,0 +1,8 @@ ++#include "hw/maple/maple_controller.h" ++ ++MapleController maple_controller[MAPLE_NUM_PORTS] = { ++ { 1 , 0xFFFF, 0, 0, 0, 0 }, ++ { 0 , 0xFFFF, 0, 0, 0, 0 }, ++ { 0 , 0xFFFF, 0, 0, 0, 0 }, ++ { 0 , 0xFFFF, 0, 0, 0, 0 } ++}; +diff -Nur a/core/hw/maple/maple_controller.h b/core/hw/maple/maple_controller.h +--- a/core/hw/maple/maple_controller.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/hw/maple/maple_controller.h 2015-10-06 22:08:18.378992677 -0300 +@@ -0,0 +1,42 @@ ++#pragma once ++#include "types.h" ++ ++// If you change the value of MAPLE_NUM_PORTS, please note that you need to change the initializers in maple_controller.cpp as well ++#define MAPLE_NUM_PORTS 4 ++ ++struct MapleController ++{ ++ bool enabled; ++ u16 buttons; ++ u8 trigger_left; ++ u8 trigger_right; ++ s8 stick_x; ++ s8 stick_y; ++}; ++ ++extern MapleController maple_controller[MAPLE_NUM_PORTS]; ++ ++enum DreamcastControllerCodes ++{ ++ DC_BTN_C = 1, ++ DC_BTN_B = 1<<1, ++ DC_BTN_A = 1<<2, ++ DC_BTN_START = 1<<3, ++ DC_BTN_DPAD_UP = 1<<4, ++ DC_BTN_DPAD_DOWN = 1<<5, ++ DC_BTN_DPAD_LEFT = 1<<6, ++ DC_BTN_DPAD_RIGHT = 1<<7, ++ DC_BTN_Z = 1<<8, ++ DC_BTN_Y = 1<<9, ++ DC_BTN_X = 1<<10, ++ DC_BTN_D = 1<<11, ++ DC_BTN_DPAD2_UP = 1<<12, ++ DC_BTN_DPAD2_DOWN = 1<<13, ++ DC_BTN_DPAD2_LEFT = 1<<14, ++ DC_BTN_DPAD2_RIGHT = 1<<15, ++ ++ DC_AXIS_LT = 0X10000, ++ DC_AXIS_RT = 0X10001, ++ DC_AXIS_X = 0X20000, ++ DC_AXIS_Y = 0X20001 ++}; +diff -Nur a/core/linux-dist/evdev.cpp b/core/linux-dist/evdev.cpp +--- a/core/linux-dist/evdev.cpp 2015-10-06 22:07:39.028703879 -0300 ++++ b/core/linux-dist/evdev.cpp 2015-10-06 22:08:18.381992699 -0300 +@@ -314,43 +314,43 @@ + { + case EV_KEY: + if (ie.code == controller->mapping->Btn_A) { +- SET_FLAG(kcode[port], DC_BTN_A, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_A, ie.value); + } else if (ie.code == controller->mapping->Btn_B) { +- SET_FLAG(kcode[port], DC_BTN_B, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_B, ie.value); + } else if (ie.code == controller->mapping->Btn_C) { +- SET_FLAG(kcode[port], DC_BTN_C, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_C, ie.value); + } else if (ie.code == controller->mapping->Btn_D) { +- SET_FLAG(kcode[port], DC_BTN_D, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_D, ie.value); + } else if (ie.code == controller->mapping->Btn_X) { +- SET_FLAG(kcode[port], DC_BTN_X, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_X, ie.value); + } else if (ie.code == controller->mapping->Btn_Y) { +- SET_FLAG(kcode[port], DC_BTN_Y, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_Y, ie.value); + } else if (ie.code == controller->mapping->Btn_Z) { +- SET_FLAG(kcode[port], DC_BTN_Z, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_Z, ie.value); + } else if (ie.code == controller->mapping->Btn_Start) { +- SET_FLAG(kcode[port], DC_BTN_START, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_START, ie.value); + } else if (ie.code == controller->mapping->Btn_Escape) { + die("death by escape key"); + } else if (ie.code == controller->mapping->Btn_DPad_Left) { +- SET_FLAG(kcode[port], DC_DPAD_LEFT, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_LEFT, ie.value); + } else if (ie.code == controller->mapping->Btn_DPad_Right) { +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_RIGHT, ie.value); + } else if (ie.code == controller->mapping->Btn_DPad_Up) { +- SET_FLAG(kcode[port], DC_DPAD_UP, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_UP, ie.value); + } else if (ie.code == controller->mapping->Btn_DPad_Down) { +- SET_FLAG(kcode[port], DC_DPAD_DOWN, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_DOWN, ie.value); + } else if (ie.code == controller->mapping->Btn_DPad2_Left) { +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_LEFT, ie.value); + } else if (ie.code == controller->mapping->Btn_DPad2_Right) { +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_RIGHT, ie.value); + } else if (ie.code == controller->mapping->Btn_DPad2_Up) { +- SET_FLAG(kcode[port], DC_DPAD2_UP, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_UP, ie.value); + } else if (ie.code == controller->mapping->Btn_DPad2_Down) { +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, ie.value); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_DOWN, ie.value); + } else if (ie.code == controller->mapping->Btn_Trigger_Left) { +- lt[port] = (ie.value ? 255 : 0); ++ maple_controller[port].trigger_left = (ie.value ? 255 : 0); + } else if (ie.code == controller->mapping->Btn_Trigger_Right) { +- rt[port] = (ie.value ? 255 : 0); ++ maple_controller[port].trigger_right = (ie.value ? 255 : 0); + } + break; + case EV_ABS: +@@ -359,16 +359,16 @@ + switch(ie.value) + { + case -1: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 1); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_LEFT, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_RIGHT, 0); + break; + case 0: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_LEFT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_RIGHT, 0); + break; + case 1: +- SET_FLAG(kcode[port], DC_DPAD_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD_RIGHT, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_LEFT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_RIGHT, 1); + break; + } + } +@@ -377,16 +377,16 @@ + switch(ie.value) + { + case -1: +- SET_FLAG(kcode[port], DC_DPAD_UP, 1); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_UP, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_DOWN, 0); + break; + case 0: +- SET_FLAG(kcode[port], DC_DPAD_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_UP, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_DOWN, 0); + break; + case 1: +- SET_FLAG(kcode[port], DC_DPAD_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD_DOWN, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_UP, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD_DOWN, 1); + break; + } + } +@@ -395,16 +395,16 @@ + switch(ie.value) + { + case -1: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 1); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_LEFT, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_RIGHT, 0); + break; + case 0: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_LEFT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_RIGHT, 0); + break; + case 1: +- SET_FLAG(kcode[port], DC_DPAD2_LEFT, 0); +- SET_FLAG(kcode[port], DC_DPAD2_RIGHT, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_LEFT, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_RIGHT, 1); + break; + } + } +@@ -413,34 +413,34 @@ + switch(ie.value) + { + case -1: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 1); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_UP, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_DOWN, 0); + break; + case 0: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_UP, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_DOWN, 0); + break; + case 1: +- SET_FLAG(kcode[port], DC_DPAD2_UP, 0); +- SET_FLAG(kcode[port], DC_DPAD2_DOWN, 1); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_UP, 0); ++ SET_FLAG(maple_controller[port].buttons, DC_BTN_DPAD2_DOWN, 1); + break; + } + } + else if (ie.code == controller->mapping->Axis_Analog_X) + { +- joyx[port] = (controller->data_x.convert(ie.value) + 128); ++ maple_controller[port].stick_x = (controller->data_x.convert(ie.value) + 128); + } + else if (ie.code == controller->mapping->Axis_Analog_Y) + { +- joyy[port] = (controller->data_y.convert(ie.value) + 128); ++ maple_controller[port].stick_y = (controller->data_y.convert(ie.value) + 128); + } + else if (ie.code == controller->mapping->Axis_Trigger_Left) + { +- lt[port] = controller->data_trigger_left.convert(ie.value); ++ maple_controller[port].trigger_left = controller->data_trigger_left.convert(ie.value); + } + else if (ie.code == controller->mapping->Axis_Trigger_Right) + { +- rt[port] = controller->data_trigger_right.convert(ie.value); ++ maple_controller[port].trigger_right = controller->data_trigger_right.convert(ie.value); + } + break; + } +diff -Nur a/core/linux-dist/joystick.cpp b/core/linux-dist/joystick.cpp +--- a/core/linux-dist/joystick.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/joystick.cpp 2015-10-06 22:08:18.381992699 -0300 +@@ -5,14 +5,14 @@ + #include "linux-dist/joystick.h" + + #if defined(USE_JOYSTICK) +- const u32 joystick_map_btn_usb[JOYSTICK_MAP_SIZE] = { DC_BTN_Y, DC_BTN_B, DC_BTN_A, DC_BTN_X, 0, 0, 0, 0, 0, DC_BTN_START }; +- const u32 joystick_map_axis_usb[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, 0, 0, 0, 0, 0, 0, 0, 0 }; ++ const DreamcastControllerCodes joystick_map_btn_usb[JOYSTICK_MAP_SIZE] = { DC_BTN_Y, DC_BTN_B, DC_BTN_A, DC_BTN_X, 0, 0, 0, 0, 0, DC_BTN_START }; ++ const DreamcastControllerCodes joystick_map_axis_usb[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, 0, 0, 0, 0, 0, 0, 0, 0 }; + +- const u32 joystick_map_btn_xbox360[JOYSTICK_MAP_SIZE] = { DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, 0, 0, 0, DC_BTN_START, 0, 0 }; +- const u32 joystick_map_axis_xbox360[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, 0, 0, DC_AXIS_RT, DC_DPAD_LEFT, DC_DPAD_UP, 0, 0 }; ++ const DreamcastControllerCodes joystick_map_btn_xbox360[JOYSTICK_MAP_SIZE] = { DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, 0, 0, 0, DC_BTN_START, 0, 0 }; ++ const DreamcastControllerCodes joystick_map_axis_xbox360[JOYSTICK_MAP_SIZE] = { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, 0, 0, DC_AXIS_RT, DC_BTN_DPAD_LEFT, DC_BTN_DPAD_UP, 0, 0 }; + +- const u32* joystick_map_btn = joystick_map_btn_usb; +- const u32* joystick_map_axis = joystick_map_axis_usb; ++ const DreamcastControllerCodes* joystick_map_btn = joystick_map_btn_usb; ++ const DreamcastControllerCodes* joystick_map_axis = joystick_map_axis_usb; + + int input_joystick_init(const char* device) + { +@@ -73,18 +73,18 @@ + + if (mt == 0) + { +- kcode[port] |= mo; +- kcode[port] |= mo*2; ++ maple_controller[port].buttons |= mo; ++ maple_controller[port].buttons |= mo*2; + if (v<-64) + { +- kcode[port] &= ~mo; ++ maple_controller[port].buttons &= ~mo; + } + else if (v>64) + { +- kcode[port] &= ~(mo*2); ++ maple_controller[port].buttons &= ~(mo*2); + } + +- //printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2)); ++ //printf("Mapped to %d %d %d\n",mo,maple_controller[port].buttons&mo,maple_controller[port].buttons&(mo*2)); + } + else if (mt == 1) + { +@@ -95,11 +95,11 @@ + //printf("AXIS %d,%d Mapped to %d %d %d\n",JE.number,JE.value,mo,v,v+127); + if (mo == 0) + { +- lt[port] = (v + 127); ++ maple_controller[port].trigger_left = (v + 127); + } + else if (mo == 1) + { +- rt[port] = (v + 127); ++ maple_controller[port].trigger_right = (v + 127); + } + } + else if (mt == 2) +@@ -107,11 +107,11 @@ + // printf("AXIS %d,%d Mapped to %d %d [%d]",JE.number,JE.value,mo,v); + if (mo == 0) + { +- joyx[port] = v; ++ maple_controller[port].stick_x = v; + } + else if (mo == 1) + { +- joyy[port] = v; ++ maple_controller[port].stick_y = v; + } + } + } +@@ -129,11 +129,11 @@ + // printf("Mapped to %d\n",mo); + if (JE.value) + { +- kcode[port] &= ~mo; ++ maple_controller[port].buttons &= ~mo; + } + else + { +- kcode[port] |= mo; ++ maple_controller[port].buttons |= mo; + } + } + else if (mt == 1) +@@ -141,11 +141,11 @@ + // printf("Mapped to %d %d\n",mo,JE.value?255:0); + if (mo==0) + { +- lt[port] = JE.value ? 255 : 0; ++ maple_controller[port].trigger_left = JE.value ? 255 : 0; + } + else if (mo==1) + { +- rt[port] = JE.value ? 255 : 0; ++ maple_controller[port].trigger_right = JE.value ? 255 : 0; + } + } + } +diff -Nur a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp +--- a/core/linux-dist/main.cpp 2015-10-06 22:07:39.028703879 -0300 ++++ b/core/linux-dist/main.cpp 2015-10-06 22:08:18.381992699 -0300 +@@ -69,22 +69,11 @@ + return x11_disp; + } + +-u16 kcode[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; +-u8 rt[4] = {0, 0, 0, 0}; +-u8 lt[4] = {0, 0, 0, 0}; +-u32 vks[4]; +-s8 joyx[4], joyy[4]; +- + void emit_WriteCodeCache(); + + #if defined(USE_EVDEV) + /* evdev input */ +- static EvdevController evdev_controllers[4] = { +- { -1, NULL }, +- { -1, NULL }, +- { -1, NULL }, +- { -1, NULL } +- }; ++ static EvdevController evdev_controllers[MAPLE_NUM_PORTS]; + #endif + + #if defined(USE_JOYSTICK) +@@ -95,14 +84,17 @@ + void SetupInput() + { + #if defined(USE_EVDEV) +- int evdev_device_id[4] = { -1, -1, -1, -1 }; ++ int evdev_device_id[MAPLE_NUM_PORTS]; + size_t size_needed; + int port, i; + + char* evdev_device; + +- for (port = 0; port < 4; port++) ++ for (port = 0; port < MAPLE_NUM_PORTS; port++) + { ++ evdev_controllers[port] = { -1, NULL }; ++ evdev_device_id[port] = -1; ++ + size_needed = snprintf(NULL, 0, EVDEV_DEVICE_CONFIG_KEY, port+1) + 1; + char* evdev_config_key = (char*)malloc(size_needed); + sprintf(evdev_config_key, EVDEV_DEVICE_CONFIG_KEY, port+1); +@@ -135,6 +127,7 @@ + free(evdev_config_key); + + input_evdev_init(&evdev_controllers[port], evdev_device, mapping); ++ maple_controller[port].enabled = true; + + free(evdev_device); + } +diff -Nur a/core/linux-dist/main.h b/core/linux-dist/main.h +--- a/core/linux-dist/main.h 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/main.h 2015-10-06 22:08:18.381992699 -0300 +@@ -1,35 +1,6 @@ + #pragma once + #include "types.h" +- +-extern u16 kcode[4]; +-extern u32 vks[4]; +-extern u8 rt[4], lt[4]; +-extern s8 joyx[4], joyy[4]; ++#include "hw/maple/maple_controller.h" + + extern void* x11_win; + extern void* x11_disp; +- +-enum DreamcastController +-{ +- DC_BTN_C = 1, +- DC_BTN_B = 1<<1, +- DC_BTN_A = 1<<2, +- DC_BTN_START = 1<<3, +- DC_DPAD_UP = 1<<4, +- DC_DPAD_DOWN = 1<<5, +- DC_DPAD_LEFT = 1<<6, +- DC_DPAD_RIGHT = 1<<7, +- DC_BTN_Z = 1<<8, +- DC_BTN_Y = 1<<9, +- DC_BTN_X = 1<<10, +- DC_BTN_D = 1<<11, +- DC_DPAD2_UP = 1<<12, +- DC_DPAD2_DOWN = 1<<13, +- DC_DPAD2_LEFT = 1<<14, +- DC_DPAD2_RIGHT = 1<<15, +- +- DC_AXIS_LT = 0X10000, +- DC_AXIS_RT = 0X10001, +- DC_AXIS_X = 0X20000, +- DC_AXIS_Y = 0X20001, +-}; +diff -Nur a/core/linux-dist/x11.cpp b/core/linux-dist/x11.cpp +--- a/core/linux-dist/x11.cpp 2015-10-06 22:04:14.520204440 -0300 ++++ b/core/linux-dist/x11.cpp 2015-10-06 22:08:18.381992699 -0300 +@@ -82,11 +82,11 @@ + int dc_key = x11_keymap[e.xkey.keycode]; + if (e.type == KeyPress) + { +- kcode[0] &= ~dc_key; ++ maple_controller[0].buttons &= ~dc_key; + } + else + { +- kcode[0] |= dc_key; ++ maple_controller[0].buttons |= dc_key; + } + } + //printf("KEY: %d -> %d: %d\n",e.xkey.keycode, dc_key, x11_dc_buttons ); +@@ -98,11 +98,11 @@ + + void input_x11_init() + { +- x11_keymap[113] = DC_DPAD_LEFT; +- x11_keymap[114] = DC_DPAD_RIGHT; ++ x11_keymap[113] = DC_BTN_DPAD_LEFT; ++ x11_keymap[114] = DC_BTN_DPAD_RIGHT; + +- x11_keymap[111] = DC_DPAD_UP; +- x11_keymap[116] = DC_DPAD_DOWN; ++ x11_keymap[111] = DC_BTN_DPAD_UP; ++ x11_keymap[116] = DC_BTN_DPAD_DOWN; + + x11_keymap[53] = DC_BTN_X; + x11_keymap[54] = DC_BTN_B; +diff -Nur a/core/nacl/nacl.cpp b/core/nacl/nacl.cpp +--- a/core/nacl/nacl.cpp 2015-10-06 22:07:39.028703879 -0300 ++++ b/core/nacl/nacl.cpp 2015-10-06 22:08:18.381992699 -0300 +@@ -15,6 +15,7 @@ + #include "ppapi/utility/completion_callback_factory.h" + + #include "types.h" ++#include "hw/maple/maple_controller.h" + + #include + +@@ -234,12 +235,6 @@ + } + } // namespace pp + +- +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +- + int get_mic_data(u8* buffer) { return 0; } + int push_vmu_screen(u8* buffer) { return 0; } + +diff -Nur a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp +--- a/core/rend/gles/gles.cpp 2015-10-06 22:07:39.029703886 -0300 ++++ b/core/rend/gles/gles.cpp 2015-10-06 22:08:18.382992707 -0300 +@@ -2,6 +2,7 @@ + #include "gles.h" + #include "rend/TexCache.h" + #include "cfg/cfg.h" ++#include "hw/maple/maple_controller.h" + + #ifdef TARGET_PANDORA + #include +@@ -1043,28 +1044,6 @@ + //printf("%f\n",B*log(maxdev)/log(2.0)+A); + } + +- +- +-extern u16 kcode[4]; +-extern u8 rt[4],lt[4]; +- +-#define key_CONT_C (1 << 0) +-#define key_CONT_B (1 << 1) +-#define key_CONT_A (1 << 2) +-#define key_CONT_START (1 << 3) +-#define key_CONT_DPAD_UP (1 << 4) +-#define key_CONT_DPAD_DOWN (1 << 5) +-#define key_CONT_DPAD_LEFT (1 << 6) +-#define key_CONT_DPAD_RIGHT (1 << 7) +-#define key_CONT_Z (1 << 8) +-#define key_CONT_Y (1 << 9) +-#define key_CONT_X (1 << 10) +-#define key_CONT_D (1 << 11) +-#define key_CONT_DPAD2_UP (1 << 12) +-#define key_CONT_DPAD2_DOWN (1 << 13) +-#define key_CONT_DPAD2_LEFT (1 << 14) +-#define key_CONT_DPAD2_RIGHT (1 << 15) +- + u32 osd_base; + u32 osd_count; + +@@ -1260,21 +1239,21 @@ + osd_count=0; + + #ifndef TARGET_PANDORA +- DrawButton2(vjoy_pos[0],kcode[0]&key_CONT_DPAD_LEFT); +- DrawButton2(vjoy_pos[1],kcode[0]&key_CONT_DPAD_UP); +- DrawButton2(vjoy_pos[2],kcode[0]&key_CONT_DPAD_RIGHT); +- DrawButton2(vjoy_pos[3],kcode[0]&key_CONT_DPAD_DOWN); ++ DrawButton2(vjoy_pos[0], maple_controller[0].buttons & DC_BTN_DPAD_LEFT); ++ DrawButton2(vjoy_pos[1], maple_controller[0].buttons & DC_BTN_DPAD_UP); ++ DrawButton2(vjoy_pos[2], maple_controller[0].buttons & DC_BTN_DPAD_RIGHT); ++ DrawButton2(vjoy_pos[3], maple_controller[0].buttons & DC_BTN_DPAD_DOWN); + +- DrawButton2(vjoy_pos[4],kcode[0]&key_CONT_X); +- DrawButton2(vjoy_pos[5],kcode[0]&key_CONT_Y); +- DrawButton2(vjoy_pos[6],kcode[0]&key_CONT_B); +- DrawButton2(vjoy_pos[7],kcode[0]&key_CONT_A); ++ DrawButton2(vjoy_pos[4], maple_controller[0].buttons & DC_BTN_X); ++ DrawButton2(vjoy_pos[5], maple_controller[0].buttons & DC_BTN_Y); ++ DrawButton2(vjoy_pos[6], maple_controller[0].buttons & DC_BTN_B); ++ DrawButton2(vjoy_pos[7], maple_controller[0].buttons & DC_BTN_A); + +- DrawButton2(vjoy_pos[8],kcode[0]&key_CONT_START); ++ DrawButton2(vjoy_pos[8], maple_controller[0].buttons & DC_BTN_START); + +- DrawButton(vjoy_pos[9],lt[0]); ++ DrawButton(vjoy_pos[9], maple_controller[0].trigger_left); + +- DrawButton(vjoy_pos[10],rt[0]); ++ DrawButton(vjoy_pos[10], maple_controller[0].trigger_right); + + DrawButton2(vjoy_pos[11],1); + DrawButton2(vjoy_pos[12],0); +@@ -1818,8 +1797,6 @@ + #endif + #endif + +-extern u16 kcode[4]; +- + /* + bool rend_single_frame() + { +@@ -1833,7 +1810,7 @@ + } + + bool do_swp=false; +- //if (kcode[0]&(1<<9)) ++ //if (maple_controller[0].buttons&(1<<9)) + { + + +diff -Nur a/core/sdl/main.cpp b/core/sdl/main.cpp +--- a/core/sdl/main.cpp 2015-10-06 22:07:39.029703886 -0300 ++++ b/core/sdl/main.cpp 2015-10-06 22:08:18.382992707 -0300 +@@ -21,6 +21,7 @@ + #include + + #include "hw/mem/_vmem.h" ++#include "hw/maple/maple_controller.h" + + #ifdef TARGET_PANDORA + #define WINDOW_WIDTH 800 +@@ -56,42 +57,10 @@ + return MBX_OK; + } + +- +- +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +- + extern bool KillTex; + + extern void dc_term(); + +-enum DCPad { +- Btn_C = 1, +- Btn_B = 1<<1, +- Btn_A = 1<<2, +- Btn_Start = 1<<3, +- DPad_Up = 1<<4, +- DPad_Down = 1<<5, +- DPad_Left = 1<<6, +- DPad_Right = 1<<7, +- Btn_Z = 1<<8, +- Btn_Y = 1<<9, +- Btn_X = 1<<10, +- Btn_D = 1<<11, +- DPad2_Up = 1<<12, +- DPad2_Down = 1<<13, +- DPad2_Left = 1<<14, +- DPad2_Right = 1<<15, +- +- Axis_LT= 0x10000, +- Axis_RT= 0x10001, +- Axis_X= 0x20000, +- Axis_Y= 0x20001, +-}; +- +- + void emit_WriteCodeCache(); + + static SDL_Joystick *JoySDL = 0; +@@ -100,33 +69,26 @@ + + #define MAP_SIZE 32 + +-const u32 JMapBtn_USB[MAP_SIZE] = +- { Btn_Y,Btn_B,Btn_A,Btn_X,0,0,0,0,0,Btn_Start }; ++const DreamcastControllerCodes JMapBtn_USB[MAP_SIZE] = ++ { DC_BTN_Y, DC_BTN_B, DC_BTN_A, DC_BTN_X, 0, 0, 0, 0, 0, DC_BTN_START }; + +-const u32 JMapAxis_USB[MAP_SIZE] = +- { Axis_X,Axis_Y,0,0,0,0,0,0,0,0 }; ++const DreamcastControllerCodes JMapAxis_USB[MAP_SIZE] = ++ { DC_AXIS_X, DC_AXIS_Y, 0 ,0, 0, 0, 0, 0, 0, 0 }; + +-const u32 JMapBtn_360[MAP_SIZE] = +- { Btn_A,Btn_B,Btn_X,Btn_Y,0,0,0,Btn_Start,0,0 }; ++const DreamcastControllerCodes JMapBtn_360[MAP_SIZE] = ++ { DC_BTN_A, DC_BTN_B, DC_BTN_X, DC_BTN_Y, 0, 0, 0, DC_BTN_START, 0, 0 }; + +-const u32 JMapAxis_360[MAP_SIZE] = +- { Axis_X,Axis_Y,Axis_LT,0,0,Axis_RT,DPad_Left,DPad_Up,0,0 }; ++const DreamcastControllerCodes JMapAxis_360[MAP_SIZE] = ++ { DC_AXIS_X, DC_AXIS_Y, DC_AXIS_LT, 0, 0, DC_AXIS_RT, DC_BTN_DPAD_LEFT, DC_BTN_DPAD_UP, 0, 0 }; + +-const u32* JMapBtn=JMapBtn_USB; +-const u32* JMapAxis=JMapAxis_USB; ++const DreamcastControllerCodes* JMapBtn = JMapBtn_USB; ++const DreamcastControllerCodes* JMapAxis = JMapAxis_USB; + #ifdef TARGET_PANDORA + u32 JSensitivity[256]; // To have less sensitive value on nubs + #endif + + void SetupInput() + { +- for (int port=0;port<4;port++) +- { +- kcode[port]=0xFFFF; +- rt[port]=0; +- lt[port]=0; +- } +- + // Open joystick device + int numjoys = SDL_NumJoysticks(); + printf("Number of Joysticks found = %i\n", numjoys); +@@ -236,17 +198,17 @@ + { + // printf("Mapped to %d\n",mo); + if (value) +- kcode[port]&=~mo; ++ maple_controller[port].buttons &= ~mo; + else +- kcode[port]|=mo; ++ maple_controller[port].buttons |= mo; + } + else if (mt==1) + { + // printf("Mapped to %d %d\n",mo,JE.value?255:0); + if (mo==0) +- lt[port]=value?255:0; ++ maple_controller[port].trigger_left = value ? 255 : 0; + else if (mo==1) +- rt[port]=value?255:0; ++ maple_controller[port].trigger_right = value ? 255 : 0; + } + + } +@@ -266,18 +228,18 @@ + + if (mt==0) + { +- kcode[port]|=mo; +- kcode[port]|=mo*2; ++ maple_controller[port].buttons |= mo; ++ maple_controller[port].buttons |= mo*2; + if (v<-64) + { +- kcode[port]&=~mo; ++ maple_controller[port].buttons &= ~mo; + } + else if (v>64) + { +- kcode[port]&=~(mo*2); ++ maple_controller[port].buttons &= ~(mo*2); + } + +- // printf("Mapped to %d %d %d\n",mo,kcode[port]&mo,kcode[port]&(mo*2)); ++ // printf("Mapped to %d %d %d\n",mo,maple_controller[port].buttons&mo,maple_controller[port].buttons&(mo*2)); + } + else if (mt==1) + { +@@ -286,17 +248,17 @@ + // printf("AXIS %d,%d Mapped to %d %d %d\n",JE.number,JE.value,mo,v,v+127); + + if (mo==0) +- lt[port]=v+127; ++ maple_controller[port].trigger_left = v+127; + else if (mo==1) +- rt[port]=v+127; ++ maple_controller[port].trigger_right = v+127; + } + else if (mt==2) + { + // printf("AXIS %d,%d Mapped to %d %d [%d]",JE.number,JE.value,mo,v); + if (mo==0) +- joyx[port]=v; ++ maple_controller[port].stick_x = v; + else if (mo==1) +- joyy[port]=v; ++ maple_controller[port].stick_y = v; + } + } + break; +@@ -314,18 +276,18 @@ + case 0: // nothing + break; + case 1: // Up=RT, Down=LT +- if (yy<0) rt[port]=-yy; +- if (yy>0) lt[port]=yy; ++ if (yy<0) maple_controller[port].trigger_right = -yy; ++ if (yy>0) maple_controller[port].trigger_left = yy; + break; + case 2: // Left=LT, Right=RT +- if (xx<0) lt[port]=-xx; +- if (xx>0) rt[port]=xx; ++ if (xx<0) maple_controller[port].trigger_left = -xx; ++ if (xx>0) maple_controller[port].trigger_right = xx; + break; + case 3: // Nub = ABXY +- if (xx<-127) kcode[port] &= ~Btn_X; +- if (xx>127) kcode[port] &= ~Btn_B; +- if (yy<-127) kcode[port] &= ~Btn_Y; +- if (yy>127) kcode[port] &= ~Btn_A; ++ if (xx<-127) maple_controller[port].buttons &= ~DC_BTN_X; ++ if (xx>127) maple_controller[port].buttons &= ~DC_BTN_B; ++ if (yy<-127) maple_controller[port].buttons &= ~DC_BTN_Y; ++ if (yy>127) maple_controller[port].buttons &= ~DC_BTN_A; + break; + } + break; +@@ -333,16 +295,16 @@ + + } + +- if (keys[0]) { kcode[port] &= ~Btn_C; } +- if (keys[6]) { kcode[port] &= ~Btn_A; } +- if (keys[7]) { kcode[port] &= ~Btn_B; } +- if (keys[5]) { kcode[port] &= ~Btn_Y; } +- if (keys[8]) { kcode[port] &= ~Btn_X; } +- if (keys[1]) { kcode[port] &= ~DPad_Up; } +- if (keys[2]) { kcode[port] &= ~DPad_Down; } +- if (keys[3]) { kcode[port] &= ~DPad_Left; } +- if (keys[4]) { kcode[port] &= ~DPad_Right; } +- if (keys[12]){ kcode[port] &= ~Btn_Start; } ++ if (keys[0]) { maple_controller[port].buttons &= ~DC_BTN_C; } ++ if (keys[6]) { maple_controller[port].buttons &= ~DC_BTN_A; } ++ if (keys[7]) { maple_controller[port].buttons &= ~DC_BTN_B; } ++ if (keys[5]) { maple_controller[port].buttons &= ~DC_BTN_Y; } ++ if (keys[8]) { maple_controller[port].buttons &= ~DC_BTN_X; } ++ if (keys[1]) { maple_controller[port].buttons &= ~DC_BTN_DPAD_UP; } ++ if (keys[2]) { maple_controller[port].buttons &= ~DC_BTN_DPAD_DOWN; } ++ if (keys[3]) { maple_controller[port].buttons &= ~DC_BTN_DPAD_LEFT; } ++ if (keys[4]) { maple_controller[port].buttons &= ~DC_BTN_DPAD_RIGHT; } ++ if (keys[12]){ maple_controller[port].buttons &= ~DC_BTN_START; } + if (keys[9]){ + //die("death by escape key"); + //printf("death by escape key\n"); +@@ -352,8 +314,8 @@ + // is there a proper way to exit? dc_term() doesn't end the dc_run() loop it seems + die("death by escape key"); + } +- if (keys[10]) rt[port]=255; +- if (keys[11]) lt[port]=255; ++ if (keys[10]) maple_controller[port].trigger_right=255; ++ if (keys[11]) maple_controller[port].trigger_left=255; + + return true; + } +@@ -362,9 +324,9 @@ + { + static char key = 0; + +- kcode[port]=0xFFFF; +- rt[port]=0; +- lt[port]=0; ++ maple_controller[port].buttons=0xFFFF; ++ maple_controller[port].trigger_right=0; ++ maple_controller[port].trigger_left=0; + + HandleEvents(port); + } +diff -Nur a/core/windows/winmain.cpp b/core/windows/winmain.cpp +--- a/core/windows/winmain.cpp 2015-10-06 22:07:39.030703893 -0300 ++++ b/core/windows/winmain.cpp 2015-10-06 22:08:18.383992714 -0300 +@@ -1,5 +1,6 @@ + #include "oslib\oslib.h" + #include "oslib\audiostream.h" ++#include "hw\maple\maple_controller.h" + #include "imgread\common.h" + + #define _WIN32_WINNT 0x0500 +@@ -173,66 +174,46 @@ + return MessageBox(NULL,temp,VER_SHORTNAME,type | MB_TASKMODAL); + } + +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +-#define key_CONT_C (1 << 0) +-#define key_CONT_B (1 << 1) +-#define key_CONT_A (1 << 2) +-#define key_CONT_START (1 << 3) +-#define key_CONT_DPAD_UP (1 << 4) +-#define key_CONT_DPAD_DOWN (1 << 5) +-#define key_CONT_DPAD_LEFT (1 << 6) +-#define key_CONT_DPAD_RIGHT (1 << 7) +-#define key_CONT_Z (1 << 8) +-#define key_CONT_Y (1 << 9) +-#define key_CONT_X (1 << 10) +-#define key_CONT_D (1 << 11) +-#define key_CONT_DPAD2_UP (1 << 12) +-#define key_CONT_DPAD2_DOWN (1 << 13) +-#define key_CONT_DPAD2_LEFT (1 << 14) +-#define key_CONT_DPAD2_RIGHT (1 << 15) + void UpdateInputState(u32 port) + { +- //joyx[port]=pad.Lx; +- //joyy[port]=pad.Ly; +- lt[port]=GetAsyncKeyState('A')?255:0; +- rt[port]=GetAsyncKeyState('S')?255:0; ++ //maple_controller[port].stick_x = pad.Lx; ++ //maple_controller[port].stick_y = pad.Ly; ++ maple_controller[port].trigger_left = GetAsyncKeyState('A') ? 255 : 0; ++ maple_controller[port].trigger_right = GetAsyncKeyState('S') ? 255 : 0; + +- joyx[port]=joyy[port]=0; ++ maple_controller[port].stick_x = maple_controller[port].stick_y = 0; + + if (GetAsyncKeyState('J')) +- joyx[port]-=126; ++ maple_controller[port].stick_x -= 126; + if (GetAsyncKeyState('L')) +- joyx[port]+=126; ++ maple_controller[port].stick_x += 126; + + if (GetAsyncKeyState('I')) +- joyy[port]-=126; ++ maple_controller[port].stick_y -= 126; + if (GetAsyncKeyState('K')) +- joyy[port]+=126; ++ maple_controller[port].stick_y += 126; + +- kcode[port]=0xFFFF; ++ maple_controller[port].buttons = 0xFFFF; + if (GetAsyncKeyState('V')) +- kcode[port]&=~key_CONT_A; ++ maple_controller[port].buttons &= ~DC_BTN_A; + if (GetAsyncKeyState('C')) +- kcode[port]&=~key_CONT_B; ++ maple_controller[port].buttons &= ~DC_BTN_B; + if (GetAsyncKeyState('X')) +- kcode[port]&=~key_CONT_Y; ++ maple_controller[port].buttons &= ~DC_BTN_Y; + if (GetAsyncKeyState('Z')) +- kcode[port]&=~key_CONT_X; ++ maple_controller[port].buttons &= ~DC_BTN_X; + + if (GetAsyncKeyState(VK_SHIFT)) +- kcode[port]&=~key_CONT_START; ++ maple_controller[port].buttons &= ~DC_BTN_START; + + if (GetAsyncKeyState(VK_UP)) +- kcode[port]&=~key_CONT_DPAD_UP; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_UP; + if (GetAsyncKeyState(VK_DOWN)) +- kcode[port]&=~key_CONT_DPAD_DOWN; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_DOWN; + if (GetAsyncKeyState(VK_LEFT)) +- kcode[port]&=~key_CONT_DPAD_LEFT; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_LEFT; + if (GetAsyncKeyState(VK_RIGHT)) +- kcode[port]&=~key_CONT_DPAD_RIGHT; ++ maple_controller[port].buttons &= ~DC_BTN_DPAD_RIGHT; + + if (GetAsyncKeyState(VK_F1)) + settings.pvr.ta_skip = 100; +diff -Nur a/shell/android/jni/src/Android.cpp b/shell/android/jni/src/Android.cpp +--- a/shell/android/jni/src/Android.cpp 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/android/jni/src/Android.cpp 2015-10-06 22:08:18.383992714 -0300 +@@ -16,6 +16,7 @@ + #include "rend/TexCache.h" + #include "hw/maple/maple_devs.h" + #include "hw/maple/maple_if.h" ++#include "hw/maple/maple_controller.h" + #include "oslib/audiobackend_android.h" + + #include "util.h" +@@ -175,10 +176,6 @@ + // Additonal controllers 2, 3 and 4 connected ? + static bool add_controllers[3] = { false, false, false }; + +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; + float vjoy_pos[14][8]; + + extern bool print_stats; +@@ -211,7 +208,7 @@ + } + + // Add additonal controllers +- for (int i = 0; i < 3; i++) ++ for (int i = 0; i < (MAPLE_NUM_PORTS - 1); i++) + { + if (add_controllers[i]) + mcfg_Create(MDT_SegaController,i+1,5); +@@ -443,13 +440,13 @@ + jint *jx_body = env->GetIntArrayElements(jx, 0); + jint *jy_body = env->GetIntArrayElements(jy, 0); + +- for(int i = 0; i < 4; i++) ++ for(int i = 0; i < MAPLE_NUM_PORTS; i++) + { +- kcode[i] = k_code_body[i]; +- lt[i] = l_t_body[i]; +- rt[i] = r_t_body[i]; +- joyx[i] = jx_body[i]; +- joyy[i] = jy_body[i]; ++ maple_controller[i].buttons = k_code_body[i]; ++ maple_controller[i].trigger_left = l_t_body[i]; ++ maple_controller[i].trigger_right = r_t_body[i]; ++ maple_controller[i].stick_x = jx_body[i]; ++ maple_controller[i].stick_y = jy_body[i]; + } + + env->ReleaseIntArrayElements(k_code, k_code_body, 0); +diff -Nur a/shell/apple/emulator-ios/emulator/EmulatorView.mm b/shell/apple/emulator-ios/emulator/EmulatorView.mm +--- a/shell/apple/emulator-ios/emulator/EmulatorView.mm 2015-10-06 21:43:53.121336967 -0300 ++++ b/shell/apple/emulator-ios/emulator/EmulatorView.mm 2015-10-06 22:08:18.383992714 -0300 +@@ -9,15 +9,7 @@ + #import "EmulatorView.h" + + #include "types.h" +- +-extern u16 kcode[4]; +-extern u32 vks[4]; +-extern s8 joyx[4],joyy[4]; +-extern u8 rt[4],lt[4]; +- +-#define key_CONT_A (1 << 2) +-#define key_CONT_START (1 << 3) +-#define key_CONT_DPAD_LEFT (1 << 6) ++#include "hw/maple/maple_controller.h" + + int dpad_or_btn = 0; + +@@ -34,9 +26,9 @@ + -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + + if (dpad_or_btn &1) +- kcode[0] &= ~(key_CONT_START|key_CONT_A); ++ maple_controller[0].buttons &= ~(DC_BTN_START|DC_BTN_A); + else +- kcode[0] &= ~(key_CONT_DPAD_LEFT); ++ maple_controller[0].buttons &= ~(DC_BTN_DPAD_LEFT); + } + + -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { +@@ -44,9 +36,9 @@ + // [event allTouches]; + + if (dpad_or_btn &1) +- kcode[0] |= (key_CONT_START|key_CONT_A); ++ maple_controller[0].buttons |= (DC_BTN_START|DC_BTN_A); + else +- kcode[0] |= (key_CONT_DPAD_LEFT); ++ maple_controller[0].buttons |= (DC_BTN_DPAD_LEFT); + + dpad_or_btn++; + } +diff -Nur a/shell/apple/emulator-ios/emulator/ios_main.mm b/shell/apple/emulator-ios/emulator/ios_main.mm +--- a/shell/apple/emulator-ios/emulator/ios_main.mm 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/apple/emulator-ios/emulator/ios_main.mm 2015-10-06 22:08:18.383992714 -0300 +@@ -20,6 +20,7 @@ + #include + #include + #include "hw/sh4/dyna/blockmanager.h" ++#include "hw/maple/maple_controller.h" + #include + + +@@ -55,11 +56,6 @@ + int dc_init(int argc,wchar* argv[]); + void dc_run(); + +-u16 kcode[4]; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +- + extern "C" int reicast_main(int argc, wchar* argv[]) + { + //if (argc==2) +diff -Nur a/shell/apple/emulator-osx/emulator-osx/osx-main.mm b/shell/apple/emulator-osx/emulator-osx/osx-main.mm +--- a/shell/apple/emulator-osx/emulator-osx/osx-main.mm 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/apple/emulator-osx/emulator-osx/osx-main.mm 2015-10-06 22:08:18.383992714 -0300 +@@ -8,6 +8,7 @@ + #import + + #include "types.h" ++#include "hw/maple/maple_controller.h" + #include + + #include +@@ -38,11 +39,6 @@ + return 0; + } + +-u16 kcode[4] = { 0xFFFF }; +-u32 vks[4]; +-s8 joyx[4],joyy[4]; +-u8 rt[4],lt[4]; +- + int get_mic_data(u8* buffer) { return 0; } + int push_vmu_screen(u8* buffer) { return 0; } + +@@ -131,35 +127,11 @@ + gles_init(); + } + +-enum DCPad { +- Btn_C = 1, +- Btn_B = 1<<1, +- Btn_A = 1<<2, +- Btn_Start = 1<<3, +- DPad_Up = 1<<4, +- DPad_Down = 1<<5, +- DPad_Left = 1<<6, +- DPad_Right = 1<<7, +- Btn_Z = 1<<8, +- Btn_Y = 1<<9, +- Btn_X = 1<<10, +- Btn_D = 1<<11, +- DPad2_Up = 1<<12, +- DPad2_Down = 1<<13, +- DPad2_Left = 1<<14, +- DPad2_Right = 1<<15, +- +- Axis_LT= 0x10000, +- Axis_RT= 0x10001, +- Axis_X= 0x20000, +- Axis_Y= 0x20001, +-}; +- + void handle_key(int dckey, int state) { + if (state) +- kcode[0] &= ~dckey; ++ maple_controller[0].buttons &= ~dckey; + else +- kcode[0] |= dckey; ++ maple_controller[0].buttons |= dckey; + } + + void handle_trig(u8* dckey, int state) { +@@ -172,18 +144,18 @@ + extern "C" void emu_key_input(char* keyt, int state) { + int key = keyt[0]; + switch(key) { +- case 'z': handle_key(Btn_X, state); break; +- case 'x': handle_key(Btn_Y, state); break; +- case 'c': handle_key(Btn_B, state); break; +- case 'v': handle_key(Btn_A, state); break; ++ case 'z': handle_key(DC_BTN_X, state); break; ++ case 'x': handle_key(DC_BTN_Y, state); break; ++ case 'c': handle_key(DC_BTN_B, state); break; ++ case 'v': handle_key(DC_BTN_A, state); break; + + case 'a': handle_trig(lt, state); break; + case 's': handle_trig(rt, state); break; + +- case 'j': handle_key(DPad_Left, state); break; +- case 'k': handle_key(DPad_Down, state); break; +- case 'l': handle_key(DPad_Right, state); break; +- case 'i': handle_key(DPad_Up, state); break; +- case 0xa: handle_key(Btn_Start, state); break; ++ case 'j': handle_key(DC_BTN_DPAD_LEFT, state); break; ++ case 'k': handle_key(DC_BTN_DPAD_DOWN, state); break; ++ case 'l': handle_key(DC_BTN_DPAD_RIGHT, state); break; ++ case 'i': handle_key(DC_BTN_DPAD_UP, state); break; ++ case 0xa: handle_key(DC_BTN_START, state); break; + } + } +\ No newline at end of file +diff -Nur a/shell/reicast.vcxproj b/shell/reicast.vcxproj +--- a/shell/reicast.vcxproj 2015-10-06 22:07:39.030703893 -0300 ++++ b/shell/reicast.vcxproj 2015-10-06 22:08:18.383992714 -0300 +@@ -92,6 +92,7 @@ + + + ++ + + + diff --git a/pcr/reicast-git/refactor-rend-stuff.patch b/pcr/reicast-git/refactor-rend-stuff.patch new file mode 100644 index 000000000..187ccb8d0 --- /dev/null +++ b/pcr/reicast-git/refactor-rend-stuff.patch @@ -0,0 +1,1244 @@ +diff -Nur a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp +--- a/core/rend/gles/gles.cpp 2015-10-06 21:43:53.047336437 -0300 ++++ b/core/rend/gles/gles.cpp 2015-10-06 21:51:21.723570329 -0300 +@@ -1,27 +1,3 @@ +-#include +-#include "gles.h" +-#include "rend/TexCache.h" +-#include "cfg/cfg.h" +- +-#ifdef TARGET_PANDORA +-#include +-#include +-#include +-#include +- +-#ifndef FBIO_WAITFORVSYNC +- #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +-#endif +-int fbdev = -1; +-#endif +- +-#ifndef GLES +-#if HOST_OS != OS_DARWIN +-#include +-#pragma comment(lib,"Opengl32.lib") +-#endif +-#endif +- + /* + GL|ES 2 + Slower, smaller subset of gl2 +@@ -54,305 +30,126 @@ + + */ + ++#include ++#include "cfg/cfg.h" + #include "oslib/oslib.h" + #include "rend/rend.h" ++#include "rend/TexCache.h" + #include "hw/pvr/Renderer_if.h" ++#include "deps/libpng/png.h" ++#include "gles.h" ++#include "glshaders.h" + +-void GenSorted(); +- +-float fb_scale_x,fb_scale_y; +- +-#ifndef GLES +-#define attr "in" +-#define vary "out" +-#else +-#define attr "attribute" +-#define vary "varying" ++#ifdef TARGET_PANDORA ++ #include ++ #include ++ #include ++ #include + #endif +-#if 1 + +-//Fragment and vertex shaders code +-//pretty much 1:1 copy of the d3d ones for now +-const char* VertexShaderSource = +-#ifndef GLES +- "#version 140 \n" ++#if !defined(GLES) && HOST_OS != OS_DARWIN ++ #include ++ #pragma comment(lib,"Opengl32.lib") + #endif +-"\ +-/* Vertex constants*/ \n\ +-uniform highp vec4 scale; \n\ +-uniform highp vec4 depth_scale; \n\ +-uniform highp float sp_FOG_DENSITY; \n\ +-/* Vertex input */ \n\ +-" attr " highp vec4 in_pos; \n\ +-" attr " lowp vec4 in_base; \n\ +-" attr " lowp vec4 in_offs; \n\ +-" attr " mediump vec2 in_uv; \n\ +-/* output */ \n\ +-" vary " lowp vec4 vtx_base; \n\ +-" vary " lowp vec4 vtx_offs; \n\ +-" vary " mediump vec2 vtx_uv; \n\ +-" vary " highp vec3 vtx_xyz; \n\ +-void main() \n\ +-{ \n\ +- vtx_base=in_base; \n\ +- vtx_offs=in_offs; \n\ +- vtx_uv=in_uv; \n\ +- vec4 vpos=in_pos; \n\ +- vtx_xyz.xy = vpos.xy; \n\ +- vtx_xyz.z = vpos.z*sp_FOG_DENSITY; \n\ +- vpos.w=1.0/vpos.z; \n\ +- vpos.xy=vpos.xy*scale.xy-scale.zw; \n\ +- vpos.xy*=vpos.w; \n\ +- vpos.z=depth_scale.x+depth_scale.y*vpos.w; \n\ +- gl_Position = vpos; \n\ +-}"; +- + +-#else +- +- +- +-const char* VertexShaderSource = +- "" +- "/* Test Projection Matrix */" +- "" +- "uniform highp mat4 Projection;" +- "" +- "" +- "/* Vertex constants */" +- "" +- "uniform highp float sp_FOG_DENSITY;" +- "uniform highp vec4 scale;" +- "" +- "/* Vertex output */" +- "" +- "attribute highp vec4 in_pos;" +- "attribute lowp vec4 in_base;" +- "attribute lowp vec4 in_offs;" +- "attribute mediump vec2 in_uv;" +- "" +- "/* Transformed input */" +- "" +- "varying lowp vec4 vtx_base;" +- "varying lowp vec4 vtx_offs;" +- "varying mediump vec2 vtx_uv;" +- "varying highp vec3 vtx_xyz;" +- "" +- "void main()" +- "{" +- " vtx_base = in_base;" +- " vtx_offs = in_offs;" +- " vtx_uv = in_uv;" +- "" +- " vec4 vpos = in_pos;" +- " vtx_xyz.xy = vpos.xy; " +- " vtx_xyz.z = vpos.z*sp_FOG_DENSITY; " +- "" +- " vpos.w = 1.0/vpos.z; " +- " vpos.z *= -scale.w; " +- " vpos.xy = vpos.xy*scale.xy-sign(scale.xy); " +- " vpos.xy *= vpos.w; " +- "" +- " gl_Position = vpos;" +- // " gl_Position = vpos * Projection;" +- "}" +- ; ++#define OSD_TEX_W 512 ++#define OSD_TEX_H 256 + ++#define key_CONT_C (1 << 0) ++#define key_CONT_B (1 << 1) ++#define key_CONT_A (1 << 2) ++#define key_CONT_START (1 << 3) ++#define key_CONT_DPAD_UP (1 << 4) ++#define key_CONT_DPAD_DOWN (1 << 5) ++#define key_CONT_DPAD_LEFT (1 << 6) ++#define key_CONT_DPAD_RIGHT (1 << 7) ++#define key_CONT_Z (1 << 8) ++#define key_CONT_Y (1 << 9) ++#define key_CONT_X (1 << 10) ++#define key_CONT_D (1 << 11) ++#define key_CONT_DPAD2_UP (1 << 12) ++#define key_CONT_DPAD2_DOWN (1 << 13) ++#define key_CONT_DPAD2_LEFT (1 << 14) ++#define key_CONT_DPAD2_RIGHT (1 << 15) + +-#endif ++gl_ctx gl; + ++float fb_scale_x; ++float fb_scale_y; ++int screen_width; ++int screen_height; + ++GLuint osd_tex; + ++extern u16 kcode[4]; ++extern u8 rt[4]; ++extern u8 lt[4]; + ++u32 osd_base; ++u32 osd_count; + ++#if defined(_ANDROID) ++ extern float vjoy_pos[14][8]; ++#else ++ float vjoy_pos[14][8]= ++ { ++ {24+0,24+64,64,64}, //LEFT ++ {24+64,24+0,64,64}, //UP ++ {24+128,24+64,64,64}, //RIGHT ++ {24+64,24+128,64,64}, //DOWN ++ ++ {440+0,280+64,64,64}, //X ++ {440+64,280+0,64,64}, //Y ++ {440+128,280+64,64,64}, //B ++ {440+64,280+128,64,64}, //A ++ ++ {320-32,360+32,64,64}, //Start ++ ++ {440,200,90,64}, //RT ++ {542,200,90,64}, //LT ++ ++ {-24,128+224,128,128}, //ANALOG_RING ++ {96,320,64,64}, //ANALOG_POINT ++ {1} ++ }; ++#endif // !_ANDROID + +-/* ++float vjoy_sz[2][14] = { ++ { 64,64,64,64, 64,64,64,64, 64, 90,90, 128, 64 }, ++ { 64,64,64,64, 64,64,64,64, 64, 64,64, 128, 64 }, ++}; + +-cp_AlphaTest 0 1 2 2 +-pp_ClipTestMode -1 0 1 3 6 +-pp_UseAlpha 0 1 2 12 +-pp_Texture 1 +- pp_IgnoreTexA 0 1 2 2 +- pp_ShadInstr 0 1 2 3 4 8 +- pp_Offset 0 1 2 16 +- pp_FogCtrl 0 1 2 3 4 64 +-pp_Texture 0 +- pp_FogCtrl 0 2 3 4 4 +- +-pp_Texture: off -> 12*4=48 shaders +-pp_Texture: on -> 12*64=768 shaders +-Total: 816 shaders +- +-highp float fdecp(highp float flt,out highp float e) \n\ +-{ \n\ +- highp float lg2=log2(flt); //ie , 2.5 \n\ +- highp float frc=fract(lg2); //ie , 0.5 \n\ +- e=lg2-frc; //ie , 2.5-0.5=2 (exp) \n\ +- return pow(2.0,frc); //2^0.5 (manitsa) \n\ +-} \n\ +-lowp float fog_mode2(highp float invW) \n\ +-{ \n\ +- highp float foginvW=invW; \n\ +- foginvW=clamp(foginvW,1.0,255.0); \n\ +- \n\ +- highp float fogexp; //0 ... 7 \n\ +- highp float fogman=fdecp(foginvW, fogexp); //[1,2) mantissa bits. that is 1.m \n\ +- \n\ +- highp float fogman_hi=fogman*16.0-16.0; //[16,32) -16 -> [0,16) \n\ +- highp float fogman_idx=floor(fogman_hi); //[0,15] \n\ +- highp float fogman_blend=fract(fogman_hi); //[0,1) -- can also be fogman_idx-fogman_idx ! \n\ +- highp float fog_idx_fr=fogexp*16.0+fogman_idx; //[0,127] \n\ +- \n\ +- highp float fog_idx_pixel_fr=fog_idx_fr+0.5; \n\ +- highp float fog_idx_pixel_n=fog_idx_pixel_fr/128.0;//normalise to [0.5/128,127.5/128) coordinates \n\ +- \n\ +- //fog is 128x1 texure \n\ +- lowp vec2 fog_coefs=texture2D(fog_table,vec2(fog_idx_pixel_n)).rg; \n\ +- \n\ +- lowp float fog_coef=mix(fog_coefs.r,fog_coefs.g,fogman_blend); \n\ +- \n\ +- return fog_coef; \n\ +-} \n\ +-*/ ++#ifdef TARGET_PANDORA ++ #ifndef FBIO_WAITFORVSYNC ++ #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) ++ #endif + +-#ifndef GLES +-#define FRAGCOL "FragColor" +-#define TEXLOOKUP "texture" +-#define vary "in" +-#else +-#define FRAGCOL "gl_FragColor" +-#define TEXLOOKUP "texture2D" ++ int fbdev = -1; ++ char OSD_Info[128]; ++ int OSD_Delay = 0; ++ char OSD_Counters[256]; ++ int OSD_Counter = 0; ++ GLuint osd_font; + #endif + +- +-const char* PixelPipelineShader = +-#ifndef GLES +- "#version 140 \n" +- "out vec4 FragColor; \n" ++#if !defined(_ANDROID) && !defined(TARGET_NACL32) && HOST_OS==OS_LINUX ++ #define SET_AFNT 1 + #endif +-"\ +-\ +-#define cp_AlphaTest %d \n\ +-#define pp_ClipTestMode %d.0 \n\ +-#define pp_UseAlpha %d \n\ +-#define pp_Texture %d \n\ +-#define pp_IgnoreTexA %d \n\ +-#define pp_ShadInstr %d \n\ +-#define pp_Offset %d \n\ +-#define pp_FogCtrl %d \n\ +-/* Shader program params*/ \n\ +-/* gles has no alpha test stage, so its emulated on the shader */ \n\ +-uniform lowp float cp_AlphaTestValue; \n\ +-uniform lowp vec4 pp_ClipTest; \n\ +-uniform lowp vec3 sp_FOG_COL_RAM,sp_FOG_COL_VERT; \n\ +-uniform highp vec2 sp_LOG_FOG_COEFS; \n\ +-uniform sampler2D tex,fog_table; \n\ +-/* Vertex input*/ \n\ +-" vary " lowp vec4 vtx_base; \n\ +-" vary " lowp vec4 vtx_offs; \n\ +-" vary " mediump vec2 vtx_uv; \n\ +-" vary " highp vec3 vtx_xyz; \n\ +-lowp float fog_mode2(highp float val) \n\ +-{ \n\ +- highp float fog_idx=clamp(val,0.0,127.99); \n\ +- return clamp(sp_LOG_FOG_COEFS.y*log2(fog_idx)+sp_LOG_FOG_COEFS.x,0.001,1.0); //the clamp is required due to yet another bug !\n\ +-} \n\ +-void main() \n\ +-{ \n\ +- lowp vec4 color=vtx_base; \n\ +- #if pp_UseAlpha==0 \n\ +- color.a=1.0; \n\ +- #endif\n\ +- #if pp_FogCtrl==3 \n\ +- color=vec4(sp_FOG_COL_RAM.rgb,fog_mode2(vtx_xyz.z)); \n\ +- #endif\n\ +- #if pp_Texture==1 \n\ +- { \n\ +- lowp vec4 texcol=" TEXLOOKUP "(tex,vtx_uv); \n\ +- \n\ +- #if pp_IgnoreTexA==1 \n\ +- texcol.a=1.0; \n\ +- #endif\n\ +- \n\ +- #if pp_ShadInstr==0 \n\ +- { \n\ +- color.rgb=texcol.rgb; \n\ +- color.a=texcol.a; \n\ +- } \n\ +- #endif\n\ +- #if pp_ShadInstr==1 \n\ +- { \n\ +- color.rgb*=texcol.rgb; \n\ +- color.a=texcol.a; \n\ +- } \n\ +- #endif\n\ +- #if pp_ShadInstr==2 \n\ +- { \n\ +- color.rgb=mix(color.rgb,texcol.rgb,texcol.a); \n\ +- } \n\ +- #endif\n\ +- #if pp_ShadInstr==3 \n\ +- { \n\ +- color*=texcol; \n\ +- } \n\ +- #endif\n\ +- \n\ +- #if pp_Offset==1 \n\ +- { \n\ +- color.rgb+=vtx_offs.rgb; \n\ +- if (pp_FogCtrl==1) \n\ +- color.rgb=mix(color.rgb,sp_FOG_COL_VERT.rgb,vtx_offs.a); \n\ +- } \n\ +- #endif\n\ +- } \n\ +- #endif\n\ +- #if pp_FogCtrl==0 \n\ +- { \n\ +- color.rgb=mix(color.rgb,sp_FOG_COL_RAM.rgb,fog_mode2(vtx_xyz.z)); \n\ +- } \n\ +- #endif\n\ +- #if cp_AlphaTest == 1 \n\ +- if (cp_AlphaTestValue>color.a) discard;\n\ +- #endif \n\ +- //color.rgb=vec3(vtx_xyz.z/255.0);\n\ +- " FRAGCOL "=color; \n\ +-}"; + +-const char* ModifierVolumeShader = +-#ifndef GLES +- "#version 140 \n" +- "out vec4 FragColor; \n" +-#endif +-" \ +-uniform lowp float sp_ShaderColor; \n\ +-/* Vertex input*/ \n\ +-void main() \n\ +-{ \n\ +- " FRAGCOL "=vec4(0.0, 0.0, 0.0, sp_ShaderColor); \n\ +-}"; ++FILE* pngfile; + +-const char* OSD_Shader = +-#ifndef GLES +- "#version 140 \n" +- "out vec4 FragColor; \n" +-#endif +-" \ +-" vary " lowp vec4 vtx_base; \n\ +-" vary " mediump vec2 vtx_uv; \n\ +-/* Vertex input*/ \n\ +-uniform sampler2D tex; \n\ +-void main() \n\ +-{ \n\ +- mediump vec2 uv=vtx_uv; \n\ +- uv.y=1.0-uv.y; \n\ +- " FRAGCOL "=vtx_base*" TEXLOOKUP "(tex,uv.st); \n\n\ +-}"; ++void GenSorted(); + ++bool gl_init(void* wind, void* disp); + +-gl_ctx gl; ++//swap buffers ++void gl_swap(); ++//destroy the gles context and free resources ++void gl_term(); + +-int screen_width; +-int screen_height; ++GLuint gl_CompileShader(const char* shader,GLuint type); ++ ++bool gl_create_resources(); + + #if (HOST_OS != OS_DARWIN) && !defined(TARGET_NACL32) + #ifdef GLES +@@ -843,11 +640,6 @@ + return glIsProgram(s->program)==GL_TRUE; + } + +-GLuint osd_tex; +-#ifdef TARGET_PANDORA +-GLuint osd_font; +-#endif +- + bool gl_create_resources() + { + +@@ -938,51 +730,8 @@ + return true; + } + +-bool gl_init(void* wind, void* disp); +- +-//swap buffers +-void gl_swap(); +-//destroy the gles context and free resources +-void gl_term(); +- +-GLuint gl_CompileShader(const char* shader,GLuint type); +- +-bool gl_create_resources(); +- + //setup + +- +-bool gles_init() +-{ +- +- if (!gl_init((void*)libPvr_GetRenderTarget(), +- (void*)libPvr_GetRenderSurface())) +- return false; +- +- if (!gl_create_resources()) +- return false; +- +-#if defined(GLES) && HOST_OS != OS_DARWIN && !defined(TARGET_NACL32) +- #ifdef TARGET_PANDORA +- fbdev=open("/dev/fb0", O_RDONLY); +- #else +- eglSwapInterval(gl.setup.display,1); +- #endif +-#endif +- +- //clean up all buffers ... +- for (int i=0;i<10;i++) +- { +- glClearColor(0.f, 0.f, 0.f, 0.f); +- glClear(GL_COLOR_BUFFER_BIT); +- gl_swap(); +- } +- +- return true; +-} +- +- +- + float fog_coefs[]={0,0}; + void tryfit(float* x,float* y) + { +@@ -1043,64 +792,6 @@ + //printf("%f\n",B*log(maxdev)/log(2.0)+A); + } + +- +- +-extern u16 kcode[4]; +-extern u8 rt[4],lt[4]; +- +-#define key_CONT_C (1 << 0) +-#define key_CONT_B (1 << 1) +-#define key_CONT_A (1 << 2) +-#define key_CONT_START (1 << 3) +-#define key_CONT_DPAD_UP (1 << 4) +-#define key_CONT_DPAD_DOWN (1 << 5) +-#define key_CONT_DPAD_LEFT (1 << 6) +-#define key_CONT_DPAD_RIGHT (1 << 7) +-#define key_CONT_Z (1 << 8) +-#define key_CONT_Y (1 << 9) +-#define key_CONT_X (1 << 10) +-#define key_CONT_D (1 << 11) +-#define key_CONT_DPAD2_UP (1 << 12) +-#define key_CONT_DPAD2_DOWN (1 << 13) +-#define key_CONT_DPAD2_LEFT (1 << 14) +-#define key_CONT_DPAD2_RIGHT (1 << 15) +- +-u32 osd_base; +-u32 osd_count; +- +- +-#if defined(_ANDROID) +-extern float vjoy_pos[14][8]; +-#else +- +-float vjoy_pos[14][8]= +-{ +- {24+0,24+64,64,64}, //LEFT +- {24+64,24+0,64,64}, //UP +- {24+128,24+64,64,64}, //RIGHT +- {24+64,24+128,64,64}, //DOWN +- +- {440+0,280+64,64,64}, //X +- {440+64,280+0,64,64}, //Y +- {440+128,280+64,64,64}, //B +- {440+64,280+128,64,64}, //A +- +- {320-32,360+32,64,64}, //Start +- +- {440,200,90,64}, //RT +- {542,200,90,64}, //LT +- +- {-24,128+224,128,128}, //ANALOG_RING +- {96,320,64,64}, //ANALOG_POINT +- {1} +-}; +-#endif // !_ANDROID +- +-float vjoy_sz[2][14] = { +- { 64,64,64,64, 64,64,64,64, 64, 90,90, 128, 64 }, +- { 64,64,64,64, 64,64,64,64, 64, 64,64, 128, 64 }, +-}; +- + static void DrawButton(float* xy, u32 state) + { + Vertex vtx; +@@ -1139,12 +830,6 @@ + osd_count+=4; + } + +-static void ClearBG() +-{ +- +-} +- +- + void DrawButton2(float* xy, bool state) { DrawButton(xy,state?0:255); } + #ifdef TARGET_PANDORA + static void DrawCenteredText(float yy, float scale, int transparency, const char* text) +@@ -1247,13 +932,6 @@ + } + #endif + +-#ifdef TARGET_PANDORA +-char OSD_Info[128]; +-int OSD_Delay=0; +-char OSD_Counters[256]; +-int OSD_Counter=0; +-#endif +- + static void OSD_HOOK() + { + osd_base=pvrrc.verts.used(); +@@ -1290,128 +968,95 @@ + #endif + } + +-extern GLuint osd_tex; +-#ifdef TARGET_PANDORA +-extern GLuint osd_font; +-#endif +- +-#define OSD_TEX_W 512 +-#define OSD_TEX_H 256 +- +-void OSD_DRAW() ++/* ++bool rend_single_frame() + { +- #ifndef TARGET_PANDORA +- if (osd_tex) +- { +- float u=0; +- float v=0; +- +- for (int i=0;i<13;i++) +- { +- //umin,vmin,umax,vmax +- vjoy_pos[i][4]=(u+1)/OSD_TEX_W; +- vjoy_pos[i][5]=(v+1)/OSD_TEX_H; +- +- vjoy_pos[i][6]=((u+vjoy_sz[0][i]-1))/OSD_TEX_W; +- vjoy_pos[i][7]=((v+vjoy_sz[1][i]-1))/OSD_TEX_H; +- +- u+=vjoy_sz[0][i]; +- if (u>=OSD_TEX_W) +- { +- u-=OSD_TEX_W; +- v+=vjoy_sz[1][i]; +- } +- //v+=vjoy_pos[i][3]; +- } +- +- verify(glIsProgram(gl.OSD_SHADER.program)); ++ //wait render start only if no frame pending ++ _pvrrc = DequeueRender(); + +- glBindTexture(GL_TEXTURE_2D,osd_tex); +- glUseProgram(gl.OSD_SHADER.program); ++ while (!_pvrrc) ++ { ++ rs.Wait(); ++ _pvrrc = DequeueRender(); ++ } + +- //reset rendering scale +-/* +- float dc_width=640; +- float dc_height=480; ++ bool do_swp=false; ++ //if (kcode[0]&(1<<9)) ++ { + +- float dc2s_scale_h=screen_height/480.0f; +- float ds2s_offs_x=(screen_width-dc2s_scale_h*640)/2; + +- //-1 -> too much to left +- ShaderUniforms.scale_coefs[0]=2.0f/(screen_width/dc2s_scale_h); +- ShaderUniforms.scale_coefs[1]=-2/dc_height; +- ShaderUniforms.scale_coefs[2]=1-2*ds2s_offs_x/(screen_width); +- ShaderUniforms.scale_coefs[3]=-1; ++ //clear up & free data .. ++ tactx_Recycle(_pvrrc); ++ _pvrrc=0; + +- glUniform4fv( gl.OSD_SHADER.scale, 1, ShaderUniforms.scale_coefs); ++ return do_swp; ++} + */ + +- glEnable(GL_BLEND); +- glDisable(GL_DEPTH_TEST); +- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); +- +- glDepthMask(false); +- glDepthFunc(GL_ALWAYS); +- +- glDisable(GL_CULL_FACE); +- glDisable(GL_SCISSOR_TEST); +- +- int dfa=osd_count/4; +- +- for (int i=0;i too much to left +- ShaderUniforms.scale_coefs[0]=2.0f/(screen_width/dc2s_scale_h); +- ShaderUniforms.scale_coefs[1]=-2/dc_height; +- ShaderUniforms.scale_coefs[2]=1-2*ds2s_offs_x/(screen_width); +- ShaderUniforms.scale_coefs[3]=-1; ++ bool Process(TA_context* ctx); ++ bool Render(); + +- glUniform4fv( gl.OSD_SHADER.scale, 1, ShaderUniforms.scale_coefs); +-*/ ++ void Present(); + +- glEnable(GL_BLEND); +- glDisable(GL_DEPTH_TEST); +- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ++ void DrawOSD(); + ++ virtual u32 GetTexture(TSP tsp, TCW tcw); ++}; + +- glDepthMask(false); +- glDepthFunc(GL_ALWAYS); ++bool glesrend::Init() ++{ ++ ++ if (!gl_init((void*)libPvr_GetRenderTarget(), (void*)libPvr_GetRenderSurface())) ++ { ++ return false; ++ } + ++ if (!gl_create_resources()) ++ { ++ return false; ++ } + +- glDisable(GL_CULL_FACE); +- glDisable(GL_SCISSOR_TEST); ++ #if defined(GLES) && HOST_OS != OS_DARWIN && !defined(TARGET_NACL32) ++ #ifdef TARGET_PANDORA ++ fbdev = open("/dev/fb0", O_RDONLY); ++ #else ++ eglSwapInterval(gl.setup.display,1); ++ #endif ++ #endif + ++ //clean up all buffers ... ++ for (int i=0;i<10;i++) ++ { ++ glClearColor(0.f, 0.f, 0.f, 0.f); ++ glClear(GL_COLOR_BUFFER_BIT); ++ gl_swap(); ++ } + +- int dfa=osd_count/4; ++ return true; ++} + +- for (int i=0;irend.isRTT) +@@ -1435,7 +1080,7 @@ + return true; + } + +-bool RenderFrame() ++bool glesrend::Render() + { + DoCleanup(); + +@@ -1737,10 +1382,10 @@ + } + else + { +-#if HOST_OS != OS_DARWIN +- //Fix this in a proper way +- glBindFramebuffer(GL_FRAMEBUFFER,0); +-#endif ++ #if HOST_OS != OS_DARWIN ++ //Fix this in a proper way ++ glBindFramebuffer(GL_FRAMEBUFFER,0); ++ #endif + } + + //Clear depth +@@ -1812,68 +1457,93 @@ + return !is_rtt; + } + +-#if !defined(_ANDROID) && !defined(TARGET_NACL32) +-#if HOST_OS==OS_LINUX +-#define SET_AFNT 1 +-#endif +-#endif +- +-extern u16 kcode[4]; ++void glesrend::Present() ++{ ++ gl_swap(); ++ glViewport(0, 0, screen_width, screen_height); ++} + +-/* +-bool rend_single_frame() ++void glesrend::DrawOSD() + { +- //wait render start only if no frame pending +- _pvrrc = DequeueRender(); ++ #ifdef TARGET_PANDORA ++ GLuint osd_texture = osd_font; ++ #else ++ GLuint osd_texture = osd_tex; ++ #endif + +- while (!_pvrrc) ++ if (!osd_texture) + { +- rs.Wait(); +- _pvrrc = DequeueRender(); ++ return; + } + +- bool do_swp=false; +- //if (kcode[0]&(1<<9)) +- { ++ verify(glIsProgram(gl.OSD_SHADER.program)); + ++ #ifndef TARGET_PANDORA ++ float u = 0; ++ float v = 0; ++ ++ for (int i = 0; i < 13; i++) ++ { ++ //umin,vmin,umax,vmax ++ vjoy_pos[i][4]=(u+1)/OSD_TEX_W; ++ vjoy_pos[i][5]=(v+1)/OSD_TEX_H; + +- //clear up & free data .. +- tactx_Recycle(_pvrrc); +- _pvrrc=0; ++ vjoy_pos[i][6]=((u+vjoy_sz[0][i]-1))/OSD_TEX_W; ++ vjoy_pos[i][7]=((v+vjoy_sz[1][i]-1))/OSD_TEX_H; + +- return do_swp; +-} +-*/ ++ u+=vjoy_sz[0][i]; ++ if (u>=OSD_TEX_W) ++ { ++ u-=OSD_TEX_W; ++ v+=vjoy_sz[1][i]; ++ } ++ //v+=vjoy_pos[i][3]; ++ } ++ #endif + ++ glBindTexture(GL_TEXTURE_2D, osd_texture); ++ glUseProgram(gl.OSD_SHADER.program); + +-void rend_set_fb_scale(float x,float y) +-{ +- fb_scale_x=x; +- fb_scale_y=y; +-} ++ /* ++ //reset rendering scale + +-struct glesrend : Renderer +-{ +- bool Init() { return gles_init(); } +- void Resize(int w, int h) { screen_width=w; screen_height=h; } +- void Term() { } ++ float dc_width=640; ++ float dc_height=480; + +- bool Process(TA_context* ctx) { return ProcessFrame(ctx); } +- bool Render() { return RenderFrame(); } ++ float dc2s_scale_h=screen_height/480.0f; ++ float ds2s_offs_x=(screen_width-dc2s_scale_h*640)/2; + +- void Present() { gl_swap(); glViewport(0, 0, screen_width, screen_height); } ++ //-1 -> too much to left ++ ShaderUniforms.scale_coefs[0]=2.0f/(screen_width/dc2s_scale_h); ++ ShaderUniforms.scale_coefs[1]=-2/dc_height; ++ ShaderUniforms.scale_coefs[2]=1-2*ds2s_offs_x/(screen_width); ++ ShaderUniforms.scale_coefs[3]=-1; + +- void DrawOSD() { OSD_DRAW(); } ++ glUniform4fv( gl.OSD_SHADER.scale, 1, ShaderUniforms.scale_coefs); ++ */ + +- virtual u32 GetTexture(TSP tsp, TCW tcw) { +- return gl_GetTexture(tsp, tcw); +- } +-}; ++ glEnable(GL_BLEND); ++ glDisable(GL_DEPTH_TEST); ++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + ++ glDepthMask(false); ++ glDepthFunc(GL_ALWAYS); + +-#include "deps/libpng/png.h" ++ glDisable(GL_CULL_FACE); ++ glDisable(GL_SCISSOR_TEST); + +-FILE* pngfile; ++ int dfa = osd_count/4; ++ ++ for (int i = 0; i < dfa; i++) ++ { ++ glDrawArrays(GL_TRIANGLE_STRIP, osd_base + i*4, 4); ++ } ++} ++ ++u32 glesrend::GetTexture(TSP tsp, TCW tcw) ++{ ++ return gl_GetTexture(tsp, tcw); ++} + + void png_cstd_read(png_structp png_ptr, png_bytep data, png_size_t length) + { +@@ -2021,5 +1691,4 @@ + return texture; + } + +- + Renderer* rend_GLES2() { return new glesrend(); } +diff -Nur a/core/rend/gles/glshaders.cpp b/core/rend/gles/glshaders.cpp +--- a/core/rend/gles/glshaders.cpp 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/rend/gles/glshaders.cpp 2015-10-06 21:51:21.723570329 -0300 +@@ -0,0 +1,280 @@ ++#ifndef GLES ++#define attr "in" ++#define vary "out" ++#else ++#define attr "attribute" ++#define vary "varying" ++#endif ++#if 1 ++ ++//Fragment and vertex shaders code ++//pretty much 1:1 copy of the d3d ones for now ++const char* VertexShaderSource = ++#ifndef GLES ++ "#version 140 \n" ++#endif ++"\ ++/* Vertex constants*/ \n\ ++uniform highp vec4 scale; \n\ ++uniform highp vec4 depth_scale; \n\ ++uniform highp float sp_FOG_DENSITY; \n\ ++/* Vertex input */ \n\ ++" attr " highp vec4 in_pos; \n\ ++" attr " lowp vec4 in_base; \n\ ++" attr " lowp vec4 in_offs; \n\ ++" attr " mediump vec2 in_uv; \n\ ++/* output */ \n\ ++" vary " lowp vec4 vtx_base; \n\ ++" vary " lowp vec4 vtx_offs; \n\ ++" vary " mediump vec2 vtx_uv; \n\ ++" vary " highp vec3 vtx_xyz; \n\ ++void main() \n\ ++{ \n\ ++ vtx_base=in_base; \n\ ++ vtx_offs=in_offs; \n\ ++ vtx_uv=in_uv; \n\ ++ vec4 vpos=in_pos; \n\ ++ vtx_xyz.xy = vpos.xy; \n\ ++ vtx_xyz.z = vpos.z*sp_FOG_DENSITY; \n\ ++ vpos.w=1.0/vpos.z; \n\ ++ vpos.xy=vpos.xy*scale.xy-scale.zw; \n\ ++ vpos.xy*=vpos.w; \n\ ++ vpos.z=depth_scale.x+depth_scale.y*vpos.w; \n\ ++ gl_Position = vpos; \n\ ++}"; ++ ++ ++#else ++ ++ ++ ++const char* VertexShaderSource = ++ "" ++ "/* Test Projection Matrix */" ++ "" ++ "uniform highp mat4 Projection;" ++ "" ++ "" ++ "/* Vertex constants */" ++ "" ++ "uniform highp float sp_FOG_DENSITY;" ++ "uniform highp vec4 scale;" ++ "" ++ "/* Vertex output */" ++ "" ++ "attribute highp vec4 in_pos;" ++ "attribute lowp vec4 in_base;" ++ "attribute lowp vec4 in_offs;" ++ "attribute mediump vec2 in_uv;" ++ "" ++ "/* Transformed input */" ++ "" ++ "varying lowp vec4 vtx_base;" ++ "varying lowp vec4 vtx_offs;" ++ "varying mediump vec2 vtx_uv;" ++ "varying highp vec3 vtx_xyz;" ++ "" ++ "void main()" ++ "{" ++ " vtx_base = in_base;" ++ " vtx_offs = in_offs;" ++ " vtx_uv = in_uv;" ++ "" ++ " vec4 vpos = in_pos;" ++ " vtx_xyz.xy = vpos.xy; " ++ " vtx_xyz.z = vpos.z*sp_FOG_DENSITY; " ++ "" ++ " vpos.w = 1.0/vpos.z; " ++ " vpos.z *= -scale.w; " ++ " vpos.xy = vpos.xy*scale.xy-sign(scale.xy); " ++ " vpos.xy *= vpos.w; " ++ "" ++ " gl_Position = vpos;" ++ // " gl_Position = vpos * Projection;" ++ "}" ++ ; ++ ++ ++#endif ++ ++/* ++ ++cp_AlphaTest 0 1 2 2 ++pp_ClipTestMode -1 0 1 3 6 ++pp_UseAlpha 0 1 2 12 ++pp_Texture 1 ++ pp_IgnoreTexA 0 1 2 2 ++ pp_ShadInstr 0 1 2 3 4 8 ++ pp_Offset 0 1 2 16 ++ pp_FogCtrl 0 1 2 3 4 64 ++pp_Texture 0 ++ pp_FogCtrl 0 2 3 4 4 ++ ++pp_Texture: off -> 12*4=48 shaders ++pp_Texture: on -> 12*64=768 shaders ++Total: 816 shaders ++ ++highp float fdecp(highp float flt,out highp float e) \n\ ++{ \n\ ++ highp float lg2=log2(flt); //ie , 2.5 \n\ ++ highp float frc=fract(lg2); //ie , 0.5 \n\ ++ e=lg2-frc; //ie , 2.5-0.5=2 (exp) \n\ ++ return pow(2.0,frc); //2^0.5 (manitsa) \n\ ++} \n\ ++lowp float fog_mode2(highp float invW) \n\ ++{ \n\ ++ highp float foginvW=invW; \n\ ++ foginvW=clamp(foginvW,1.0,255.0); \n\ ++ \n\ ++ highp float fogexp; //0 ... 7 \n\ ++ highp float fogman=fdecp(foginvW, fogexp); //[1,2) mantissa bits. that is 1.m \n\ ++ \n\ ++ highp float fogman_hi=fogman*16.0-16.0; //[16,32) -16 -> [0,16) \n\ ++ highp float fogman_idx=floor(fogman_hi); //[0,15] \n\ ++ highp float fogman_blend=fract(fogman_hi); //[0,1) -- can also be fogman_idx-fogman_idx ! \n\ ++ highp float fog_idx_fr=fogexp*16.0+fogman_idx; //[0,127] \n\ ++ \n\ ++ highp float fog_idx_pixel_fr=fog_idx_fr+0.5; \n\ ++ highp float fog_idx_pixel_n=fog_idx_pixel_fr/128.0;//normalise to [0.5/128,127.5/128) coordinates \n\ ++ \n\ ++ //fog is 128x1 texure \n\ ++ lowp vec2 fog_coefs=texture2D(fog_table,vec2(fog_idx_pixel_n)).rg; \n\ ++ \n\ ++ lowp float fog_coef=mix(fog_coefs.r,fog_coefs.g,fogman_blend); \n\ ++ \n\ ++ return fog_coef; \n\ ++} \n\ ++*/ ++ ++#ifndef GLES ++#define FRAGCOL "FragColor" ++#define TEXLOOKUP "texture" ++#define vary "in" ++#else ++#define FRAGCOL "gl_FragColor" ++#define TEXLOOKUP "texture2D" ++#endif ++ ++ ++const char* PixelPipelineShader = ++#ifndef GLES ++ "#version 140 \n" ++ "out vec4 FragColor; \n" ++#endif ++"\ ++\ ++#define cp_AlphaTest %d \n\ ++#define pp_ClipTestMode %d.0 \n\ ++#define pp_UseAlpha %d \n\ ++#define pp_Texture %d \n\ ++#define pp_IgnoreTexA %d \n\ ++#define pp_ShadInstr %d \n\ ++#define pp_Offset %d \n\ ++#define pp_FogCtrl %d \n\ ++/* Shader program params*/ \n\ ++/* gles has no alpha test stage, so its emulated on the shader */ \n\ ++uniform lowp float cp_AlphaTestValue; \n\ ++uniform lowp vec4 pp_ClipTest; \n\ ++uniform lowp vec3 sp_FOG_COL_RAM,sp_FOG_COL_VERT; \n\ ++uniform highp vec2 sp_LOG_FOG_COEFS; \n\ ++uniform sampler2D tex,fog_table; \n\ ++/* Vertex input*/ \n\ ++" vary " lowp vec4 vtx_base; \n\ ++" vary " lowp vec4 vtx_offs; \n\ ++" vary " mediump vec2 vtx_uv; \n\ ++" vary " highp vec3 vtx_xyz; \n\ ++lowp float fog_mode2(highp float val) \n\ ++{ \n\ ++ highp float fog_idx=clamp(val,0.0,127.99); \n\ ++ return clamp(sp_LOG_FOG_COEFS.y*log2(fog_idx)+sp_LOG_FOG_COEFS.x,0.001,1.0); //the clamp is required due to yet another bug !\n\ ++} \n\ ++void main() \n\ ++{ \n\ ++ lowp vec4 color=vtx_base; \n\ ++ #if pp_UseAlpha==0 \n\ ++ color.a=1.0; \n\ ++ #endif\n\ ++ #if pp_FogCtrl==3 \n\ ++ color=vec4(sp_FOG_COL_RAM.rgb,fog_mode2(vtx_xyz.z)); \n\ ++ #endif\n\ ++ #if pp_Texture==1 \n\ ++ { \n\ ++ lowp vec4 texcol=" TEXLOOKUP "(tex,vtx_uv); \n\ ++ \n\ ++ #if pp_IgnoreTexA==1 \n\ ++ texcol.a=1.0; \n\ ++ #endif\n\ ++ \n\ ++ #if pp_ShadInstr==0 \n\ ++ { \n\ ++ color.rgb=texcol.rgb; \n\ ++ color.a=texcol.a; \n\ ++ } \n\ ++ #endif\n\ ++ #if pp_ShadInstr==1 \n\ ++ { \n\ ++ color.rgb*=texcol.rgb; \n\ ++ color.a=texcol.a; \n\ ++ } \n\ ++ #endif\n\ ++ #if pp_ShadInstr==2 \n\ ++ { \n\ ++ color.rgb=mix(color.rgb,texcol.rgb,texcol.a); \n\ ++ } \n\ ++ #endif\n\ ++ #if pp_ShadInstr==3 \n\ ++ { \n\ ++ color*=texcol; \n\ ++ } \n\ ++ #endif\n\ ++ \n\ ++ #if pp_Offset==1 \n\ ++ { \n\ ++ color.rgb+=vtx_offs.rgb; \n\ ++ if (pp_FogCtrl==1) \n\ ++ color.rgb=mix(color.rgb,sp_FOG_COL_VERT.rgb,vtx_offs.a); \n\ ++ } \n\ ++ #endif\n\ ++ } \n\ ++ #endif\n\ ++ #if pp_FogCtrl==0 \n\ ++ { \n\ ++ color.rgb=mix(color.rgb,sp_FOG_COL_RAM.rgb,fog_mode2(vtx_xyz.z)); \n\ ++ } \n\ ++ #endif\n\ ++ #if cp_AlphaTest == 1 \n\ ++ if (cp_AlphaTestValue>color.a) discard;\n\ ++ #endif \n\ ++ //color.rgb=vec3(vtx_xyz.z/255.0);\n\ ++ " FRAGCOL "=color; \n\ ++}"; ++ ++const char* ModifierVolumeShader = ++#ifndef GLES ++ "#version 140 \n" ++ "out vec4 FragColor; \n" ++#endif ++" \ ++uniform lowp float sp_ShaderColor; \n\ ++/* Vertex input*/ \n\ ++void main() \n\ ++{ \n\ ++ " FRAGCOL "=vec4(0.0, 0.0, 0.0, sp_ShaderColor); \n\ ++}"; ++ ++const char* OSD_Shader = ++#ifndef GLES ++ "#version 140 \n" ++ "out vec4 FragColor; \n" ++#endif ++" \ ++" vary " lowp vec4 vtx_base; \n\ ++" vary " mediump vec2 vtx_uv; \n\ ++/* Vertex input*/ \n\ ++uniform sampler2D tex; \n\ ++void main() \n\ ++{ \n\ ++ mediump vec2 uv=vtx_uv; \n\ ++ uv.y=1.0-uv.y; \n\ ++ " FRAGCOL "=vtx_base*" TEXLOOKUP "(tex,uv.st); \n\n\ ++}"; +diff -Nur a/core/rend/gles/glshaders.h b/core/rend/gles/glshaders.h +--- a/core/rend/gles/glshaders.h 1969-12-31 21:00:00.000000000 -0300 ++++ b/core/rend/gles/glshaders.h 2015-10-06 21:51:21.723570329 -0300 +@@ -0,0 +1,5 @@ ++#pragma once ++extern const char* VertexShaderSource; ++extern const char* PixelPipelineShader; ++extern const char* ModifierVolumeShader; ++extern const char* OSD_Shader; +\ No newline at end of file diff --git a/pcr/reicast-git/sdl-opengl.patch b/pcr/reicast-git/sdl-opengl.patch new file mode 100644 index 000000000..372ec9a52 --- /dev/null +++ b/pcr/reicast-git/sdl-opengl.patch @@ -0,0 +1,251 @@ +diff -Nur a/core/khronos/GL3/gl3w.c b/core/khronos/GL3/gl3w.c +--- a/core/khronos/GL3/gl3w.c 2015-10-06 21:43:53.040336386 -0300 ++++ b/core/khronos/GL3/gl3w.c 2015-10-06 22:04:39.682388782 -0300 +@@ -1,6 +1,25 @@ + #include + +-#ifdef _WIN32 ++#if defined(USE_SDL2) ++ #include ++ static void open_libgl(void) ++ { ++ SDL_GL_LoadLibrary(NULL); ++ } ++ ++ static void close_libgl(void) ++ { ++ SDL_GL_UnloadLibrary(); ++ } ++ ++ static void *get_proc(const char *proc) ++ { ++ void *res = NULL; ++ res = (void*)SDL_GL_GetProcAddress(proc); ++ return res; ++ } ++ ++#elif defined(_WIN32) + #define WIN32_LEAN_AND_MEAN 1 + #include + +diff -Nur a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp +--- a/core/sdl/sdl.cpp 2015-10-06 21:43:53.048336444 -0300 ++++ b/core/sdl/sdl.cpp 2015-10-06 22:04:39.683388790 -0300 +@@ -5,6 +5,18 @@ + #include "sdl/sdl.h" + #ifdef GLES + #include ++#else ++ #ifndef USE_SDL2 ++ #error "Our SDL1.2 implementation only supports GLES. You need SDL2 for OpenGL 3 support!" ++ #endif ++ #include "khronos/GL3/gl3w.h" ++#endif ++ ++#ifdef USE_SDL2 ++ static SDL_Window* window = NULL; ++ static SDL_GLContext glcontext; ++#else ++ SDL_Surface *screen = NULL; + #endif + + #ifdef TARGET_PANDORA +@@ -14,8 +26,6 @@ + #endif + #define WINDOW_HEIGHT 480 + +-SDL_Surface *screen = NULL; +- + static SDL_Joystick *JoySDL = 0; + + extern bool FrameSkipping; +@@ -80,11 +90,15 @@ + + AxisCount = SDL_JoystickNumAxes(JoySDL); + ButtonCount = SDL_JoystickNumButtons(JoySDL); +- Name = SDL_JoystickName(0); +- ++ #ifdef USE_SDL2 ++ Name = SDL_JoystickName(JoySDL); ++ #else ++ Name = SDL_JoystickName(0); ++ #endif ++ + printf("SDK: Found '%s' joystick with %d axes and %d buttons\n", Name, AxisCount, ButtonCount); + +- if (strcmp(Name,"Microsoft X-Box 360 pad")==0) ++ if (Name != NULL && strcmp(Name,"Microsoft X-Box 360 pad")==0) + { + sdl_map_btn = sdl_map_btn_xbox360; + sdl_map_axis = sdl_map_axis_xbox360; +@@ -113,12 +127,16 @@ + } + #endif + +- SDL_ShowCursor(0); ++ #ifndef USE_SDL2 ++ SDL_ShowCursor(0); + +- if (SDL_WM_GrabInput( SDL_GRAB_ON ) != SDL_GRAB_ON) +- { +- printf("SDK: Error while grabbing mouse\n"); +- } ++ if (SDL_WM_GrabInput( SDL_GRAB_ON ) != SDL_GRAB_ON) ++ { ++ printf("SDL: Error while grabbing mouse\n"); ++ } ++ #else ++ SDL_SetRelativeMouseMode(SDL_TRUE); ++ #endif + } + + void input_sdl_handle(u32 port) +@@ -397,7 +415,14 @@ + #ifdef TARGET_PANDORA + strncpy(OSD_Counters, text, 256); + #else +- SDL_WM_SetCaption(text, NULL); // *TODO* Set Icon also... ++ #ifdef USE_SDL2 ++ if(window) ++ { ++ SDL_SetWindowTitle(window, text); // *TODO* Set Icon also... ++ } ++ #else ++ SDL_WM_SetCaption(text, NULL); ++ #endif + #endif + } + +@@ -415,17 +440,79 @@ + + int window_width = cfgLoadInt("x11","width", WINDOW_WIDTH); + int window_height = cfgLoadInt("x11","height", WINDOW_HEIGHT); ++ + #ifdef TARGET_PANDORA + int flags = SDL_FULLSCREEN; + #else + int flags = SDL_SWSURFACE; + #endif +- screen = SDL_SetVideoMode(window_width, window_height, 0, flags); +- if (!screen) +- { +- die("error creating SDL screen"); +- } +- x11_disp = EGL_DEFAULT_DISPLAY; +- printf("Created SDL Windows (%ix%i) successfully\n", window_width, window_height); ++ ++ #if !defined(GLES) && defined(USE_SDL2) ++ flags |= SDL_WINDOW_OPENGL; ++ ++ SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); ++ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); ++ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); ++ SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); ++ SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); ++ SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); ++ SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); ++ SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); ++ SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); ++ SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); ++ ++ window = SDL_CreateWindow("Reicast Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, flags); ++ if (!window) ++ { ++ die("error creating SDL window"); ++ } ++ ++ glcontext = SDL_GL_CreateContext(window); ++ if (!glcontext) ++ { ++ die("Error creating SDL GL context"); ++ } ++ SDL_GL_MakeCurrent(window, NULL); ++ #else ++ screen = SDL_SetVideoMode(window_width, window_height, 0, flags); ++ if (!screen) ++ { ++ die("error creating SDL screen"); ++ } ++ ++ x11_disp = EGL_DEFAULT_DISPLAY; ++ #endif ++ ++ printf("Created SDL Window (%ix%i) and GL Context successfully\n", window_width, window_height); + } + #endif ++ ++#if !defined(GLES) && defined(USE_SDL2) ++ extern int screen_width, screen_height; ++ ++ bool gl_init(void* wind, void* disp) ++ { ++ SDL_GL_MakeCurrent(window, glcontext); ++ return gl3wInit() != -1 && gl3wIsSupported(3, 1); ++ } ++ ++ void gl_swap() ++ { ++ SDL_GL_SwapWindow(window); ++ ++ /* Check if drawable has been resized */ ++ int new_width, new_height; ++ SDL_GL_GetDrawableSize(window, &new_width, &new_height); ++ ++ if (new_width != screen_width || new_height != screen_height) ++ { ++ screen_width = new_width; ++ screen_height = new_height; ++ } ++ } ++ ++ void gl_term() ++ { ++ SDL_GL_DeleteContext(glcontext); ++ } ++#endif +\ No newline at end of file +diff -Nur a/core/sdl/sdl.h b/core/sdl/sdl.h +--- a/core/sdl/sdl.h 2015-10-06 21:43:53.048336444 -0300 ++++ b/core/sdl/sdl.h 2015-10-06 22:04:39.683388790 -0300 +@@ -1,5 +1,9 @@ + #pragma once +-#include ++#ifdef USE_SDL2 ++ #include ++#else ++ #include ++#endif + extern void* sdl_glc; + extern void input_sdl_init(); + extern void input_sdl_handle(u32 port); +diff -Nur a/shell/linux/Makefile b/shell/linux/Makefile +--- a/shell/linux/Makefile 2015-10-06 21:43:53.161337253 -0300 ++++ b/shell/linux/Makefile 2015-10-06 22:04:39.683388790 -0300 +@@ -175,6 +175,10 @@ + $(error Unknown platform) + endif + ++ifdef USE_SDL2 ++ USE_SDL := 1 ++endif ++ + RZDCY_SRC_DIR = ../../core + include $(RZDCY_SRC_DIR)/core.mk + +@@ -202,8 +206,14 @@ + endif + + ifdef USE_SDL +- CXXFLAGS += `sdl-config --cflags` -D USE_SDL +- LIBS += `sdl-config --libs` ++ CXXFLAGS += -D USE_SDL ++ ifdef USE_SDL2 ++ CXXFLAGS += `sdl2-config --cflags` -D USE_SDL2 ++ LIBS += `sdl2-config --libs` ++ else ++ CXXFLAGS += `sdl-config --cflags` ++ LIBS += `sdl-config --libs` ++ endif + endif + + ifdef PGO_MAKE diff --git a/pcr/reicast-git/sh-block-graphs.patch b/pcr/reicast-git/sh-block-graphs.patch new file mode 100644 index 000000000..c8e1bcf15 --- /dev/null +++ b/pcr/reicast-git/sh-block-graphs.patch @@ -0,0 +1,296 @@ +diff -Nur a/core/hw/sh4/dyna/blockmanager.cpp b/core/hw/sh4/dyna/blockmanager.cpp +--- a/core/hw/sh4/dyna/blockmanager.cpp 2015-10-06 21:43:53.030336315 -0300 ++++ b/core/hw/sh4/dyna/blockmanager.cpp 2015-10-06 21:58:25.685653822 -0300 +@@ -122,7 +122,11 @@ + } + else + { +- printf("bm_GetBlock(%08X) failed ..\n",dynarec_code); ++ for (iter = blkmap.begin(); iter != blkmap.end(); iter++) { ++ if ((*iter)->contains_code((u8*)dynarec_code)) ++ return *iter; ++ } ++ //printf("bm_GetBlock(%p, %p) failed ..\n",dynarec_code, ngen_FailedToFindBlock); + return 0; + } + } +@@ -158,6 +162,8 @@ + verify((void*)bm_GetCode(blk->addr)==(void*)ngen_FailedToFindBlock); + FPCA(blk->addr)=blk->code; + ++ verify(bm_GetBlock(blk->addr) == blk); ++ + #ifdef DYNA_OPROF + if (oprofHandle) + { +diff -Nur a/core/hw/sh4/dyna/blockmanager.h b/core/hw/sh4/dyna/blockmanager.h +--- a/core/hw/sh4/dyna/blockmanager.h 2015-10-06 21:43:53.030336315 -0300 ++++ b/core/hw/sh4/dyna/blockmanager.h 2015-10-06 21:58:25.685653822 -0300 +@@ -71,6 +71,7 @@ + + u32 memops; + u32 linkedmemops; ++ bool entry_block; + }; + + struct CachedBlockInfo: RuntimeBlockInfo_Core +diff -Nur a/core/hw/sh4/dyna/decoder.cpp b/core/hw/sh4/dyna/decoder.cpp +--- a/core/hw/sh4/dyna/decoder.cpp 2015-10-06 21:43:53.030336315 -0300 ++++ b/core/hw/sh4/dyna/decoder.cpp 2015-10-06 21:58:25.685653822 -0300 +@@ -14,6 +14,7 @@ + #include "hw/sh4/sh4_core.h" + #include "hw/sh4/sh4_mem.h" + #include "decoder_opcodes.h" ++#include "../interpr/sh4_opcodes.h" + + #define BLOCK_MAX_SH_OPS_SOFT 500 + #define BLOCK_MAX_SH_OPS_HARD 511 +@@ -1098,6 +1099,13 @@ + else + blk->guest_cycles+=CPU_RATIO; + ++ if ((state.cpu.is_delayslot && OpDesc[op]->SetPC()) || ++ OpDesc[op]->oph == iNotImplemented) { ++ blk->addr = -1; ++ return; ++ } ++ ++ + verify(!(state.cpu.is_delayslot && OpDesc[op]->SetPC())); + if (state.ngen.OnlyDynamicEnds || !OpDesc[op]->rec_oph) + { +@@ -1168,6 +1176,8 @@ + if (settings.dynarec.idleskip) + { + //Experimental hash-id based idle skip ++ if (blk->addr == 0x8C0B926A) ++ blk->guest_cycles *= 100; + if (strstr(idle_hash,blk->hash(false,true))) + { + //printf("IDLESKIP: %08X reloc match %s\n",blk->addr,blk->hash(false,true)); +diff -Nur a/core/hw/sh4/dyna/driver.cpp b/core/hw/sh4/dyna/driver.cpp +--- a/core/hw/sh4/dyna/driver.cpp 2015-10-06 21:43:53.030336315 -0300 ++++ b/core/hw/sh4/dyna/driver.cpp 2015-10-06 21:58:25.685653822 -0300 +@@ -72,11 +72,24 @@ + LastAddr=LastAddr_min; + memset(emit_GetCCPtr(),0xCC,emit_FreeSpace()); + } ++ ++#include ++#include ++#include ++ ++typedef map BlockGraph; ++ ++vector graphs; ++map blockgraphs; ++ + void recSh4_ClearCache() + { + LastAddr=LastAddr_min; + bm_Reset(); + ++ graphs.clear(); ++ blockgraphs.clear(); ++ + printf("recSh4:Dynarec Cache clear at %08X\n",curr_pc); + } + +@@ -212,9 +225,145 @@ + AnalyseBlock(this); + } + ++void merge_graphs(BlockGraph* one, BlockGraph* two) { ++ for (BlockGraph::iterator it = two->begin(); it != two->end(); it++) { ++ blockgraphs[it->second->addr] = one; ++ (*one)[it->second->addr] = it->second; ++ } ++ graphs.erase(find(graphs.begin(), graphs.end(), two)); ++} ++ ++void discover_graph(u32 bootstrap) { ++ BlockGraph* graph; ++ set resolved; ++ vector unresolved; ++ ++ if (blockgraphs.count(bootstrap)) { ++ graph = blockgraphs[bootstrap]; ++ (*graph)[bootstrap]->entry_block = true; ++ return; ++ } else { ++ graph = new BlockGraph(); ++ ++ graphs.push_back(graph); ++ } ++ ++ unresolved.push_back(bootstrap); ++ ++ while (unresolved.size()) { ++ u32 pc = unresolved[unresolved.size()-1]; ++ unresolved.pop_back(); ++ ++ if (resolved.count(pc)) ++ continue; ++ ++ if (graph->count(pc)) ++ continue; ++ ++ if (blockgraphs.count(pc)) { ++ verify(blockgraphs[pc] != graph); ++ merge_graphs(blockgraphs[pc], graph); ++ graph = blockgraphs[pc]; ++ resolved.clear(); ++ continue; ++ } ++ ++ resolved.insert(pc); ++ //printf("resolving %08X\n", pc); ++ ++ RuntimeBlockInfo* rbi = ngen_AllocateBlock(); ++ rbi->Setup(pc,fpscr); ++ rbi->entry_block = pc == bootstrap; ++ ++ if (rbi->addr == -1) ++ continue; ++ ++ (*graph)[pc] = rbi; ++ blockgraphs[pc] = graph; ++ ++ if (rbi->BranchBlock !=-1 && rbi->BlockType != BET_StaticCall) ++ unresolved.push_back(rbi->BranchBlock); ++ ++ if (rbi->NextBlock != -1) ++ unresolved.push_back(rbi->NextBlock); ++ } ++ ++ int entrypoints = 0; ++ ++ for (BlockGraph::iterator it = graph->begin(); it != graph->end(); it++) { ++ entrypoints += it->second->entry_block; ++ } ++ ++ //printf("Graph: %d blocks w/ %d entrypoints, %d graphs\n", graph->size(), entrypoints, graphs.size()); ++} ++ ++void print_graphs() { ++ int top_runs = 0; ++ int total_runs = 0; ++ map graph_runs; ++ ++ for (size_t i = 0; i < graphs.size(); i++) { ++ BlockGraph* graph = graphs[i]; ++ for (BlockGraph::iterator it = graphs[i]->begin(); it != graphs[i]->end(); it++) { ++ ++ RuntimeBlockInfo* natblock = bm_GetBlock(it->first); ++ if (!natblock || natblock->runs == 0) ++ continue; ++ ++ if (natblock->runs > top_runs) ++ top_runs = natblock->runs; ++ ++ total_runs += natblock->runs; ++ ++ graph_runs[graph] += natblock->runs; ++ } ++ } ++ ++ int baseline = top_runs / 100; ++ ++ printf("begin(); it != graphs[i]->end(); it++) { ++ ++ RuntimeBlockInfo* natblock = bm_GetBlock(it->first); ++ if (!natblock || natblock->runs == 0 || natblock->runs < baseline) { ++ if (natblock) { ++ cnt2++; ++ natblock->runs = 0; ++ } else { ++ cnt++; ++ } ++ continue; ++ } ++ printf("\t\tBlock %08X, compiled: %d, entrypoint: %d, type: %d, len: %d, cycles: %d, runs %d, loop %d\n", ++ it->first, natblock != 0, it->second->entry_block, it->second->BlockType, it->second->oplist.size(), ++ it->second->guest_cycles, natblock ? natblock->runs : 0, ++ (it->second->BlockType == BET_Cond_0 || it->second->BlockType == BET_Cond_1) && graph->count(it->second->BranchBlock) ); ++ ++ if (natblock) ++ natblock->runs = 0; ++ } ++ if (cnt2) { ++ printf("\t\t and %d more not worth mentioning\n", cnt2); ++ } ++ if (cnt) { ++ printf("\t\t and %d more that never run\n", cnt); ++ } ++ } ++ printf("Graphdump>\n"); ++} ++ + DynarecCodeEntryPtr rdv_CompilePC() + { + u32 pc=next_pc; ++ discover_graph(pc); + + if (emit_FreeSpace()<16*1024 || pc==0x8c0000e0 || pc==0xac010000 || pc==0xac008300) + recSh4_ClearCache(); +@@ -232,6 +381,7 @@ + rbi->staging_runs=do_opts?100:-100; + ngen_Compile(rbi,DoCheck(rbi->addr),(pc&0xFFFFFF)==0x08300 || (pc&0xFFFFFF)==0x10000,false,do_opts); + verify(rbi->code!=0); ++ verify(rbi->host_code_size!=0); + + bm_AddBlock(rbi); + +diff -Nur a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp +--- a/core/linux-dist/main.cpp 2015-10-06 21:43:53.042336401 -0300 ++++ b/core/linux-dist/main.cpp 2015-10-06 21:58:25.685653822 -0300 +@@ -189,6 +189,18 @@ + #if defined(USE_SDL) + input_sdl_handle(port); + #endif ++ ++ //Whatever happened to these? ++#if FEAT_SHREC != DYNAREC_NONE ++ /* ++ void print_graphs(); ++ if ('b' == key) emit_WriteCodeCache(); ++ if ('n' == key) bm_Reset(); ++ if ('m' == key) bm_Sort(); ++ if (',' == key) { emit_WriteCodeCache(); bm_Sort(); } ++ if ('q' == key) print_graphs(); ++ */ ++#endif + } + + void os_DoEvents() +diff -Nur a/core/rec-x64/rec_x64.cpp b/core/rec-x64/rec_x64.cpp +--- a/core/rec-x64/rec_x64.cpp 2015-10-06 21:43:53.045336422 -0300 ++++ b/core/rec-x64/rec_x64.cpp 2015-10-06 21:58:25.685653822 -0300 +@@ -162,6 +162,10 @@ + + sub(dword[rax], block->guest_cycles); + ++ mov(rax, (size_t)&block->runs); ++ add(dword[rax], 1); ++ ++ + sub(rsp, 0x28); + + for (size_t i = 0; i < block->oplist.size(); i++) { +@@ -355,6 +359,7 @@ + + block->code = (DynarecCodeEntryPtr)getCode(); + ++ block->host_code_size = getSize(); + emit_Skip(getSize()); + } + diff --git a/pcr/reicast-git/ta-hash-logs.patch b/pcr/reicast-git/ta-hash-logs.patch new file mode 100644 index 000000000..1d120852f --- /dev/null +++ b/pcr/reicast-git/ta-hash-logs.patch @@ -0,0 +1,120 @@ +diff -Nur a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp +--- a/core/hw/pvr/Renderer_if.cpp 2015-10-06 21:43:53.028336301 -0300 ++++ b/core/hw/pvr/Renderer_if.cpp 2015-10-06 21:49:25.016725724 -0300 +@@ -5,10 +5,16 @@ + + #include "deps/zlib/zlib.h" + ++#include "deps/crypto/md5.h" ++ + #if FEAT_HAS_NIXPROF + #include "profiler/profiler.h" + #endif + ++#define FRAME_MD5 0x1 ++FILE* fLogFrames; ++FILE* fCheckFrames; ++ + /* + + rendv3 ideas +@@ -291,6 +297,48 @@ + + if (ctx) + { ++ if (fLogFrames || fCheckFrames) { ++ MD5Context md5; ++ u8 digest[16]; ++ ++ MD5Init(&md5); ++ MD5Update(&md5, ctx->tad.thd_root, ctx->tad.End() - ctx->tad.thd_root); ++ MD5Final(digest, &md5); ++ ++ if (fLogFrames) { ++ fputc(FRAME_MD5, fLogFrames); ++ fwrite(digest, 1, 16, fLogFrames); ++ fflush(fLogFrames); ++ } ++ ++ if (fCheckFrames) { ++ u8 v; ++ u8 digest2[16]; ++ int ch = fgetc(fCheckFrames); ++ ++ if (ch == EOF) { ++ printf("Testing: TA Hash log matches, exiting\n"); ++ exit(1); ++ } ++ ++ verify(ch == FRAME_MD5); ++ ++ fread(digest2, 1, 16, fCheckFrames); ++ ++ verify(memcmp(digest, digest2, 16) == 0); ++ ++ ++ } ++ ++ /* ++ u8* dig = digest; ++ printf("FRAME: %02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X\n", ++ digest[0], digest[1], digest[2], digest[3], digest[4], digest[5], digest[6], digest[7], ++ digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15] ++ ); ++ */ ++ } ++ + if (!ctx->rend.Overrun) + { + //printf("REP: %.2f ms\n",render_end_pending_cycles/200000.0); +@@ -366,6 +414,13 @@ + + bool rend_init() + { ++ if (fLogFrames = fopen(settings.pvr.HashLogFile.c_str(), "wb")) { ++ printf("Saving frame hashes to: '%s'\n", settings.pvr.HashLogFile.c_str()); ++ } ++ ++ if (fCheckFrames = fopen(settings.pvr.HashCheckFile.c_str(), "rb")) { ++ printf("Comparing frame hashes against: '%s'\n", settings.pvr.HashCheckFile.c_str()); ++ } + + #ifdef NO_REND + renderer = rend_norend(); +@@ -435,6 +490,11 @@ + + void rend_term() + { ++ if (fCheckFrames) ++ fclose(fCheckFrames); ++ ++ if (fLogFrames) ++ fclose(fLogFrames); + } + + void rend_vblank() +diff -Nur a/core/nullDC.cpp b/core/nullDC.cpp +--- a/core/nullDC.cpp 2015-10-06 21:43:53.043336408 -0300 ++++ b/core/nullDC.cpp 2015-10-06 21:49:25.017725731 -0300 +@@ -260,6 +260,8 @@ + #endif + + settings.bios.UseReios = cfgLoadInt("config", "bios.UseReios", 0); ++ settings.pvr.HashLogFile = cfgLoadStr("testing", "ta.HashLogFile", ""); ++ settings.pvr.HashCheckFile = cfgLoadStr("testing", "ta.HashCheckFile", ""); + + #if (HOST_OS != OS_LINUX || defined(_ANDROID) || defined(TARGET_PANDORA)) + settings.aica.BufferSize=2048; +diff -Nur a/core/types.h b/core/types.h +--- a/core/types.h 2015-10-06 21:43:53.048336444 -0300 ++++ b/core/types.h 2015-10-06 21:49:25.017725731 -0300 +@@ -696,6 +696,9 @@ + + u32 MaxThreads; + u32 SynchronousRendering; ++ ++ string HashLogFile; ++ string HashCheckFile; + } pvr; + + struct { -- cgit v1.2.3